diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 857907b35e..b37d7d7c2a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev g++-multilib gcc-multilib libasound2-dev libx11-dev libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev libmbedtls-dev libpng-dev libturbojpeg-dev libuv1-dev libvorbis-dev + sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev g++-multilib gcc-multilib libasound2-dev libx11-dev libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev libmbedtls-dev libpng-dev libturbojpeg-dev libuv1-dev libvorbis-dev libvulkan-dev - uses: krdlab/setup-haxe@v2 with: @@ -110,7 +110,7 @@ jobs: run: | sudo add-apt-repository ppa:haxe/releases -y sudo apt-get update - sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libx11-dev libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev libmbedtls-dev libpng-dev libturbojpeg-dev libuv1-dev libvorbis-dev + sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libx11-dev libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev libmbedtls-dev libpng-dev libturbojpeg-dev libuv1-dev libvorbis-dev libvulkan-dev # krdlab/setup-haxe doesn't support arm64 linux # so this is our workaround for now @@ -135,10 +135,6 @@ jobs: haxelib install hxp --quiet haxelib install utest --quiet - - name: Enable HXCPP compile cache - run: | - echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV - - name: Rebuild Lime tools run: | haxelib dev lime ${{ github.workspace }} @@ -182,6 +178,59 @@ jobs: lime create SimpleAudio -verbose -nocolor lime build SimpleAudio linux -release -verbose -nocolor + vulkan-smoke: + runs-on: ubuntu-22.04 + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libx11-dev libx11-xcb1 libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev libmbedtls-dev libpng-dev libturbojpeg-dev libuv1-dev libvorbis-dev libvulkan-dev mesa-vulkan-drivers xvfb + + - uses: krdlab/setup-haxe@v2 + with: + haxe-version: ${{ env.HAXE_VERSION }} + + - name: Set HAXEPATH + run: | + echo "HAXEPATH=$HAXE_STD_PATH/.." >> $GITHUB_ENV + + - name: Install Haxe dependencies + run: | + curl --output ../hxcpp-4.3.45.zip --location https://github.com/HaxeFoundation/hxcpp/releases/download/v4.3.45/hxcpp-4.3.45.zip + haxelib --global update haxelib --quiet + haxelib install ../hxcpp-4.3.45.zip --quiet + haxelib install format --quiet + haxelib install hxp --quiet + haxelib install utest --quiet + + - name: Rebuild Lime tools + run: | + haxelib dev lime ${{ github.workspace }} + haxelib run lime rebuild tools -nocolor -verbose -nocffi + haxelib run lime setup -alias -y -nocffi + + - name: Rebuild Lime (Linux default Vulkan) + run: | + lime rebuild linux -64 -release -nocolor -verbose -nocffi + + - name: Build Vulkan smoke test app + working-directory: tests/vulkan-smoke + run: | + lime build linux -release -verbose -nocolor + + - name: Run Vulkan smoke test app + working-directory: tests/vulkan-smoke + run: | + if [ -f /usr/share/vulkan/icd.d/lvp_icd.x86_64.json ]; then + export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json + fi + SDL_AUDIODRIVER=dummy xvfb-run -a Export/linux/bin/LimeVulkanSmoke + macos: runs-on: macos-14 steps: @@ -476,6 +525,11 @@ jobs: run: | lime create SimpleAudio -verbose -nocolor -eval lime build SimpleAudio android -release -verbose -nocolor -eval + + - name: Build Vulkan smoke test app + working-directory: tests/vulkan-smoke + run: | + lime build android -release -verbose -nocolor -eval ios: runs-on: macos-14 steps: @@ -536,7 +590,7 @@ jobs: lime build SimpleAudio ios -release -nosign -verbose -nocolor -eval package-haxelib: - needs: [linux, macos, windows, android, ios] + needs: [linux, vulkan-smoke, macos, windows, android, ios] runs-on: ubuntu-22.04 steps: @@ -728,7 +782,7 @@ jobs: runs-on: windows-latest strategy: matrix: - haxe-version: [4.0.5, 4.1.5, 4.2.5, 4.3.6] + haxe-version: [4.0.5, 4.1.5, 4.2.5, 4.3.7] steps: - uses: actions/checkout@v6 @@ -882,7 +936,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - haxe-version: [3.4.7, 4.0.5, 4.1.5, 4.2.5, 4.3.6] + haxe-version: [3.4.7, 4.0.5, 4.1.5, 4.2.5, 4.3.7] steps: - uses: actions/checkout@v6 @@ -996,7 +1050,7 @@ jobs: notify: runs-on: ubuntu-22.04 - needs: [package-haxelib, docs, android, flash-samples, air-samples, hashlink-samples, hashlinkc-samples, html5-samples, ios, linux, macos, neko-samples, windows] + needs: [package-haxelib, docs, android, flash-samples, air-samples, hashlink-samples, hashlinkc-samples, html5-samples, ios, linux, vulkan-smoke, macos, neko-samples, windows] if: ${{ github.repository == 'openfl/lime' && github.event_name != 'pull_request' }} steps: - name: Notify Discord diff --git a/CHANGELOG.md b/CHANGELOG.md index 38d456a168..f3ddcb60e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,38 @@ Changelog ========= +8.4.0 (06/18/2026) +------------------ + +- Added an experimental Vulkan renderer for native Windows, Linux, and Android targets. +- Added `VulkanRenderContext` and Haxe Vulkan bindings for instance, device, swapchain, command, descriptor, memory, and pipeline helpers. +- Added Vulkan bootstrap logging, error details, MSAA resolve support, mapped memory helpers, and descriptor helpers. +- Added configurable application frame timing with `FrameProfile`, `FrameOptions`, `VSyncMode`, busy-wait, time precision, and uncap controls. +- Added `AudioInput` and audio input device APIs with native OpenAL, HTML5, and Flash backends. +- Added SDL_sound decoding and streaming, including inline stream playback, streams with unknown length, and loop counts. +- Added `Window.alwaysOnTop` and transparent window support. +- Added input event timestamps without changing listener signatures. +- Added `Promise.completeAsync()`. +- Added explicit font rendering flags, DPI-aware glyph rendering, unhinted font decomposition, and HarfBuzz FT font change notifications. +- Added project.xml support for Android manifest tags and Gradle plugin entries. +- Added AIR options for Android App Bundles, Android Studio output, and shared runtime deployment. +- Added VAO support on macOS. +- Changed asset copying and embedding to behave consistently across targets. +- Changed OpenAL Soft HRTF to be disabled by default. +- Updated pixman and platform config for LLVM assembly fixes, ARM NEON, Android NDKs, and Apple platforms. +- Updated MojoAL and gamepad mappings. +- Fixed an asset embedding regression. +- Fixed Windows cpp icon resource handling when no icon is generated. +- Fixed GL cleanup and desktop GL object collection. +- Fixed native and HashLink `AudioBuffer` layout mismatches. +- Fixed `AudioBuffer.fromBytes()` and `AudioBuffer.fromBase64()` on HTML5 to avoid forcing HTML5 audio buffers. +- Fixed OpenAL output device recovery. +- Fixed perspective camera matrix calculation. +- Fixed Tizen `appinfo.json` templating. +- Fixed Android architecture parsing for `x86_64` and `x86_32`. +- Fixed SDL_sound ARM64 Linux detection outside Raspberry Pi OS. +- Fixed HTML5 transparent docs generation. + 8.3.2 (05/13/2026) ------------------ diff --git a/README.md b/README.md index c6803fb1a5..167628b285 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,13 @@ Lime does not include a renderer, but exposes the current context: * DOM * Flash * GL + * Vulkan The GL context is based upon the WebGL standard, implemented for both OpenGL and OpenGL ES as needed. +Native Vulkan support exposes an explicit Vulkan API layer for renderer backends, including native window/swapchain integration and resource/command primitives. +Native Vulkan support is included in standard Windows and Linux C++ Lime builds, including the matching Haxe API define. Apple targets still require an explicit Vulkan-enabled build and MoltenVK packaging. +To request a Vulkan window, use the standard `RenderContextType.VULKAN` context selection or set `` in project XML. +The in-repo `tests/vulkan-smoke` project is used as the current Vulkan CI smoke app. Lime provides a unified audio API, but also provides access to OpenAL for advanced audio on native targets. diff --git a/docs/ImportAll.hx b/docs/ImportAll.hx index e0039724f6..d1fbcc89cf 100644 --- a/docs/ImportAll.hx +++ b/docs/ImportAll.hx @@ -58,6 +58,41 @@ import lime.graphics.PixelFormat; import lime.graphics.RenderContext; import lime.graphics.RenderContextAttributes; import lime.graphics.RenderContextType; +import lime.graphics.VulkanRenderContext; +import lime.graphics.vulkan.VK; +import lime.graphics.vulkan.VKAcquireResult; +import lime.graphics.vulkan.VKBuffer; +import lime.graphics.vulkan.VKCommandBuffer; +import lime.graphics.vulkan.VKCommandPool; +import lime.graphics.vulkan.VKDescriptorPool; +import lime.graphics.vulkan.VKDescriptorPoolSize; +import lime.graphics.vulkan.VKDescriptorSet; +import lime.graphics.vulkan.VKDescriptorSetLayout; +import lime.graphics.vulkan.VKDescriptorSetLayoutBinding; +import lime.graphics.vulkan.VKDevice; +import lime.graphics.vulkan.VKDeviceMemory; +import lime.graphics.vulkan.VKFence; +import lime.graphics.vulkan.VKFramebuffer; +import lime.graphics.vulkan.VKGraphicsPipelineInfo; +import lime.graphics.vulkan.VKImage; +import lime.graphics.vulkan.VKImageView; +import lime.graphics.vulkan.VKInstance; +import lime.graphics.vulkan.VKMemoryRequirements; +import lime.graphics.vulkan.VKPhysicalDevice; +import lime.graphics.vulkan.VKPipeline; +import lime.graphics.vulkan.VKPipelineCache; +import lime.graphics.vulkan.VKPipelineLayout; +import lime.graphics.vulkan.VKQueue; +import lime.graphics.vulkan.VKQueueFamilyInfo; +import lime.graphics.vulkan.VKRenderPass; +import lime.graphics.vulkan.VKRenderer; +import lime.graphics.vulkan.VKSampler; +import lime.graphics.vulkan.VKSemaphore; +import lime.graphics.vulkan.VKShaderModule; +import lime.graphics.vulkan.VKSurface; +import lime.graphics.vulkan.VKSwapchain; +import lime.graphics.vulkan.VKVertexAttribute; +import lime.graphics.vulkan.VKVertexBinding; import lime.graphics.WebGL2RenderContext; import lime.graphics.WebGLRenderContext; import lime.math.ARGB; @@ -87,6 +122,8 @@ import lime.media.vorbis.VorbisInfo; import lime.media.AudioBuffer; import lime.media.AudioContext; import lime.media.AudioContextType; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; import lime.media.AudioManager; import lime.media.AudioSource; import lime.media.FlashAudioContext; diff --git a/include.xml b/include.xml index 04f641e3c6..e38f58019f 100644 --- a/include.xml +++ b/include.xml @@ -24,6 +24,8 @@ + + diff --git a/project/Build.xml b/project/Build.xml index ef9bc7458d..84ef070811 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -35,10 +35,13 @@ + + + @@ -59,6 +62,10 @@ + + + + @@ -236,6 +243,7 @@ + @@ -270,6 +278,7 @@ + diff --git a/project/include/graphics/vulkan/VKRenderer.h b/project/include/graphics/vulkan/VKRenderer.h new file mode 100644 index 0000000000..ae2b0b8f69 --- /dev/null +++ b/project/include/graphics/vulkan/VKRenderer.h @@ -0,0 +1,160 @@ +#ifndef LIME_GRAPHICS_VULKAN_VKRENDERER_H +#define LIME_GRAPHICS_VULKAN_VKRENDERER_H + +#include +#include +#include +#include +#include + + +namespace lime { + + + class VulkanRenderer { + + public: + + explicit VulkanRenderer (Window* window); + ~VulkanRenderer (); + + bool ClearOverlay (); + bool Create (const char* applicationName); + void Destroy (); + bool Render (float red, float green, float blue, float alpha); + bool Resize (); + bool SetOverlay (const unsigned char* data, int width, int height, int x, int y); + + inline const std::string& GetInfo () const { return info; } + inline const std::string& GetLastError () const { return lastError; } + + private: + + bool CreateCommandBuffers (); + bool CreateCommandPool (); + bool CreateDevice (); + bool CreateFramebuffers (); + bool CreateImageViews (); + bool CreateInstance (const char* applicationName); + bool CreateOverlayBuffer (size_t requiredSize); + bool CreateRenderPass (); + bool CreateSurface (); + bool CreateSwapchain (); + bool CreateSwapchainResources (); + bool CreateSyncObjects (); + void DestroyOverlayResources (); + void DestroySwapchainResources (); + uint32_t FindMemoryType (uint32_t typeFilter, VkMemoryPropertyFlags properties); + bool LoadDeviceProcs (); + bool LoadGlobalProcs (); + bool LoadInstanceProcs (); + bool PickPhysicalDevice (); + bool RecordCommandBuffer (uint32_t imageIndex, float red, float green, float blue, float alpha); + bool RecreateSwapchain (); + void SetError (const std::string& value); + + Window* window; + std::string info; + std::string lastError; + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkCreateDevice vkCreateDevice; + PFN_vkCreateFence vkCreateFence; + PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreateInstance vkCreateInstance; + PFN_vkCreateRenderPass vkCreateRenderPass; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyInstance vkDestroyInstance; + PFN_vkDestroyRenderPass vkDestroyRenderPass; + PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; + PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkMapMemory vkMapMemory; + PFN_vkQueuePresentKHR vkQueuePresentKHR; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkResetCommandPool vkResetCommandPool; + PFN_vkResetFences vkResetFences; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkWaitForFences vkWaitForFences; + + VkInstance instance; + VkSurfaceKHR surface; + VkPhysicalDevice physicalDevice; + VkPhysicalDeviceProperties physicalDeviceProperties; + VkDevice device; + VkQueue queue; + uint32_t queueFamilyIndex; + VkSwapchainKHR swapchain; + VkFormat swapchainFormat; + VkPresentModeKHR swapchainPresentMode; + int requestedVSyncMode; + VkExtent2D swapchainExtent; + VkRenderPass renderPass; + VkCommandPool commandPool; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; + VkFence inFlightFence; + VkBuffer overlayBuffer; + VkDeviceMemory overlayBufferMemory; + bool portabilityEnumerationSupported; + bool portabilitySubsetSupported; + bool swapchainDirty; + size_t overlayBufferCapacity; + unsigned char* overlayMappedData; + uint32_t overlayWidth; + uint32_t overlayHeight; + int overlayX; + int overlayY; + bool overlayEnabled; + + std::vector instanceExtensions; + std::vector deviceExtensions; + std::vector swapchainImages; + std::vector swapchainImageViews; + std::vector framebuffers; + std::vector commandBuffers; + + }; + + +} + + +#endif diff --git a/project/include/media/AudioBuffer.h b/project/include/media/AudioBuffer.h index 5f9a8130e0..5cd3e476d9 100644 --- a/project/include/media/AudioBuffer.h +++ b/project/include/media/AudioBuffer.h @@ -40,6 +40,7 @@ namespace lime { vdynamic* __srcAudio; vdynamic* __srcBuffer; + int __srcBufferContext; vdynamic* __srcCustom; vdynamic* __srcHowl; bool __isDisposed; @@ -63,4 +64,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/include/ui/FileDialog.h b/project/include/ui/FileDialog.h index 4a310b3198..1adf918f7b 100644 --- a/project/include/ui/FileDialog.h +++ b/project/include/ui/FileDialog.h @@ -9,14 +9,36 @@ namespace lime { + // Functions in this class return pointers to externally owned memory, which will be reused automatically + // for future dialogs and should not be freed. class FileDialog { public: - static std::wstring* OpenDirectory (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static std::wstring* OpenFile (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static void OpenFiles (std::vector* files, std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static std::wstring* SaveFile (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); +#ifdef HX_WINDOWS + using char_t = wchar_t; +#else + using char_t = char; +#endif + + static const char_t* OpenDirectory(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + static const char_t* OpenFile(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + + // Use actual string view once we can use c++17 + class string_view { + public: + string_view(const char_t* c_str, size_t length) : c_str(c_str), length(length) {} + + const char_t* data() const { return c_str; } + size_t size() const { return length; } + + private: + const char_t* c_str; + size_t length; + }; + + static std::vector OpenFiles(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + static const char_t* SaveFile(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); }; @@ -24,4 +46,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/include/ui/GamepadEvent.h b/project/include/ui/GamepadEvent.h index 607ef9cfc8..5543da20c2 100644 --- a/project/include/ui/GamepadEvent.h +++ b/project/include/ui/GamepadEvent.h @@ -28,6 +28,7 @@ namespace lime { int id; GamepadEventType type; double axisValue; + int timestamp; static ValuePointer* callback; static ValuePointer* eventObject; @@ -42,4 +43,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/include/ui/KeyEvent.h b/project/include/ui/KeyEvent.h index 28e6fcc6fd..8d5ac047c0 100644 --- a/project/include/ui/KeyEvent.h +++ b/project/include/ui/KeyEvent.h @@ -25,6 +25,7 @@ namespace lime { int modifier; KeyEventType type; int windowID; + int timestamp; static ValuePointer* callback; static ValuePointer* eventObject; @@ -39,4 +40,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/include/ui/Window.h b/project/include/ui/Window.h index 04321be0b2..81afa74fae 100644 --- a/project/include/ui/Window.h +++ b/project/include/ui/Window.h @@ -11,8 +11,13 @@ #include #include #include +#include #include +#ifdef CreateWindow +#undef CreateWindow +#endif + namespace lime { @@ -68,7 +73,17 @@ namespace lime { virtual bool SetAlwaysOnTop (bool alwaysOnTop) = 0; virtual void WarpMouse (int x, int y) = 0; virtual int GetVSyncInterval () const { return 0; } + virtual int GetRequestedVSyncMode () const { return 0; } virtual double GetRefreshRate () const { return 60.0; } + virtual uint64_t CreateVulkanSurface (uintptr_t instance) { return 0; } + virtual void GetVulkanDrawableSize (int* width, int* height) { + + if (width) *width = 0; + if (height) *height = 0; + + } + virtual bool GetVulkanInstanceExtensions (unsigned int* count, const char** names) { return false; } + virtual void* GetVulkanInstanceProcAddr () { return 0; } Application* currentApplication; int flags; @@ -98,7 +113,9 @@ namespace lime { WINDOW_FLAG_MINIMIZED = 0x00002000, WINDOW_FLAG_MAXIMIZED = 0x00004000, WINDOW_FLAG_ALWAYS_ON_TOP = 0x00008000, - WINDOW_FLAG_COLOR_DEPTH_32_BIT = 0x00010000 + WINDOW_FLAG_COLOR_DEPTH_32_BIT = 0x00010000, + WINDOW_FLAG_VULKAN = 0x00020000, + WINDOW_FLAG_TRANSPARENT = 0x00040000 }; diff --git a/project/lib/custom/pixman/config.h b/project/lib/custom/pixman/pixman-config.h similarity index 87% rename from project/lib/custom/pixman/config.h rename to project/lib/custom/pixman/pixman-config.h index 0fa8ab453f..02ffd50113 100644 --- a/project/lib/custom/pixman/config.h +++ b/project/lib/custom/pixman/pixman-config.h @@ -15,9 +15,6 @@ 3. Update the version number(s) if they've changed. **/ -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - /* Whether we have alarm() */ #ifdef HX_LINUX #define HAVE_ALARM 1 @@ -32,13 +29,6 @@ /* #undef HAVE_BUILTIN_CLZ */ #endif -/* Define to 1 if you have the header file. */ -#ifndef HX_WINDOWS -#define HAVE_DLFCN_H 1 -#else -/* #undef HAVE_DLFCN_H */ -#endif - /* Whether we have FE_DIVBYZERO */ #ifdef HX_LINUX #define HAVE_FEDIVBYZERO 1 @@ -108,13 +98,6 @@ /* #undef HAVE_LIBPNG */ #endif -/* Define to 1 if you have the header file. */ -#ifdef HX_LINUX -#define HAVE_MEMORY_H 1 -#else -/* #undef HAVE_MEMORY_H */ -#endif - /* Whether we have mmap() */ #ifdef HX_LINUX #define HAVE_MMAP 1 @@ -200,24 +183,6 @@ /* Name of package */ #define PACKAGE "pixman" -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "pixman@lists.freedesktop.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "pixman" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "pixman 0.42.2" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "pixman" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.42.2" - /* enable output that can be piped to gnuplot */ /* #undef PIXMAN_GNUPLOT */ @@ -252,6 +217,12 @@ /* #undef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR */ #endif +#define ASM_HAVE_SYNTAX_UNIFIED + +#if defined(__APPLE__) +#define ASM_LEADING_UNDERSCORE 1 +#endif + /* use ARM A64_NEON assembly optimizations */ /* #undef USE_ARM_A64_NEON */ @@ -316,9 +287,6 @@ /* #undef USE_X86_MMX */ #endif -/* Version number of package */ -#define VERSION "0.42.2" - /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD @@ -336,6 +304,3 @@ #ifndef __cplusplus /* #undef inline */ #endif - -/* Define to sqrt if you do not have the `sqrtf' function. */ -/* #undef sqrtf */ diff --git a/project/lib/custom/pixman/pixman/pixman-version.h b/project/lib/custom/pixman/pixman/pixman-version.h index 23d30b5500..5767975fcd 100644 --- a/project/lib/custom/pixman/pixman/pixman-version.h +++ b/project/lib/custom/pixman/pixman/pixman-version.h @@ -32,10 +32,10 @@ #endif #define PIXMAN_VERSION_MAJOR 0 -#define PIXMAN_VERSION_MINOR 40 -#define PIXMAN_VERSION_MICRO 1 +#define PIXMAN_VERSION_MINOR 44 +#define PIXMAN_VERSION_MICRO 2 -#define PIXMAN_VERSION_STRING "0.40.1" +#define PIXMAN_VERSION_STRING "0.44.2" #define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \ ((major) * 10000) \ diff --git a/project/lib/custom/sdl/include/SDL_config_linux.h b/project/lib/custom/sdl/include/SDL_config_linux.h index fc5213ebc9..54a9fe5b30 100644 --- a/project/lib/custom/sdl/include/SDL_config_linux.h +++ b/project/lib/custom/sdl/include/SDL_config_linux.h @@ -308,6 +308,9 @@ /* #undef SDL_VIDEO_OPENGL_OSMESA */ /* #undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC */ +/* Enable Vulkan support */ +#define SDL_VIDEO_VULKAN 1 + /* Enable system power support */ #define SDL_POWER_LINUX 1 /* #undef SDL_POWER_WINDOWS */ diff --git a/project/lib/pixman b/project/lib/pixman index 37216a3283..46655e1567 160000 --- a/project/lib/pixman +++ b/project/lib/pixman @@ -1 +1 @@ -Subproject commit 37216a32839f59e8dcaa4c3951b3fcfc3f07852c +Subproject commit 46655e15671e1ca62d699821d75a85d341d7229c diff --git a/project/lib/pixman-files.xml b/project/lib/pixman-files.xml index ef98744568..cd266b1f0a 100644 --- a/project/lib/pixman-files.xml +++ b/project/lib/pixman-files.xml @@ -1,16 +1,12 @@ - - - + + -
- - -
+ @@ -22,6 +18,7 @@ + @@ -39,7 +36,9 @@ - + + + @@ -73,6 +72,7 @@ +
diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 0fcb20e6e7..2f6abcb4a8 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -16,6 +16,9 @@ #include #include #include +#ifdef LIME_VULKAN +#include +#endif #include #include #include @@ -55,8 +58,12 @@ #endif #include +#include #include +#include #include +#include +#include #ifdef LIME_SDL_SOUND #include @@ -67,3470 +74,12621 @@ DEFINE_KIND (k_finalizer); namespace lime { + static std::string lastVulkanRendererError; + static std::string lastVKError; - void gc_application (value handle) { - - Application* application = (Application*)val_data (handle); - delete application; - } + static void LogVulkanNativeBootstrap (const char* message) { +#ifdef LIME_VULKAN + ::FILE* file = ::fopen ("lime-vulkan-native.log", "a"); + if (file) { - void hl_gc_application (HL_CFFIPointer* handle) { + ::fprintf (file, "%s\n", message ? message : ""); + ::fclose (file); - Application* application = (Application*)handle->ptr; - delete application; + } +#endif } - void gc_file_watcher (value handle) { + static void LogVulkanNativeBootstrap (const std::string& message) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - delete watcher; - #endif + LogVulkanNativeBootstrap (message.c_str ()); } - void hl_gc_file_watcher (HL_CFFIPointer* handle) { + static uint64_t CombineVulkanHandle (int high, int low) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - delete watcher; - #endif + return ((uint64_t)(uint32_t)high << 32) | (uint32_t)low; } - void gc_font (value handle) { + static value CreateVulkanHandleValue (uint64_t handleValue) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (handle); - delete font; - #endif + value result = alloc_empty_object (); + alloc_field (result, val_id ("low"), alloc_int ((int32_t)(handleValue & 0xFFFFFFFFULL))); + alloc_field (result, val_id ("high"), alloc_int ((int32_t)(handleValue >> 32))); + return result; } - void hl_gc_font (HL_CFFIPointer* handle) { + static vdynamic* HLCreateVulkanHandleValue (uint64_t handleValue) { - #ifdef LIME_FREETYPE - Font* font = (Font*)handle->ptr; - delete font; - #endif + const int id_low = hl_hash_utf8 ("low"); + const int id_high = hl_hash_utf8 ("high"); + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_seti (result, id_low, &hlt_i32, (int32_t)(handleValue & 0xFFFFFFFFULL)); + hl_dyn_seti (result, id_high, &hlt_i32, (int32_t)(handleValue >> 32)); + return result; } - void gc_window (value handle) { +#ifdef LIME_VULKAN + static VkSurfaceKHR UInt64ToVulkanSurface (uint64_t value) { - Window* window = (Window*)val_data (handle); - delete window; + return (VkSurfaceKHR)value; } - void hl_gc_window (HL_CFFIPointer* handle) { - - Window* window = (Window*)handle->ptr; - delete window; + struct ManagedVulkanMappedMemory { - } + VkDevice device; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; + void* data; + }; - std::string wstring_utf8 (const std::wstring& val) { - std::string out; - unsigned int codepoint = 0; + static std::unordered_map mappedVulkanMemory; + static std::unordered_map > managedVulkanDeviceProcCache; - for (const wchar_t chr : val) { - if (chr >= 0xd800 && chr <= 0xdbff) { + static uint64_t GetManagedVulkanMappedMemoryKey (VkDeviceMemory memory) { - codepoint = ((chr - 0xd800) << 10) + 0x10000; + return (uint64_t)(uintptr_t)memory; - } else { + } - if (chr >= 0xdc00 && chr <= 0xdfff) { - codepoint |= chr - 0xdc00; + static VkDeviceSize NormalizeVulkanRangeSize (uint64_t size) { - } else { + return size == 0 ? VK_WHOLE_SIZE : (VkDeviceSize)size; - codepoint = chr; + } - } - if (codepoint <= 0x7f) { + static void ClearManagedVulkanDeviceProcCache (VkDevice device) { - out.append (1, static_cast (codepoint)); + if (device) managedVulkanDeviceProcCache.erase ((uint64_t)(uintptr_t)device); - } else if (codepoint <= 0x7ff) { + } - out.append (1, static_cast (0xc0 | ((codepoint >> 6) & 0x1f))); - out.append (1, static_cast (0x80 | (codepoint & 0x3f))); - } else if (codepoint <= 0xffff) { + static bool CreateManagedVulkanInstance (Window* targetWindow, const char* applicationName, VkInstance* outInstance) { - out.append (1, static_cast (0xe0 | ((codepoint >> 12) & 0x0f))); - out.append (1, static_cast (0x80 | ((codepoint >> 6) & 0x3f))); - out.append (1, static_cast (0x80 | (codepoint & 0x3f))); + if (!targetWindow || !outInstance) { - } else { + lastVKError = "Missing Vulkan window or output instance"; + return false; - out.append (1, static_cast (0xf0 | ((codepoint >> 18) & 0x07))); - out.append (1, static_cast (0x80 | ((codepoint >> 12) & 0x3f))); - out.append (1, static_cast (0x80 | ((codepoint >> 6) & 0x3f))); - out.append (1, static_cast (0x80 | (codepoint & 0x3f))); + } - } + *outInstance = VK_NULL_HANDLE; - codepoint = 0; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { - } + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; } - return out; + PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr (VK_NULL_HANDLE, "vkCreateInstance"); + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = + (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr (VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = + (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr (VK_NULL_HANDLE, "vkEnumerateInstanceVersion"); - } + if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties) { + lastVKError = "Missing required Vulkan global functions"; + return false; - vbyte* hl_wstring_to_utf8_bytes (const std::wstring& val) { + } - const std::string utf8 (wstring_utf8 (val)); - vbyte* const bytes = hl_alloc_bytes (utf8.size () + 1); - std::memcpy(bytes, utf8.c_str (), utf8.size () + 1); - return bytes; + unsigned int requiredExtensionCount = 0; + if (!targetWindow->GetVulkanInstanceExtensions (&requiredExtensionCount, 0)) { - } + lastVKError = "Failed to query required Vulkan window extensions"; + return false; + } - std::wstring* hxstring_to_wstring (HxString val) { + std::vector requiredExtensions (requiredExtensionCount); + if (requiredExtensionCount > 0 && !targetWindow->GetVulkanInstanceExtensions (&requiredExtensionCount, requiredExtensions.data ())) { - if (val.c_str ()) { + lastVKError = "Failed to fetch required Vulkan window extensions"; + return false; - #ifdef HX_WINDOWS - return new std::wstring (hxs_wchar (val, nullptr)); - #else - const std::string _val (hxs_utf8 (val, nullptr)); - return new std::wstring (_val.begin (), _val.end ()); - #endif + } - } else { + std::vector instanceExtensions; + for (size_t i = 0; i < requiredExtensions.size (); ++i) { - return 0; + instanceExtensions.push_back (requiredExtensions[i]); } - } - + bool portabilityEnumerationSupported = false; + uint32_t availableExtensionCount = 0; + if (vkEnumerateInstanceExtensionProperties (0, &availableExtensionCount, 0) == VK_SUCCESS && availableExtensionCount > 0) { - std::wstring* hxstring_to_wstring (hl_vstring* val) { - - if (val) { + std::vector availableExtensions (availableExtensionCount); + if (vkEnumerateInstanceExtensionProperties (0, &availableExtensionCount, availableExtensions.data ()) == VK_SUCCESS) { - std::string _val = std::string (hl_to_utf8 (val->bytes)); - #ifdef HX_WINDOWS - std::wstring_convert> converter; - return new std::wstring (converter.from_bytes (_val)); - #else - return new std::wstring (_val.begin (), _val.end ()); - #endif + for (size_t i = 0; i < availableExtensions.size (); ++i) { - } else { + #ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + if (strcmp (availableExtensions[i].extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { - return 0; + portabilityEnumerationSupported = true; - } + } + #endif - } + } + } - value wstring_to_value (std::wstring* val) { + } - if (val) { + if (portabilityEnumerationSupported) { - #ifdef HX_WINDOWS - return alloc_wstring (val->c_str ()); - #else - std::string _val = std::string (val->begin (), val->end ()); - return alloc_string (_val.c_str ()); + #ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + instanceExtensions.push_back (VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); #endif - } else { - - return 0; - } - } + uint32_t instanceVersion = VK_API_VERSION_1_0; + if (vkEnumerateInstanceVersion) { + vkEnumerateInstanceVersion (&instanceVersion); - value lime_application_create () { + } - Application* application = CreateApplication (); - return CFFIPointer (application, gc_application); + VkApplicationInfo applicationInfo; + memset (&applicationInfo, 0, sizeof (applicationInfo)); + applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + applicationInfo.pApplicationName = applicationName ? applicationName : "Lime"; + applicationInfo.pEngineName = "Lime"; + applicationInfo.applicationVersion = VK_MAKE_VERSION (1, 0, 0); + applicationInfo.engineVersion = VK_MAKE_VERSION (1, 0, 0); + applicationInfo.apiVersion = instanceVersion >= VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : instanceVersion; - } + VkInstanceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &applicationInfo; + createInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size (); + createInfo.ppEnabledExtensionNames = instanceExtensions.empty () ? 0 : instanceExtensions.data (); + #ifdef VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR + if (portabilityEnumerationSupported) { - HL_PRIM HL_CFFIPointer* HL_NAME(hl_application_create) () { + createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; - Application* application = CreateApplication (); - return HLCFFIPointer (application, (hl_finalizer)hl_gc_application); + } + #endif - } + VkResult result = vkCreateInstance (&createInfo, 0, outInstance); + if (result != VK_SUCCESS) { + lastVKError = "vkCreateInstance failed"; + return false; - void lime_application_event_manager_register (value callback, value eventObject) { + } - ApplicationEvent::callback = new ValuePointer (callback); - ApplicationEvent::eventObject = new ValuePointer (eventObject); + lastVKError.clear (); + return true; } - HL_PRIM void HL_NAME(hl_application_event_manager_register) (vclosure* callback, ApplicationEvent* eventObject) { - - ApplicationEvent::callback = new ValuePointer (callback); - ApplicationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + static std::vector GetVulkanDeviceExtensions (value extensions) { - } + std::vector deviceExtensions; + if (val_is_null (extensions)) { - int lime_application_exec (value application) { + deviceExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return deviceExtensions; - Application* app = (Application*)val_data (application); - return app->Exec (); + } - } + int length = val_array_size (extensions); + for (int i = 0; i < length; ++i) { + value extension = val_array_i (extensions, i); + if (!val_is_null (extension)) { - HL_PRIM int HL_NAME(hl_application_exec) (HL_CFFIPointer* application) { + deviceExtensions.push_back (val_string (extension)); - Application* app = (Application*)application->ptr; - return app->Exec (); + } - } + } + return deviceExtensions; - void lime_application_init (value application) { + } - Application* app = (Application*)val_data (application); - app->Init (); - } + static std::vector GetHLVulkanDeviceExtensions (hl_varray* extensions) { + std::vector deviceExtensions; - HL_PRIM void HL_NAME(hl_application_init) (HL_CFFIPointer* application) { + if (!extensions) { - Application* app = (Application*)application->ptr; - app->Init (); + deviceExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return deviceExtensions; - } + } + int length = extensions->size; + hl_vstring** extensionData = hl_aptr (extensions, hl_vstring*); - int lime_application_quit (value application) { + for (int i = 0; i < length; ++i) { - Application* app = (Application*)val_data (application); - return app->Quit (); + hl_vstring* extension = *extensionData++; + if (extension) { - } + deviceExtensions.push_back (hl_to_utf8 ((const uchar*)extension->bytes)); + } - HL_PRIM int HL_NAME(hl_application_quit) (HL_CFFIPointer* application) { + } - Application* app = (Application*)application->ptr; - return app->Quit (); + return deviceExtensions; } - void lime_application_set_frame_rate (value application, double frameRate) { - - Application* app = (Application*)val_data (application); - app->SetFrameRate (frameRate); + static PFN_vkVoidFunction GetManagedVulkanDeviceProc (Window* targetWindow, VkInstance instance, VkDevice device, const char* name) { - } + if (!targetWindow || !instance || !device || !name) { + lastVKError = "Missing Vulkan window, instance, or device"; + return 0; - HL_PRIM void HL_NAME(hl_application_set_frame_rate) (HL_CFFIPointer* application, double frameRate) { + } - Application* app = (Application*)application->ptr; - app->SetFrameRate (frameRate); + uint64_t deviceKey = (uint64_t)(uintptr_t)device; + std::string procName (name); + std::unordered_map >::iterator deviceCache = + managedVulkanDeviceProcCache.find (deviceKey); + if (deviceCache != managedVulkanDeviceProcCache.end ()) { - } + std::unordered_map::iterator procCache = deviceCache->second.find (procName); + if (procCache != deviceCache->second.end ()) return procCache->second; + } - void lime_application_set_main_loop (value application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { - Application* app = (Application*)val_data (application); - app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return 0; - } + } + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { - HL_PRIM void HL_NAME(hl_application_set_main_loop) (HL_CFFIPointer* application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + lastVKError = "Missing Vulkan device proc address function"; + return 0; - Application* app = (Application*)application->ptr; - app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + } - } + PFN_vkVoidFunction proc = vkGetDeviceProcAddr (device, procName.c_str ()); + if (!proc) { + lastVKError = std::string ("Missing Vulkan device function: ") + procName; + return 0; - void lime_application_set_vsync_mode (value application, int vsyncMode) { + } - Application* app = (Application*)val_data (application); - app->SetVSyncMode (vsyncMode); + managedVulkanDeviceProcCache[deviceKey][procName] = proc; + return proc; } - HL_PRIM void HL_NAME(hl_application_set_vsync_mode) (HL_CFFIPointer* application, int vsyncMode) { + static bool UpdateManagedVulkanDescriptorSets (Window* targetWindow, VkInstance instance, VkDevice device, const std::vector& packed) { - Application* app = (Application*)application->ptr; - app->SetVSyncMode (vsyncMode); + if (packed.empty ()) return true; - } + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = + (PFN_vkUpdateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUpdateDescriptorSets"); + if (!vkUpdateDescriptorSets) return false; + int writeCount = packed[0]; + if (writeCount < 0) return false; - bool lime_application_update (value application) { + std::vector bufferInfos; + std::vector imageInfos; + std::vector descriptorWrites; + bufferInfos.reserve ((size_t)writeCount); + imageInfos.reserve ((size_t)writeCount); + descriptorWrites.reserve ((size_t)writeCount); - Application* app = (Application*)val_data (application); - return app->Update (); + size_t index = 1; + for (int i = 0; i < writeCount; ++i) { - } + if (index >= packed.size ()) return false; + int kind = packed[index++]; + VkWriteDescriptorSet write; + memset (&write, 0, sizeof (write)); + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.descriptorCount = 1; - HL_PRIM bool HL_NAME(hl_application_update) (HL_CFFIPointer* application) { + if (kind == 0) { - Application* app = (Application*)application->ptr; - return app->Update (); + if (index + 11 > packed.size ()) return false; + write.dstSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (packed[index], packed[index + 1]); + write.dstBinding = (uint32_t)packed[index + 2]; + write.dstArrayElement = (uint32_t)packed[index + 3]; + write.descriptorType = (VkDescriptorType)packed[index + 4]; - } + VkDescriptorBufferInfo bufferInfo; + memset (&bufferInfo, 0, sizeof (bufferInfo)); + bufferInfo.buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (packed[index + 5], packed[index + 6]); + bufferInfo.offset = (VkDeviceSize)CombineVulkanHandle (packed[index + 7], packed[index + 8]); + bufferInfo.range = NormalizeVulkanRangeSize (CombineVulkanHandle (packed[index + 9], packed[index + 10])); + bufferInfos.push_back (bufferInfo); + write.pBufferInfo = &bufferInfos[bufferInfos.size () - 1]; + index += 11; + } else if (kind == 1) { - value lime_audio_load_bytes (value data, value buffer) { + if (index + 10 > packed.size ()) return false; + write.dstSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (packed[index], packed[index + 1]); + write.dstBinding = (uint32_t)packed[index + 2]; + write.dstArrayElement = (uint32_t)packed[index + 3]; + write.descriptorType = (VkDescriptorType)packed[index + 4]; - Resource resource; - Bytes bytes; + VkDescriptorImageInfo imageInfo; + memset (&imageInfo, 0, sizeof (imageInfo)); + imageInfo.imageView = (VkImageView)(uintptr_t)CombineVulkanHandle (packed[index + 5], packed[index + 6]); + imageInfo.sampler = (VkSampler)(uintptr_t)CombineVulkanHandle (packed[index + 7], packed[index + 8]); + imageInfo.imageLayout = (VkImageLayout)packed[index + 9]; + imageInfos.push_back (imageInfo); + write.pImageInfo = &imageInfos[imageInfos.size () - 1]; + index += 10; - AudioBuffer audioBuffer = AudioBuffer (buffer); + } else { - bytes.Set (data); - resource = Resource (&bytes); + lastVKError = "Invalid Vulkan descriptor write kind"; + return false; - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, &audioBuffer)) { + } - return audioBuffer.Value (buffer); + if (!write.dstSet) return false; + descriptorWrites.push_back (write); } - #endif + vkUpdateDescriptorSets (device, (uint32_t)descriptorWrites.size (), descriptorWrites.empty () ? 0 : descriptorWrites.data (), 0, 0); + lastVKError.clear (); + return true; - if (WAV::Decode (&resource, &audioBuffer)) { + } - return audioBuffer.Value (buffer); - } + static bool CreateManagedVulkanDevice (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, + const std::vector& requestedExtensions, VkDevice* outDevice, VkQueue* outQueue) { - #ifdef LIME_OGG - if (OGG::Decode (&resource, &audioBuffer)) { + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: begin"); + if (!targetWindow || !instance || !physicalDevice || !outDevice || !outQueue) { - return audioBuffer.Value (buffer); + lastVKError = "Missing Vulkan instance, physical device, or output device"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing input"); + return false; } - #endif - return alloc_null (); + *outDevice = VK_NULL_HANDLE; + *outQueue = VK_NULL_HANDLE; - } + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: acquired vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) { + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing vkGetInstanceProcAddr"); + return false; - HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_bytes) (Bytes* data, AudioBuffer* buffer) { + } - Resource resource = Resource (data); + PFN_vkCreateDevice vkCreateDevice = (PFN_vkCreateDevice)vkGetInstanceProcAddr (instance, "vkCreateDevice"); + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = + (PFN_vkEnumerateDeviceExtensionProperties)vkGetInstanceProcAddr (instance, "vkEnumerateDeviceExtensionProperties"); + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = + (PFN_vkGetPhysicalDeviceQueueFamilyProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceQueueFamilyProperties"); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: loaded device creation procs"); - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, buffer)) { + if (!vkCreateDevice || !vkGetDeviceProcAddr || !vkEnumerateDeviceExtensionProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { - return buffer; + lastVKError = "Missing required Vulkan device creation functions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing required procs"); + return false; } - #endif - if (WAV::Decode (&resource, buffer)) { + uint32_t queueFamilyCount = 0; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: query queue family count"); + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevice, &queueFamilyCount, 0); + if (queueFamilyIndex >= queueFamilyCount) { - return buffer; + lastVKError = "Invalid Vulkan queue family index"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: invalid queue family index"); + return false; } - #ifdef LIME_OGG - if (OGG::Decode (&resource, buffer)) { - - return buffer; + float queuePriority = 1.0f; + VkDeviceQueueCreateInfo queueCreateInfo; + memset (&queueCreateInfo, 0, sizeof (queueCreateInfo)); + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; - } - #endif + std::vector deviceExtensions; + for (size_t i = 0; i < requestedExtensions.size (); ++i) { - return 0; + deviceExtensions.push_back (requestedExtensions[i].c_str ()); - } + } + uint32_t extensionCount = 0; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: enumerate device extension count"); + VkResult extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, 0); + if (extensionResult != VK_SUCCESS) { - value lime_audio_load_file (value data, value buffer) { + lastVKError = "Could not enumerate Vulkan device extensions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: extension count enumeration failed"); + return false; - Resource resource; + } - AudioBuffer audioBuffer = AudioBuffer (buffer); + std::vector availableExtensions (extensionCount); + if (extensionCount > 0) { - resource = Resource (val_string (data)); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: enumerate device extensions"); + extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, availableExtensions.data ()); + if (extensionResult != VK_SUCCESS) { - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, &audioBuffer)) { + lastVKError = "Could not enumerate Vulkan device extensions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: extension enumeration failed"); + return false; - return audioBuffer.Value (buffer); + } } + + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + bool portabilitySubsetSupported = false; + bool portabilitySubsetRequested = false; #endif - if (WAV::Decode (&resource, &audioBuffer)) { + for (size_t i = 0; i < requestedExtensions.size (); ++i) { - return audioBuffer.Value (buffer); + bool extensionSupported = false; - } + for (size_t e = 0; e < availableExtensions.size (); ++e) { - #ifdef LIME_OGG - if (OGG::Decode (&resource, &audioBuffer)) { + if (strcmp (availableExtensions[e].extensionName, requestedExtensions[i].c_str ()) == 0) { - return audioBuffer.Value (buffer); + extensionSupported = true; + break; - } - #endif + } - return alloc_null (); + } - } + if (!extensionSupported) { + lastVKError = std::string ("Vulkan physical device does not support ") + requestedExtensions[i]; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: requested extension missing"); + return false; - HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_file) (hl_vstring* data, AudioBuffer* buffer) { + } - Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + if (strcmp (requestedExtensions[i].c_str (), VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) { - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, buffer)) { + portabilitySubsetRequested = true; - return buffer; + } + #endif } - #endif - if (WAV::Decode (&resource, buffer)) { - - return buffer; + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + for (size_t i = 0; i < availableExtensions.size (); ++i) { - } + if (strcmp (availableExtensions[i].extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) { - #ifdef LIME_OGG - if (OGG::Decode (&resource, buffer)) { + portabilitySubsetSupported = true; + break; - return buffer; + } } - #endif - - return 0; - } + if (portabilitySubsetSupported && !portabilitySubsetRequested) { + deviceExtensions.push_back (VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); - value lime_audio_load (value data, value buffer) { + } + #endif - if (val_is_string (data)) { + VkPhysicalDeviceFeatures deviceFeatures; + memset (&deviceFeatures, 0, sizeof (deviceFeatures)); - return lime_audio_load_file (data, buffer); + VkDeviceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = 1; + createInfo.pQueueCreateInfos = &queueCreateInfo; + createInfo.pEnabledFeatures = &deviceFeatures; + createInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size (); + createInfo.ppEnabledExtensionNames = deviceExtensions.empty () ? 0 : deviceExtensions.data (); - } else { + VkResult result = vkCreateDevice (physicalDevice, &createInfo, 0, outDevice); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: returned from vkCreateDevice"); + if (result != VK_SUCCESS) { - return lime_audio_load_bytes (data, buffer); + lastVKError = "vkCreateDevice failed"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: vkCreateDevice failed"); + return false; } - } - + PFN_vkGetDeviceQueue vkGetDeviceQueue = (PFN_vkGetDeviceQueue)vkGetDeviceProcAddr (*outDevice, "vkGetDeviceQueue"); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: loaded vkGetDeviceQueue"); + if (!vkGetDeviceQueue) { - value lime_bytes_from_data_pointer (double data, int length, value _bytes) { + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (*outDevice, "vkDestroyDevice"); + if (vkDestroyDevice) vkDestroyDevice (*outDevice, 0); + *outDevice = VK_NULL_HANDLE; + lastVKError = "Missing Vulkan device queue function"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing vkGetDeviceQueue"); + return false; - uintptr_t ptr = (uintptr_t)data; - Bytes bytes (_bytes); - bytes.Resize (length); + } - if (ptr) { + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: get device queue"); + vkGetDeviceQueue (*outDevice, queueFamilyIndex, 0, outQueue); + if (!*outQueue) { - memcpy (bytes.b, (const void*)ptr, length); + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (*outDevice, "vkDestroyDevice"); + if (vkDestroyDevice) vkDestroyDevice (*outDevice, 0); + *outDevice = VK_NULL_HANDLE; + lastVKError = "Failed to get Vulkan device queue"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: device queue was null"); + return false; } - return bytes.Value (_bytes); + lastVKError.clear (); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: success"); + return true; } - HL_PRIM Bytes* HL_NAME(hl_bytes_from_data_pointer) (double data, int length, Bytes* bytes) { + struct ManagedVulkanSwapchain { - uintptr_t ptr = (uintptr_t)data; - bytes->Resize (length); + VkSwapchainKHR handle; + VkFormat format; + VkColorSpaceKHR colorSpace; + VkExtent2D extent; + VkPresentModeKHR presentMode; + uint32_t imageCount; - if (ptr) { + }; - memcpy (bytes->b, (const void*)ptr, length); - } + static VkPresentModeKHR ChooseManagedVulkanPresentMode (const std::vector& presentModes, VkPresentModeKHR requestedPresentMode) { - return bytes; + bool hasRequested = false; + bool hasFifo = false; + bool hasMailbox = false; + bool hasImmediate = false; - } + for (size_t i = 0; i < presentModes.size (); ++i) { + if (presentModes[i] == requestedPresentMode) hasRequested = true; + if (presentModes[i] == VK_PRESENT_MODE_FIFO_KHR) hasFifo = true; + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) hasMailbox = true; + if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) hasImmediate = true; - double lime_bytes_get_data_pointer (value bytes) { + } - Bytes data = Bytes (bytes); - return (uintptr_t)data.b; + if (hasRequested) return requestedPresentMode; + if (hasFifo) return VK_PRESENT_MODE_FIFO_KHR; + if (hasMailbox) return VK_PRESENT_MODE_MAILBOX_KHR; + if (hasImmediate) return VK_PRESENT_MODE_IMMEDIATE_KHR; + return VK_PRESENT_MODE_FIFO_KHR; } - HL_PRIM double HL_NAME(hl_bytes_get_data_pointer) (Bytes* bytes) { + static value CreateVulkanSwapchainValue (const ManagedVulkanSwapchain& swapchain) { - return bytes ? (uintptr_t)bytes->b : 0; + value result = alloc_empty_object (); + alloc_field (result, val_id ("handle"), CreateVulkanHandleValue ((uint64_t)(uintptr_t)swapchain.handle)); + alloc_field (result, val_id ("format"), alloc_int ((int)swapchain.format)); + alloc_field (result, val_id ("colorSpace"), alloc_int ((int)swapchain.colorSpace)); + alloc_field (result, val_id ("width"), alloc_int ((int)swapchain.extent.width)); + alloc_field (result, val_id ("height"), alloc_int ((int)swapchain.extent.height)); + alloc_field (result, val_id ("imageCount"), alloc_int ((int)swapchain.imageCount)); + alloc_field (result, val_id ("presentMode"), alloc_int ((int)swapchain.presentMode)); + return result; } - double lime_bytes_get_data_pointer_offset (value bytes, int offset) { + static vdynamic* HLCreateVulkanSwapchainValue (const ManagedVulkanSwapchain& swapchain) { - if (val_is_null (bytes)) return 0; + const int id_handle = hl_hash_utf8 ("handle"); + const int id_format = hl_hash_utf8 ("format"); + const int id_colorSpace = hl_hash_utf8 ("colorSpace"); + const int id_width = hl_hash_utf8 ("width"); + const int id_height = hl_hash_utf8 ("height"); + const int id_imageCount = hl_hash_utf8 ("imageCount"); + const int id_presentMode = hl_hash_utf8 ("presentMode"); - Bytes data = Bytes (bytes); - return (uintptr_t)data.b + offset; + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_setp (result, id_handle, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)swapchain.handle)); + hl_dyn_seti (result, id_format, &hlt_i32, (int)swapchain.format); + hl_dyn_seti (result, id_colorSpace, &hlt_i32, (int)swapchain.colorSpace); + hl_dyn_seti (result, id_width, &hlt_i32, (int)swapchain.extent.width); + hl_dyn_seti (result, id_height, &hlt_i32, (int)swapchain.extent.height); + hl_dyn_seti (result, id_imageCount, &hlt_i32, (int)swapchain.imageCount); + hl_dyn_seti (result, id_presentMode, &hlt_i32, (int)swapchain.presentMode); + return result; } - HL_PRIM double HL_NAME(hl_bytes_get_data_pointer_offset) (Bytes* bytes, int offset) { + static value CreateVulkanAcquireValue (VkResult acquireResult, int imageIndex) { - if (!bytes) return 0; - return (uintptr_t)bytes->b + offset; + value result = alloc_empty_object (); + alloc_field (result, val_id ("result"), alloc_int ((int)acquireResult)); + alloc_field (result, val_id ("imageIndex"), alloc_int (imageIndex)); + return result; } - value lime_bytes_read_file (HxString path, value bytes) { - - Bytes data (bytes); - data.ReadFile (hxs_utf8 (path, nullptr)); - return data.Value (bytes); - - } - + static vdynamic* HLCreateVulkanAcquireValue (VkResult acquireResult, int imageIndex) { - HL_PRIM Bytes* HL_NAME(hl_bytes_read_file) (hl_vstring* path, Bytes* bytes) { + const int id_result = hl_hash_utf8 ("result"); + const int id_imageIndex = hl_hash_utf8 ("imageIndex"); - if (!path) return 0; - bytes->ReadFile (hl_to_utf8 ((const uchar*)path->bytes)); - return bytes; + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_seti (result, id_result, &hlt_i32, (int)acquireResult); + hl_dyn_seti (result, id_imageIndex, &hlt_i32, imageIndex); + return result; } - double lime_cffi_get_native_pointer (value handle) { + static value CreateVulkanMemoryRequirementsValue (const VkMemoryRequirements& requirements) { - return (uintptr_t)val_data (handle); + value result = alloc_empty_object (); + alloc_field (result, val_id ("size"), CreateVulkanHandleValue ((uint64_t)requirements.size)); + alloc_field (result, val_id ("alignment"), CreateVulkanHandleValue ((uint64_t)requirements.alignment)); + alloc_field (result, val_id ("memoryTypeBits"), alloc_int ((int)requirements.memoryTypeBits)); + return result; } - HL_PRIM double HL_NAME(hl_cffi_get_native_pointer) (HL_CFFIPointer* handle) { + static vdynamic* HLCreateVulkanMemoryRequirementsValue (const VkMemoryRequirements& requirements) { - return (uintptr_t)handle->ptr; + const int id_size = hl_hash_utf8 ("size"); + const int id_alignment = hl_hash_utf8 ("alignment"); + const int id_memoryTypeBits = hl_hash_utf8 ("memoryTypeBits"); + + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_setp (result, id_size, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)requirements.size)); + hl_dyn_setp (result, id_alignment, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)requirements.alignment)); + hl_dyn_seti (result, id_memoryTypeBits, &hlt_i32, (int)requirements.memoryTypeBits); + return result; } - void lime_cffi_finalizer (value abstract) { + static value CreateVulkanMemoryValue (VkDeviceMemory memory, uint32_t memoryTypeIndex) { - val_call0 ((value)val_data (abstract)); + value result = alloc_empty_object (); + alloc_field (result, val_id ("handle"), CreateVulkanHandleValue ((uint64_t)(uintptr_t)memory)); + alloc_field (result, val_id ("memoryTypeIndex"), alloc_int ((int)memoryTypeIndex)); + return result; } - value lime_cffi_set_finalizer (value callback) { + static vdynamic* HLCreateVulkanMemoryValue (VkDeviceMemory memory, uint32_t memoryTypeIndex) { - value abstract = alloc_abstract (k_finalizer, callback); - val_gc (abstract, lime_cffi_finalizer); - return abstract; + const int id_handle = hl_hash_utf8 ("handle"); + const int id_memoryTypeIndex = hl_hash_utf8 ("memoryTypeIndex"); + + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_setp (result, id_handle, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)memory)); + hl_dyn_seti (result, id_memoryTypeIndex, &hlt_i32, (int)memoryTypeIndex); + return result; } - void lime_clipboard_event_manager_register (value callback, value eventObject) { + static std::vector GetVulkanIntVector (value data) { - ClipboardEvent::callback = new ValuePointer (callback); - ClipboardEvent::eventObject = new ValuePointer (eventObject); + std::vector result; + if (val_is_null (data)) return result; - } + int length = val_array_size (data); + result.reserve (length); + for (int i = 0; i < length; ++i) { + result.push_back (val_int (val_array_i (data, i))); - HL_PRIM void HL_NAME(hl_clipboard_event_manager_register) (vclosure* callback, ClipboardEvent* eventObject) { + } - ClipboardEvent::callback = new ValuePointer (callback); - ClipboardEvent::eventObject = new ValuePointer ((vobj*)eventObject); + return result; } - value lime_clipboard_get_text () { - - if (Clipboard::HasText ()) { - - const char* text = Clipboard::GetText (); - value _text = alloc_string (text); - - // TODO: Should we free for all backends? (SDL requires it) + static std::vector GetHLVulkanIntVector (hl_varray* data) { - free ((char*)text); - return _text; + std::vector result; + if (!data) return result; - } else { + result.reserve (data->size); + int* values = hl_aptr (data, int); + for (int i = 0; i < data->size; ++i) { - return alloc_null (); + result.push_back (values[i]); } - } + return result; + } - HL_PRIM vbyte* HL_NAME(hl_clipboard_get_text) () { - if (Clipboard::HasText ()) { + static std::vector GetVulkanDoubleVector (value data) { - const char* text = Clipboard::GetText (); - return (vbyte*)text; + std::vector result; + if (val_is_null (data)) return result; - } else { + int length = val_array_size (data); + result.reserve (length); + for (int i = 0; i < length; ++i) { - return 0; + result.push_back (val_number (val_array_i (data, i))); } + return result; + } - void lime_clipboard_set_text (HxString text) { + static std::vector GetHLVulkanDoubleVector (hl_varray* data) { - Clipboard::SetText (hxs_utf8 (text, nullptr)); + std::vector result; + if (!data) return result; - } + result.reserve (data->size); + double* values = hl_aptr (data, double); + for (int i = 0; i < data->size; ++i) { + result.push_back (values[i]); - HL_PRIM void HL_NAME(hl_clipboard_set_text) (hl_vstring* text) { + } - Clipboard::SetText (text ? (const char*)hl_to_utf8 ((const uchar*)text->bytes) : NULL); + return result; } - double lime_data_pointer_offset (double pointer, int offset) { - - return (uintptr_t)pointer + offset; + static bool FindManagedVulkanMemoryType (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t typeFilter, + VkMemoryPropertyFlags properties, uint32_t* outMemoryTypeIndex) { - } + if (!targetWindow || !instance || !physicalDevice || !outMemoryTypeIndex) { + lastVKError = "Missing Vulkan window, instance, physical device, or memory type output"; + return false; - HL_PRIM double HL_NAME(hl_data_pointer_offset) (double pointer, int offset) { + } - return (uintptr_t)pointer + offset; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { - } + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; + } - value lime_deflate_compress (value buffer, value bytes) { + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = + (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceMemoryProperties"); + if (!vkGetPhysicalDeviceMemoryProperties) { - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); + lastVKError = "Missing Vulkan physical device memory properties function"; + return false; - Zlib::Compress (DEFLATE, &data, &result); + } - return result.Value (bytes); - #else - return alloc_null(); - #endif + VkPhysicalDeviceMemoryProperties memoryProperties; + memset (&memoryProperties, 0, sizeof (memoryProperties)); + vkGetPhysicalDeviceMemoryProperties (physicalDevice, &memoryProperties); - } + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { + if ((typeFilter & (1u << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { - HL_PRIM Bytes* HL_NAME(hl_deflate_compress) (Bytes* buffer, Bytes* bytes) { + *outMemoryTypeIndex = i; + lastVKError.clear (); + return true; - #ifdef LIME_ZLIB - Zlib::Compress (DEFLATE, buffer, bytes); - return bytes; - #else - return 0; - #endif + } - } + } + lastVKError = "Failed to find a compatible Vulkan memory type"; + return false; - value lime_deflate_decompress (value buffer, value bytes) { + } - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - Zlib::Decompress (DEFLATE, &data, &result); + static bool CreateManagedVulkanSwapchain (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, + VkSurfaceKHR surface, uint32_t queueFamilyIndex, int requestedWidth, int requestedHeight, VkPresentModeKHR requestedPresentMode, + VkSwapchainKHR oldSwapchain, ManagedVulkanSwapchain* outSwapchain) { - return result.Value (bytes); - #else - return alloc_null (); - #endif + if (!targetWindow || !instance || !physicalDevice || !device || !surface || !outSwapchain) { - } + lastVKError = "Missing Vulkan window, instance, device, surface, or output swapchain"; + return false; + } - HL_PRIM Bytes* HL_NAME(hl_deflate_decompress) (Bytes* buffer, Bytes* bytes) { + outSwapchain->handle = VK_NULL_HANDLE; + outSwapchain->format = VK_FORMAT_UNDEFINED; + outSwapchain->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + outSwapchain->extent.width = 0; + outSwapchain->extent.height = 0; + outSwapchain->presentMode = VK_PRESENT_MODE_FIFO_KHR; + outSwapchain->imageCount = 0; - #ifdef LIME_ZLIB - Zlib::Decompress (DEFLATE, buffer, bytes); - return bytes; - #else - return 0; - #endif + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { - } + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; + } - void lime_drop_event_manager_register (value callback, value eventObject) { + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = + (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = + (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = + (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = + (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfaceSupportKHR"); - DropEvent::callback = new ValuePointer (callback); - DropEvent::eventObject = new ValuePointer (eventObject); + if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR || !vkGetPhysicalDeviceSurfacePresentModesKHR) { - } + lastVKError = "Missing required Vulkan surface functions"; + return false; + } - HL_PRIM void HL_NAME(hl_drop_event_manager_register) (vclosure* callback, DropEvent* eventObject) { + if (vkGetPhysicalDeviceSurfaceSupportKHR) { - DropEvent::callback = new ValuePointer (callback); - DropEvent::eventObject = new ValuePointer ((vobj*)eventObject); + VkBool32 supportsPresent = VK_FALSE; + VkResult supportResult = vkGetPhysicalDeviceSurfaceSupportKHR (physicalDevice, queueFamilyIndex, surface, &supportsPresent); + if (supportResult != VK_SUCCESS || supportsPresent == VK_FALSE) { - } + lastVKError = "Vulkan queue family does not support presenting to this surface"; + return false; + } - value lime_file_dialog_open_directory (HxString title, HxString filter, HxString defaultPath) { + } - #ifdef LIME_TINYFILEDIALOGS + VkSurfaceCapabilitiesKHR capabilities; + memset (&capabilities, 0, sizeof (capabilities)); + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physicalDevice, surface, &capabilities); + if (result != VK_SUCCESS) { - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + lastVKError = "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"; + return false; - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); + } - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + uint32_t formatCount = 0; + result = vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, 0); + if (result != VK_SUCCESS || formatCount == 0) { - if (path) { + lastVKError = "Failed to query Vulkan surface formats"; + return false; - value _path = wstring_to_value (path); - delete path; - return _path; + } - } else { + std::vector formats (formatCount); + result = vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, formats.data ()); + if (result != VK_SUCCESS) { - return alloc_null (); + lastVKError = "vkGetPhysicalDeviceSurfaceFormatsKHR failed"; + return false; } - #endif + VkSurfaceFormatKHR surfaceFormat = formats[0]; + if (formats.size () == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { - return alloc_null (); + surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; + surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } + } else { + for (size_t i = 0; i < formats.size (); ++i) { - HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_directory) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + if (formats[i].format == VK_FORMAT_B8G8R8A8_UNORM && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - #ifdef LIME_TINYFILEDIALOGS + surfaceFormat = formats[i]; + break; - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + } - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); + } - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + } - if (path) { + uint32_t presentModeCount = 0; + result = vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice, surface, &presentModeCount, 0); + if (result != VK_SUCCESS) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + lastVKError = "Failed to query Vulkan present modes"; + return false; - } else { + } - return NULL; + std::vector presentModes (presentModeCount > 0 ? presentModeCount : 1, VK_PRESENT_MODE_FIFO_KHR); + if (presentModeCount > 0) { - } + result = vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice, surface, &presentModeCount, presentModes.data ()); + if (result != VK_SUCCESS) { - #endif + lastVKError = "vkGetPhysicalDeviceSurfacePresentModesKHR failed"; + return false; - return NULL; + } - } + } + int drawableWidth = requestedWidth; + int drawableHeight = requestedHeight; + if (drawableWidth <= 0 || drawableHeight <= 0) { - value lime_file_dialog_open_file (HxString title, HxString filter, HxString defaultPath) { + drawableWidth = 0; + drawableHeight = 0; + targetWindow->GetVulkanDrawableSize (&drawableWidth, &drawableHeight); - #ifdef LIME_TINYFILEDIALOGS + } - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + if (drawableWidth <= 0 || drawableHeight <= 0) { - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); + lastVKError = "Vulkan drawable size is zero"; + return false; - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + } - if (path) { + VkExtent2D extent; + if (capabilities.currentExtent.width != UINT32_MAX) { - value _path = wstring_to_value (path); - delete path; - return _path; + extent = capabilities.currentExtent; } else { - return alloc_null (); + extent.width = (uint32_t)(std::max) ((int)capabilities.minImageExtent.width, + (std::min) (drawableWidth, (int)capabilities.maxImageExtent.width)); + extent.height = (uint32_t)(std::max) ((int)capabilities.minImageExtent.height, + (std::min) (drawableHeight, (int)capabilities.maxImageExtent.height)); } - #endif + if ((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) { - return alloc_null (); + lastVKError = "Vulkan surface images do not support color attachments"; + return false; - } + } + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { - HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - #ifdef LIME_TINYFILEDIALOGS + } + if (capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); + } - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { - if (path) { + imageCount = capabilities.maxImageCount; - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + } - } else { + VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + const bool transparentWindow = targetWindow && ((targetWindow->flags & WINDOW_FLAG_TRANSPARENT) != 0); + const VkCompositeAlphaFlagBitsKHR opaqueCompositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + }; + const VkCompositeAlphaFlagBitsKHR transparentCompositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR + }; + const VkCompositeAlphaFlagBitsKHR* compositeAlphaFlags = transparentWindow ? transparentCompositeAlphaFlags : opaqueCompositeAlphaFlags; + const size_t compositeAlphaFlagCount = transparentWindow + ? sizeof (transparentCompositeAlphaFlags) / sizeof (transparentCompositeAlphaFlags[0]) + : sizeof (opaqueCompositeAlphaFlags) / sizeof (opaqueCompositeAlphaFlags[0]); + + for (size_t i = 0; i < compositeAlphaFlagCount; ++i) { + + if (capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { + + compositeAlpha = compositeAlphaFlags[i]; + break; - return NULL; + } } - #endif + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateSwapchainKHR"); + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkGetSwapchainImagesKHR"); + if (!vkCreateSwapchainKHR || !vkGetSwapchainImagesKHR) return false; + + VkSwapchainCreateInfoKHR createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = imageUsage; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = compositeAlpha; + createInfo.presentMode = ChooseManagedVulkanPresentMode (presentModes, requestedPresentMode); + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = oldSwapchain; + + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + result = vkCreateSwapchainKHR (device, &createInfo, 0, &swapchain); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateSwapchainKHR failed"; + return false; - return NULL; + } - } + uint32_t swapchainImageCount = 0; + result = vkGetSwapchainImagesKHR (device, swapchain, &swapchainImageCount, 0); + if (result != VK_SUCCESS || swapchainImageCount == 0) { + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroySwapchainKHR"); + if (vkDestroySwapchainKHR) vkDestroySwapchainKHR (device, swapchain, 0); + lastVKError = "Failed to query Vulkan swapchain images"; + return false; - value lime_file_dialog_open_files (HxString title, HxString filter, HxString defaultPath) { + } - #ifdef LIME_TINYFILEDIALOGS + outSwapchain->handle = swapchain; + outSwapchain->format = surfaceFormat.format; + outSwapchain->colorSpace = surfaceFormat.colorSpace; + outSwapchain->extent = extent; + outSwapchain->presentMode = createInfo.presentMode; + outSwapchain->imageCount = swapchainImageCount; + lastVKError.clear (); + return true; - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::vector files; + } +#endif - FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); - value result = alloc_array (files.size ()); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + void gc_application (value handle) { - for (int i = 0; i < files.size (); i++) { + Application* application = (Application*)val_data (handle); + delete application; - value _file = wstring_to_value (files[i]); - val_array_set_i (result, i, _file); - delete files[i]; + } - } - #else - value result = alloc_array (0); - #endif + void hl_gc_application (HL_CFFIPointer* handle) { - return result; + Application* application = (Application*)handle->ptr; + delete application; } - HL_PRIM hl_varray* HL_NAME(hl_file_dialog_open_files) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + void gc_file_watcher (value handle) { - #ifdef LIME_TINYFILEDIALOGS + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + delete watcher; + #endif - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + } - std::vector files; - FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); - hl_varray* result = (hl_varray*)hl_alloc_array (&hlt_bytes, files.size ()); - vbyte** resultData = hl_aptr (result, vbyte*); + void hl_gc_file_watcher (HL_CFFIPointer* handle) { - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + delete watcher; + #endif - for (int i = 0; i < files.size (); i++) { + } - *resultData++ = hl_wstring_to_utf8_bytes (*files[i]); - delete files[i]; - } + void gc_font (value handle) { - #else - hl_varray* result = hl_alloc_array (&hlt_bytes, 0); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (handle); + delete font; #endif - return result; + } + + + void hl_gc_font (HL_CFFIPointer* handle) { + + #ifdef LIME_FREETYPE + Font* font = (Font*)handle->ptr; + delete font; + #endif } - value lime_file_dialog_save_file (HxString title, HxString filter, HxString defaultPath) { + void gc_window (value handle) { - #ifdef LIME_TINYFILEDIALOGS + Window* window = (Window*)val_data (handle); + delete window; - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + } - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + void hl_gc_window (HL_CFFIPointer* handle) { - if (path) { + Window* window = (Window*)handle->ptr; + delete window; - value _path = wstring_to_value (path); - delete path; - return _path; + } - } else { - return alloc_null (); + std::string wstring_utf8 (const std::wstring& val) { - } + std::string out; + unsigned int codepoint = 0; - #endif + for (const wchar_t chr : val) { - return alloc_null (); + if (chr >= 0xd800 && chr <= 0xdbff) { - } + codepoint = ((chr - 0xd800) << 10) + 0x10000; + } else { - HL_PRIM vbyte* HL_NAME(hl_file_dialog_save_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + if (chr >= 0xdc00 && chr <= 0xdfff) { - #ifdef LIME_TINYFILEDIALOGS + codepoint |= chr - 0xdc00; - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + } else { - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); + codepoint = chr; - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + } - if (path) { + if (codepoint <= 0x7f) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + out.append (1, static_cast (codepoint)); - } else { + } else if (codepoint <= 0x7ff) { - return NULL; + out.append (1, static_cast (0xc0 | ((codepoint >> 6) & 0x1f))); + out.append (1, static_cast (0x80 | (codepoint & 0x3f))); - } + } else if (codepoint <= 0xffff) { - #endif + out.append (1, static_cast (0xe0 | ((codepoint >> 12) & 0x0f))); + out.append (1, static_cast (0x80 | ((codepoint >> 6) & 0x3f))); + out.append (1, static_cast (0x80 | (codepoint & 0x3f))); - return NULL; + } else { - } + out.append (1, static_cast (0xf0 | ((codepoint >> 18) & 0x07))); + out.append (1, static_cast (0x80 | ((codepoint >> 12) & 0x3f))); + out.append (1, static_cast (0x80 | ((codepoint >> 6) & 0x3f))); + out.append (1, static_cast (0x80 | (codepoint & 0x3f))); + } - value lime_file_watcher_create (value callback) { + codepoint = 0; - #ifdef LIME_EFSW - FileWatcher* watcher = new FileWatcher (callback); - return CFFIPointer (watcher, gc_file_watcher); - #else - return alloc_null (); - #endif + } + + } + + return out; } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_file_watcher_create) (vclosure* callback) { + vbyte* hl_wstring_to_utf8_bytes (const std::wstring& val) { - // #ifdef LIME_EFSW - // FileWatcher* watcher = new FileWatcher (callback); - // return HLCFFIPointer (watcher, (hl_finalizer)hl_gc_file_watcher); - // #else - return 0; - // #endif + const std::string utf8 (wstring_utf8 (val)); + vbyte* const bytes = hl_alloc_bytes (utf8.size () + 1); + std::memcpy(bytes, utf8.c_str (), utf8.size () + 1); + return bytes; } - value lime_file_watcher_add_directory (value handle, value path, bool recursive) { + #ifdef HX_WINDOWS + #define hxs_to_fd_str(str) hxs_wchar(str, nullptr) + #define alloc_from_fd_str(str) alloc_wstring(str) + #define alloc_from_fd_str_len(str, len) alloc_wstring_len(str, len) - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - return alloc_int (watcher->AddDirectory (val_string (path), recursive)); - #else - return alloc_int (0); - #endif + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { + if (val) { + return val->bytes; + } + return nullptr; + } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src, size_t length) { + // copy first, since hl_to_utf8 has no length parameter, and hl_utf16_to_utf8 is not exposed + FileDialog::char_t* utf16 = (FileDialog::char_t*)hl_copy_bytes((vbyte*)src, (length + 1) * sizeof(FileDialog::char_t)); + utf16[length] = L'\0'; + return (vbyte*)hl_to_utf8(utf16); } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src) { + return (vbyte*)hl_to_utf8((uchar*)src); + } - HL_PRIM int HL_NAME(hl_file_watcher_add_directory) (HL_CFFIPointer* handle, hl_vstring* path, bool recursive) { + #else + #define hxs_to_fd_str(str) hxs_utf8(str, nullptr) + #define alloc_from_fd_str(str) alloc_string(str) + #define alloc_from_fd_str_len(str, len) alloc_string_len(str, len) - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - return watcher->AddDirectory ((const char*)path, recursive); - #else - return 0; - #endif + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { + if (val) { + return hl_to_utf8 (val->bytes); + } + return nullptr; + } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src, size_t length) { + vbyte* result = hl_copy_bytes((vbyte*)src, length + 1); + result[length] = '\0'; + return result; } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src) { + return hl_fd_str_to_utf8_bytes(src, std::strlen(src)); + } + #endif - void lime_file_watcher_remove_directory (value handle, value watchID) { + value lime_application_create () { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - watcher->RemoveDirectory (val_int (watchID)); - #endif + Application* application = CreateApplication (); + return CFFIPointer (application, gc_application); } - HL_PRIM void HL_NAME(hl_file_watcher_remove_directory) (HL_CFFIPointer* handle, int watchID) { + HL_PRIM HL_CFFIPointer* HL_NAME(hl_application_create) () { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - watcher->RemoveDirectory (watchID); - #endif + Application* application = CreateApplication (); + return HLCFFIPointer (application, (hl_finalizer)hl_gc_application); } - void lime_file_watcher_update (value handle) { + void lime_application_event_manager_register (value callback, value eventObject) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - watcher->Update (); - #endif + ApplicationEvent::callback = new ValuePointer (callback); + ApplicationEvent::eventObject = new ValuePointer (eventObject); } - HL_PRIM void HL_NAME(hl_file_watcher_update) (HL_CFFIPointer* handle) { + HL_PRIM void HL_NAME(hl_application_event_manager_register) (vclosure* callback, ApplicationEvent* eventObject) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - watcher->Update (); - #endif + ApplicationEvent::callback = new ValuePointer (callback); + ApplicationEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - int lime_font_get_ascender (value fontHandle) { + int lime_application_exec (value application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetAscender (); - #else - return 0; - #endif + Application* app = (Application*)val_data (application); + return app->Exec (); } - HL_PRIM int HL_NAME(hl_font_get_ascender) (HL_CFFIPointer* fontHandle) { + HL_PRIM int HL_NAME(hl_application_exec) (HL_CFFIPointer* application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetAscender (); - #else - return 0; - #endif + Application* app = (Application*)application->ptr; + return app->Exec (); } - int lime_font_get_descender (value fontHandle) { + void lime_application_init (value application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetDescender (); - #else - return 0; - #endif + Application* app = (Application*)val_data (application); + app->Init (); } - HL_PRIM int HL_NAME(hl_font_get_descender) (HL_CFFIPointer* fontHandle) { + HL_PRIM void HL_NAME(hl_application_init) (HL_CFFIPointer* application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetDescender (); - #else - return 0; - #endif + Application* app = (Application*)application->ptr; + app->Init (); } - value lime_font_get_family_name (value fontHandle) { + int lime_application_quit (value application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - wchar_t *name = font->GetFamilyName (); - value result = alloc_wstring (name); - delete name; - return result; - #else - return alloc_null (); - #endif + Application* app = (Application*)val_data (application); + return app->Quit (); } - HL_PRIM vbyte* HL_NAME(hl_font_get_family_name) (HL_CFFIPointer* fontHandle) { + HL_PRIM int HL_NAME(hl_application_quit) (HL_CFFIPointer* application) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - wchar_t *name = font->GetFamilyName (); - if (!name) - return nullptr; - vbyte* const result = hl_wstring_to_utf8_bytes (name); - delete name; - return result; - #else - return 0; - #endif + Application* app = (Application*)application->ptr; + return app->Quit (); } - int lime_font_get_glyph_index (value fontHandle, HxString character) { + void lime_application_set_frame_rate (value application, double frameRate) { + + Application* app = (Application*)val_data (application); + app->SetFrameRate (frameRate); + + } + + + HL_PRIM void HL_NAME(hl_application_set_frame_rate) (HL_CFFIPointer* application, double frameRate) { + + Application* app = (Application*)application->ptr; + app->SetFrameRate (frameRate); + + } + + + void lime_application_set_main_loop (value application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + + Application* app = (Application*)val_data (application); + app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + + } + + + HL_PRIM void HL_NAME(hl_application_set_main_loop) (HL_CFFIPointer* application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + + Application* app = (Application*)application->ptr; + app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + + } + + + void lime_application_set_vsync_mode (value application, int vsyncMode) { + + Application* app = (Application*)val_data (application); + app->SetVSyncMode (vsyncMode); + + } + + + HL_PRIM void HL_NAME(hl_application_set_vsync_mode) (HL_CFFIPointer* application, int vsyncMode) { + + Application* app = (Application*)application->ptr; + app->SetVSyncMode (vsyncMode); + + } + + + bool lime_application_update (value application) { + + Application* app = (Application*)val_data (application); + return app->Update (); + + } + + + HL_PRIM bool HL_NAME(hl_application_update) (HL_CFFIPointer* application) { + + Application* app = (Application*)application->ptr; + return app->Update (); + + } + + + value lime_audio_load_bytes (value data, value buffer) { + + Resource resource; + Bytes bytes; + + AudioBuffer audioBuffer = AudioBuffer (buffer); + + bytes.Set (data); + resource = Resource (&bytes); + + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + #endif + + + if (WAV::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + + #ifdef LIME_OGG + if (OGG::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_bytes) (Bytes* data, AudioBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + if (WAV::Decode (&resource, buffer)) { + + return buffer; + + } + + #ifdef LIME_OGG + if (OGG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_audio_load_file (value data, value buffer) { + + Resource resource; + + AudioBuffer audioBuffer = AudioBuffer (buffer); + + resource = Resource (val_string (data)); + + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + #endif + + if (WAV::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + + #ifdef LIME_OGG + if (OGG::Decode (&resource, &audioBuffer)) { + + return audioBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_file) (hl_vstring* data, AudioBuffer* buffer) { + + Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + if (WAV::Decode (&resource, buffer)) { + + return buffer; + + } + + #ifdef LIME_OGG + if (OGG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_audio_load (value data, value buffer) { + + if (val_is_string (data)) { + + return lime_audio_load_file (data, buffer); + + } else { + + return lime_audio_load_bytes (data, buffer); + + } + + } + + + value lime_bytes_from_data_pointer (double data, int length, value _bytes) { + + uintptr_t ptr = (uintptr_t)data; + Bytes bytes (_bytes); + bytes.Resize (length); + + if (ptr) { + + memcpy (bytes.b, (const void*)ptr, length); + + } + + return bytes.Value (_bytes); + + } + + + HL_PRIM Bytes* HL_NAME(hl_bytes_from_data_pointer) (double data, int length, Bytes* bytes) { + + uintptr_t ptr = (uintptr_t)data; + bytes->Resize (length); + + if (ptr) { + + memcpy (bytes->b, (const void*)ptr, length); + + } + + return bytes; + + } + + + double lime_bytes_get_data_pointer (value bytes) { + + Bytes data = Bytes (bytes); + return (uintptr_t)data.b; + + } + + + HL_PRIM double HL_NAME(hl_bytes_get_data_pointer) (Bytes* bytes) { + + return bytes ? (uintptr_t)bytes->b : 0; + + } + + + double lime_bytes_get_data_pointer_offset (value bytes, int offset) { + + if (val_is_null (bytes)) return 0; + + Bytes data = Bytes (bytes); + return (uintptr_t)data.b + offset; + + } + + + HL_PRIM double HL_NAME(hl_bytes_get_data_pointer_offset) (Bytes* bytes, int offset) { + + if (!bytes) return 0; + return (uintptr_t)bytes->b + offset; + + } + + + value lime_bytes_read_file (HxString path, value bytes) { + + Bytes data (bytes); + data.ReadFile (hxs_utf8 (path, nullptr)); + return data.Value (bytes); + + } + + + HL_PRIM Bytes* HL_NAME(hl_bytes_read_file) (hl_vstring* path, Bytes* bytes) { + + if (!path) return 0; + bytes->ReadFile (hl_to_utf8 ((const uchar*)path->bytes)); + return bytes; + + } + + + double lime_cffi_get_native_pointer (value handle) { + + return (uintptr_t)val_data (handle); + + } + + + HL_PRIM double HL_NAME(hl_cffi_get_native_pointer) (HL_CFFIPointer* handle) { + + return (uintptr_t)handle->ptr; + + } + + + void lime_cffi_finalizer (value abstract) { + + val_call0 ((value)val_data (abstract)); + + } + + + value lime_cffi_set_finalizer (value callback) { + + value abstract = alloc_abstract (k_finalizer, callback); + val_gc (abstract, lime_cffi_finalizer); + return abstract; + + } + + + void lime_clipboard_event_manager_register (value callback, value eventObject) { + + ClipboardEvent::callback = new ValuePointer (callback); + ClipboardEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_clipboard_event_manager_register) (vclosure* callback, ClipboardEvent* eventObject) { + + ClipboardEvent::callback = new ValuePointer (callback); + ClipboardEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_clipboard_get_text () { + + if (Clipboard::HasText ()) { + + const char* text = Clipboard::GetText (); + value _text = alloc_string (text); + + // TODO: Should we free for all backends? (SDL requires it) + + free ((char*)text); + return _text; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_clipboard_get_text) () { + + if (Clipboard::HasText ()) { + + const char* text = Clipboard::GetText (); + return (vbyte*)text; + + } else { + + return 0; + + } + + } + + + void lime_clipboard_set_text (HxString text) { + + Clipboard::SetText (hxs_utf8 (text, nullptr)); + + } + + + HL_PRIM void HL_NAME(hl_clipboard_set_text) (hl_vstring* text) { + + Clipboard::SetText (text ? (const char*)hl_to_utf8 ((const uchar*)text->bytes) : NULL); + + } + + + double lime_data_pointer_offset (double pointer, int offset) { + + return (uintptr_t)pointer + offset; + + } + + + HL_PRIM double HL_NAME(hl_data_pointer_offset) (double pointer, int offset) { + + return (uintptr_t)pointer + offset; + + } + + + value lime_deflate_compress (value buffer, value bytes) { + + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); + + Zlib::Compress (DEFLATE, &data, &result); + + return result.Value (bytes); + #else + return alloc_null(); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_deflate_compress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_ZLIB + Zlib::Compress (DEFLATE, buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + value lime_deflate_decompress (value buffer, value bytes) { + + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); + + Zlib::Decompress (DEFLATE, &data, &result); + + return result.Value (bytes); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_deflate_decompress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_ZLIB + Zlib::Decompress (DEFLATE, buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + void lime_drop_event_manager_register (value callback, value eventObject) { + + DropEvent::callback = new ValuePointer (callback); + DropEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_drop_event_manager_register) (vclosure* callback, DropEvent* eventObject) { + + DropEvent::callback = new ValuePointer (callback); + DropEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_file_dialog_open_directory (HxString title, HxString filter, HxString defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::OpenDirectory (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); + + if (path) { + + return alloc_from_fd_str (path); + + } + + #endif + + return alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_directory) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::OpenDirectory (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); + + if (path) { + + return hl_fd_str_to_utf8_bytes(path); + + } + + #endif + + return NULL; + + } + + + value lime_file_dialog_open_file (HxString title, HxString filter, HxString defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::OpenFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); + + if (path) { + + return alloc_from_fd_str (path); + + } + + #endif + + return alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::OpenFile (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); + + if (path) { + + return hl_fd_str_to_utf8_bytes (path); + + } + + #endif + + return NULL; + + } + + + value lime_file_dialog_open_files (HxString title, HxString filter, HxString defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + auto files = FileDialog::OpenFiles (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); + value result = alloc_array (files.size ()); + + for (int i = 0; i < files.size (); i++) { + + auto file_str = files[i]; + + value file = alloc_from_fd_str_len (file_str.data(), file_str.size()); + val_array_set_i (result, i, file); + + } + + #else + value result = alloc_array (0); + #endif + + return result; + + } + + + HL_PRIM hl_varray* HL_NAME(hl_file_dialog_open_files) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + auto files = FileDialog::OpenFiles (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); + hl_varray* result = (hl_varray*)hl_alloc_array (&hlt_bytes, files.size ()); + vbyte** resultData = hl_aptr (result, vbyte*); + + for (int i = 0; i < files.size (); i++) { + + auto file_str = files[i]; + *resultData++ = hl_fd_str_to_utf8_bytes (file_str.data(), file_str.size()); + + } + + #else + hl_varray* result = hl_alloc_array (&hlt_bytes, 0); + #endif + + return result; + + } + + + value lime_file_dialog_save_file (HxString title, HxString filter, HxString defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::SaveFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); + + if (path) { + + return alloc_from_fd_str (path); + + } + + #endif + + return alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_file_dialog_save_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + + #ifdef LIME_TINYFILEDIALOGS + + const FileDialog::char_t* path = FileDialog::SaveFile (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); + + if (path) { + + return hl_fd_str_to_utf8_bytes (path); + + } + + #endif + + return NULL; + + } + + + value lime_file_watcher_create (value callback) { + + #ifdef LIME_EFSW + FileWatcher* watcher = new FileWatcher (callback); + return CFFIPointer (watcher, gc_file_watcher); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_file_watcher_create) (vclosure* callback) { + + // #ifdef LIME_EFSW + // FileWatcher* watcher = new FileWatcher (callback); + // return HLCFFIPointer (watcher, (hl_finalizer)hl_gc_file_watcher); + // #else + return 0; + // #endif + + } + + + value lime_file_watcher_add_directory (value handle, value path, bool recursive) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + return alloc_int (watcher->AddDirectory (val_string (path), recursive)); + #else + return alloc_int (0); + #endif + + } + + + HL_PRIM int HL_NAME(hl_file_watcher_add_directory) (HL_CFFIPointer* handle, hl_vstring* path, bool recursive) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + return watcher->AddDirectory ((const char*)path, recursive); + #else + return 0; + #endif + + } + + + void lime_file_watcher_remove_directory (value handle, value watchID) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + watcher->RemoveDirectory (val_int (watchID)); + #endif + + } + + + HL_PRIM void HL_NAME(hl_file_watcher_remove_directory) (HL_CFFIPointer* handle, int watchID) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + watcher->RemoveDirectory (watchID); + #endif + + } + + + void lime_file_watcher_update (value handle) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + watcher->Update (); + #endif + + } + + + HL_PRIM void HL_NAME(hl_file_watcher_update) (HL_CFFIPointer* handle) { + + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + watcher->Update (); + #endif + + } + + + int lime_font_get_ascender (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetAscender (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_ascender) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetAscender (); + #else + return 0; + #endif + + } + + + int lime_font_get_descender (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetDescender (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_descender) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetDescender (); + #else + return 0; + #endif + + } + + + value lime_font_get_family_name (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + wchar_t *name = font->GetFamilyName (); + value result = alloc_wstring (name); + delete name; + return result; + #else + return alloc_null (); + #endif + + } + + + HL_PRIM vbyte* HL_NAME(hl_font_get_family_name) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + wchar_t *name = font->GetFamilyName (); + if (!name) + return nullptr; + vbyte* const result = hl_wstring_to_utf8_bytes (name); + delete name; + return result; + #else + return 0; + #endif + + } + + + int lime_font_get_glyph_index (value fontHandle, HxString character) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetGlyphIndex (hxs_utf8 (character, nullptr)); + #else + return -1; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_glyph_index) (HL_CFFIPointer* fontHandle, hl_vstring* character) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetGlyphIndex (character ? (char*)hl_to_utf8 ((const uchar*)character->bytes) : NULL); + #else + return -1; + #endif + + } + + + value lime_font_get_glyph_indices (value fontHandle, HxString characters) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->GetGlyphIndices (true, hxs_utf8 (characters, nullptr)); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM hl_varray* HL_NAME(hl_font_get_glyph_indices) (HL_CFFIPointer* fontHandle, hl_vstring* characters) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return (hl_varray*)font->GetGlyphIndices (false, characters ? (char*)hl_to_utf8 ((const uchar*)characters->bytes) : NULL); + #else + return 0; + #endif + + } + + + value lime_font_get_glyph_metrics (value fontHandle, int index) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->GetGlyphMetrics (true, index); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_font_get_glyph_metrics) (HL_CFFIPointer* fontHandle, int index) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return (vdynamic*)font->GetGlyphMetrics (false, index); + #else + return 0; + #endif + + } + + + int lime_font_get_height (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetHeight (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_height) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetHeight (); + #else + return 0; + #endif + + } + + + int lime_font_get_num_glyphs (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetNumGlyphs (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_num_glyphs) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetNumGlyphs (); + #else + return 0; + #endif + + } + + + int lime_font_get_underline_position (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnderlinePosition (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_underline_position) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnderlinePosition (); + #else + return 0; + #endif + + } + + + int lime_font_get_underline_thickness (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnderlineThickness (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_underline_thickness) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnderlineThickness (); + #else + return 0; + #endif + + } + + + int lime_font_get_strikethrough_position (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetStrikethroughPosition (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_strikethrough_position) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetStrikethroughPosition (); + #else + return 0; + #endif + + } + + + int lime_font_get_strikethrough_thickness (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetStrikethroughThickness (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_strikethrough_thickness) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetStrikethroughThickness (); + #else + return 0; + #endif + + } + + + int lime_font_get_units_per_em (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnitsPerEM (); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_font_get_units_per_em) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnitsPerEM (); + #else + return 0; + #endif + + } + + + value lime_font_load_bytes (value data) { + + #ifdef LIME_FREETYPE + Resource resource; + Bytes bytes; + + bytes.Set (data); + resource = Resource (&bytes); + + Font *font = new Font (&resource, 0); + + if (font) { + + if (font->face) { + + return CFFIPointer (font, gc_font); + + } else { + + delete font; + + } + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_bytes) (Bytes* data) { + + #ifdef LIME_FREETYPE + Resource resource = Resource (data); + + Font *font = new Font (&resource, 0); + + if (font) { + + if (font->face) { + + return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + + } else { + + delete font; + + } + + } + #endif + + return 0; + + } + + + value lime_font_load_file (value data) { + + #ifdef LIME_FREETYPE + Resource resource = Resource (val_string (data)); + + Font *font = new Font (&resource, 0); + + if (font) { + + if (font->face) { + + return CFFIPointer (font, gc_font); + + } else { + + delete font; + + } + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_file) (hl_vstring* data) { + + #ifdef LIME_FREETYPE + Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + + Font *font = new Font (&resource, 0); + + if (font) { + + if (font->face) { + + return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + + } else { + + delete font; + + } + + } + #endif + + return 0; + + } + + + value lime_font_load (value data) { + + if (val_is_string (data)) { + + return lime_font_load_file (data); + + } else { + + return lime_font_load_bytes (data); + + } + + } + + + value lime_font_outline_decompose (value fontHandle, int size) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->Decompose (true, size); + #else + return alloc_null (); + #endif + + } + + + value lime_font_outline_decompose_no_hint (value fontHandle, int size) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->Decompose (true, size, false); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose) (HL_CFFIPointer* fontHandle, int size) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return (vdynamic*)font->Decompose (false, size); + #else + return 0; + #endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose_no_hint) (HL_CFFIPointer* fontHandle, int size) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return (vdynamic*)font->Decompose (false, size, false); + #else + return 0; + #endif + + } + + + value lime_font_render_glyph (value fontHandle, int index, value data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); + + if (font->RenderGlyph (index, &bytes)) { + + return bytes.Value (data); + + } + #endif + + return alloc_null (); + + } + + + value lime_font_render_glyph_with_flags (value fontHandle, int index, int loadFlags, value data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); + + if (font->RenderGlyphWithFlags (index, loadFlags, &bytes)) { + + return bytes.Value (data); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM Bytes* HL_NAME(hl_font_render_glyph) (HL_CFFIPointer* fontHandle, int index, Bytes* data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + + if (font->RenderGlyph (index, data)) { + + return data; + + } + #endif + + return NULL; + + } + + + HL_PRIM Bytes* HL_NAME(hl_font_render_glyph_with_flags) (HL_CFFIPointer* fontHandle, int index, int loadFlags, Bytes* data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + + if (font->RenderGlyphWithFlags (index, loadFlags, data)) { + + return data; + + } + #endif + + return NULL; + + } + + + value lime_font_render_glyphs (value fontHandle, value indices, value data) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); + + if (font->RenderGlyphs (indices, &bytes)) { + + return bytes.Value (data); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM Bytes* HL_NAME(hl_font_render_glyphs) (HL_CFFIPointer* fontHandle, hl_varray* indices, Bytes* data) { + + // #ifdef LIME_FREETYPE + // Font *font = (Font*)fontHandle->ptr; + // return font->RenderGlyphs (indices, &bytes); + // #else + return NULL; + // #endif + + } + + + void lime_font_set_size (value fontHandle, int fontSize, int dpi) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + font->SetSize (fontSize, dpi); + #endif + + } + + + HL_PRIM void HL_NAME(hl_font_set_size) (HL_CFFIPointer* fontHandle, int fontSize, int dpi) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + font->SetSize (fontSize, dpi); + #endif + + } + + + void lime_gamepad_add_mappings (value mappings) { + + int length = val_array_size (mappings); + + for (int i = 0; i < length; i++) { + + Gamepad::AddMapping (val_string (val_array_i (mappings, i))); + + } + + } + + + HL_PRIM void HL_NAME(hl_gamepad_add_mappings) (hl_varray* mappings) { + + int length = mappings->size; + hl_vstring** mappingsData = hl_aptr (mappings, hl_vstring*); + + for (int i = 0; i < length; i++) { + + Gamepad::AddMapping (hl_to_utf8 ((const uchar*)((*mappingsData++)->bytes))); + + } + + } + + + void lime_gamepad_event_manager_register (value callback, value eventObject) { + + GamepadEvent::callback = new ValuePointer (callback); + GamepadEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_gamepad_event_manager_register) (vclosure* callback, GamepadEvent* eventObject) { + + GamepadEvent::callback = new ValuePointer (callback); + GamepadEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_gamepad_get_device_guid (int id) { + + const char* guid = Gamepad::GetDeviceGUID (id); + + if (guid) { + + value result = alloc_string (guid); + delete guid; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_guid) (int id) { + + const char* guid = Gamepad::GetDeviceGUID (id); + + if (guid) { + + return (vbyte*)guid; + + } else { + + return 0; + + } + + } + + + value lime_gamepad_get_device_name (int id) { + + const char* name = Gamepad::GetDeviceName (id); + return name ? alloc_string (name) : alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_name) (int id) { + + return (vbyte*)Gamepad::GetDeviceName (id); + + } + + + void lime_gamepad_rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { + + Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + + } + + + HL_PRIM void HL_NAME(hl_gamepad_rumble) (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { + + Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + + } + + + value lime_gzip_compress (value buffer, value bytes) { + + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); + + Zlib::Compress (GZIP, &data, &result); + + return result.Value (bytes); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_gzip_compress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_ZLIB + Zlib::Compress (GZIP, buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + value lime_gzip_decompress (value buffer, value bytes) { + + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); + + Zlib::Decompress (GZIP, &data, &result); + + return result.Value (bytes); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_gzip_decompress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_ZLIB + Zlib::Decompress (GZIP, buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + void lime_haptic_vibrate (int period, int duration) { + + #ifdef IPHONE + Haptic::Vibrate (period, duration); + #endif + + } + + + HL_PRIM void HL_NAME(hl_haptic_vibrate) (int period, int duration) { + + #ifdef IPHONE + Haptic::Vibrate (period, duration); + #endif + + } + + + value lime_image_encode (value buffer, int type, int quality, value bytes) { + + ImageBuffer imageBuffer = ImageBuffer (buffer); + Bytes data = Bytes (bytes); + + switch (type) { + + case 0: + + #ifdef LIME_PNG + if (PNG::Encode (&imageBuffer, &data)) { + + return data.Value (bytes); + + } + #endif + break; + + case 1: + + #ifdef LIME_JPEG + if (JPEG::Encode (&imageBuffer, &data, quality)) { + + return data.Value (bytes); + + } + #endif + break; + + default: break; + + } + + return alloc_null (); + + } + + + HL_PRIM Bytes* HL_NAME(hl_image_encode) (ImageBuffer* buffer, int type, int quality, Bytes* bytes) { + + switch (type) { + + case 0: + + #ifdef LIME_PNG + if (PNG::Encode (buffer, bytes)) { + + return bytes; + + } + #endif + break; + + case 1: + + #ifdef LIME_JPEG + if (JPEG::Encode (buffer, bytes, quality)) { + + return bytes; + + } + #endif + break; + + default: break; + + } + + return 0; + + } + + + value lime_image_load_bytes (value data, value buffer) { + + Resource resource; + Bytes bytes; + + ImageBuffer imageBuffer = ImageBuffer (buffer); + + bytes.Set (data); + resource = Resource (&bytes); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_image_load_bytes) (Bytes* data, ImageBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_image_load_file (value data, value buffer) { + + Resource resource = Resource (val_string (data)); + ImageBuffer imageBuffer = ImageBuffer (buffer); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_image_load_file) (hl_vstring* data, ImageBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_image_load (value data, value buffer) { + + if (val_is_string (data)) { + + return lime_image_load_file (data, buffer); + + } else { + + return lime_image_load_bytes (data, buffer); + + } + + } + + + void lime_image_data_util_color_transform (value image, value rect, value colorMatrix) { + + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); + ImageDataUtil::ColorTransform (&_image, &_rect, &_colorMatrix); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_color_transform) (Image* image, Rectangle* rect, ArrayBufferView* colorMatrix) { + + ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); + ImageDataUtil::ColorTransform (image, rect, &_colorMatrix); + + } + + + void lime_image_data_util_copy_channel (value image, value sourceImage, value sourceRect, value destPoint, int srcChannel, int destChannel) { + + Image _image = Image (image); + Image _sourceImage = Image (sourceImage); + Rectangle _sourceRect = Rectangle (sourceRect); + Vector2 _destPoint = Vector2 (destPoint); + ImageDataUtil::CopyChannel (&_image, &_sourceImage, &_sourceRect, &_destPoint, srcChannel, destChannel); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_copy_channel) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) { + + ImageDataUtil::CopyChannel (image, sourceImage, sourceRect, destPoint, srcChannel, destChannel); + + } + + + void lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value alphaImage, value alphaPoint, bool mergeAlpha) { + + Image _image = Image (image); + Image _sourceImage = Image (sourceImage); + Rectangle _sourceRect = Rectangle (sourceRect); + Vector2 _destPoint = Vector2 (destPoint); + + if (val_is_null (alphaImage)) { + + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, 0, 0, mergeAlpha); + + } else { + + Image _alphaImage = Image (alphaImage); + Vector2 _alphaPoint = Vector2 (alphaPoint); + + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, &_alphaImage, &_alphaPoint, mergeAlpha); + + } + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_copy_pixels) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, Image* alphaImage, Vector2* alphaPoint, bool mergeAlpha) { + + if (!alphaImage) { + + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, NULL, NULL, mergeAlpha); + + } else { + + if (!alphaPoint) { + + Vector2 _alphaPoint = Vector2 (0, 0); + + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, &_alphaPoint, mergeAlpha); + + } else { + + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha); + + } + + } + + } + + + void lime_image_data_util_fill_rect (value image, value rect, int rg, int ba) { + + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + int32_t color = (rg << 16) | ba; + ImageDataUtil::FillRect (&_image, &_rect, color); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_fill_rect) (Image* image, Rectangle* rect, int rg, int ba) { + + int32_t color = (rg << 16) | ba; + ImageDataUtil::FillRect (image, rect, color); + + } + + + void lime_image_data_util_flood_fill (value image, int x, int y, int rg, int ba) { + + Image _image = Image (image); + int32_t color = (rg << 16) | ba; + ImageDataUtil::FloodFill (&_image, x, y, color); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_flood_fill) (Image* image, int x, int y, int rg, int ba) { + + int32_t color = (rg << 16) | ba; + ImageDataUtil::FloodFill (image, x, y, color); + + } + + + void lime_image_data_util_get_pixels (value image, value rect, int format, value bytes) { + + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + PixelFormat _format = (PixelFormat)format; + Bytes pixels = Bytes (bytes); + ImageDataUtil::GetPixels (&_image, &_rect, _format, &pixels); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_get_pixels) (Image* image, Rectangle* rect, PixelFormat format, Bytes* bytes) { + + ImageDataUtil::GetPixels (image, rect, format, bytes); + + } + + + void lime_image_data_util_merge (value image, value sourceImage, value sourceRect, value destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { + + Image _image = Image (image); + Image _sourceImage = Image (sourceImage); + Rectangle _sourceRect = Rectangle (sourceRect); + Vector2 _destPoint = Vector2 (destPoint); + ImageDataUtil::Merge (&_image, &_sourceImage, &_sourceRect, &_destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_merge) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { + + ImageDataUtil::Merge (image, sourceImage, sourceRect, destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); + + } + + + void lime_image_data_util_multiply_alpha (value image) { + + Image _image = Image (image); + ImageDataUtil::MultiplyAlpha (&_image); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_multiply_alpha) (Image* image) { + + ImageDataUtil::MultiplyAlpha (image); + + } + + + void lime_image_data_util_resize (value image, value buffer, int width, int height) { + + Image _image = Image (image); + ImageBuffer _buffer = ImageBuffer (buffer); + ImageDataUtil::Resize (&_image, &_buffer, width, height); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_resize) (Image* image, ImageBuffer* buffer, int width, int height) { + + ImageDataUtil::Resize (image, buffer, width, height); + + } + + + void lime_image_data_util_set_format (value image, int format) { + + Image _image = Image (image); + PixelFormat _format = (PixelFormat)format; + ImageDataUtil::SetFormat (&_image, _format); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_set_format) (Image* image, PixelFormat format) { + + ImageDataUtil::SetFormat (image, format); + + } + + + void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format, int endian) { + + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + Bytes _bytes (bytes); + PixelFormat _format = (PixelFormat)format; + Endian _endian = (Endian)endian; + ImageDataUtil::SetPixels (&_image, &_rect, &_bytes, offset, _format, _endian); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_set_pixels) (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format, Endian endian) { + + ImageDataUtil::SetPixels (image, rect, bytes, offset, format, endian); + + } + + + int lime_image_data_util_threshold (value image, value sourceImage, value sourceRect, value destPoint, int operation, int thresholdRG, int thresholdBA, int colorRG, int colorBA, int maskRG, int maskBA, bool copySource) { + + Image _image = Image (image); + Image _sourceImage = Image (sourceImage); + Rectangle _sourceRect = Rectangle (sourceRect); + Vector2 _destPoint = Vector2 (destPoint); + int32_t threshold = (thresholdRG << 16) | thresholdBA; + int32_t color = (colorRG << 16) | colorBA; + int32_t mask = (maskRG << 16) | maskBA; + return ImageDataUtil::Threshold (&_image, &_sourceImage, &_sourceRect, &_destPoint, operation, threshold, color, mask, copySource); + + } + + + HL_PRIM int HL_NAME(hl_image_data_util_threshold) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int operation, int thresholdRG, int thresholdBA, int colorRG, int colorBA, int maskRG, int maskBA, bool copySource) { + + int32_t threshold = (thresholdRG << 16) | thresholdBA; + int32_t color = (colorRG << 16) | colorBA; + int32_t mask = (maskRG << 16) | maskBA; + return ImageDataUtil::Threshold (image, sourceImage, sourceRect, destPoint, operation, threshold, color, mask, copySource); + + } + + + void lime_image_data_util_unmultiply_alpha (value image) { + + Image _image = Image (image); + ImageDataUtil::UnmultiplyAlpha (&_image); + + } + + + HL_PRIM void HL_NAME(hl_image_data_util_unmultiply_alpha) (Image* image) { + + ImageDataUtil::UnmultiplyAlpha (image); + + } + + + double lime_jni_getenv () { + + #ifdef ANDROID + return (uintptr_t)JNI::GetEnv (); + #else + return 0; + #endif + + } + + + HL_PRIM double HL_NAME(hl_jni_getenv) () { + + #ifdef ANDROID + return (uintptr_t)JNI::GetEnv (); + #else + return 0; + #endif + + } + + + void lime_joystick_event_manager_register (value callback, value eventObject) { + + JoystickEvent::callback = new ValuePointer (callback); + JoystickEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_joystick_event_manager_register) (vclosure* callback, JoystickEvent* eventObject) { + + JoystickEvent::callback = new ValuePointer (callback); + JoystickEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_joystick_get_device_guid (int id) { + + const char* guid = Joystick::GetDeviceGUID (id); + return guid ? alloc_string (guid) : alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_guid) (int id) { + + return (vbyte*)Joystick::GetDeviceGUID (id); + + } + + + value lime_joystick_get_device_name (int id) { + + const char* name = Joystick::GetDeviceName (id); + return name ? alloc_string (name) : alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_name) (int id) { + + return (vbyte*)Joystick::GetDeviceName (id); + + } + + + int lime_joystick_get_num_axes (int id) { + + return Joystick::GetNumAxes (id); + + } + + + HL_PRIM int HL_NAME(hl_joystick_get_num_axes) (int id) { + + return Joystick::GetNumAxes (id); + + } + + + int lime_joystick_get_num_buttons (int id) { + + return Joystick::GetNumButtons (id); + + } + + + HL_PRIM int HL_NAME(hl_joystick_get_num_buttons) (int id) { + + return Joystick::GetNumButtons (id); + + } + + + int lime_joystick_get_num_hats (int id) { + + return Joystick::GetNumHats (id); + + } + + + HL_PRIM int HL_NAME(hl_joystick_get_num_hats) (int id) { + + return Joystick::GetNumHats (id); + + } + + + value lime_jpeg_decode_bytes (value data, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + + Bytes bytes (data); + Resource resource = Resource (&bytes); + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_jpeg_decode_file (HxString path, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + Resource resource = Resource (hxs_utf8 (path, nullptr)); + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (path); + + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + + + int lime_key_code_from_scan_code (int scanCode) { + + return KeyCode::FromScanCode (scanCode); + + } + + + HL_PRIM int HL_NAME(hl_key_code_from_scan_code) (int scanCode) { + + return KeyCode::FromScanCode (scanCode); + + } + + + int lime_key_code_to_scan_code (int keyCode) { + + return KeyCode::ToScanCode (keyCode); + + } + + + HL_PRIM int HL_NAME(hl_key_code_to_scan_code) (int keyCode) { + + return KeyCode::ToScanCode (keyCode); + + } + + + void lime_key_event_manager_register (value callback, value eventObject) { + + KeyEvent::callback = new ValuePointer (callback); + KeyEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_key_event_manager_register) (vclosure* callback, KeyEvent* eventObject) { + + KeyEvent::callback = new ValuePointer (callback); + KeyEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_locale_get_system_locale () { + + std::string* locale = Locale::GetSystemLocale (); + + if (!locale) { + + return alloc_null (); + + } else { + + value result = alloc_string (locale->c_str ()); + delete locale; + return result; + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_locale_get_system_locale) () { + + std::string* locale = Locale::GetSystemLocale (); + + if (!locale) { + + return 0; + + } else { + + int size = locale->size (); + char* _locale = (char*)malloc (size + 1); + strncpy (_locale, locale->c_str (), size); + _locale[size] = '\0'; + delete locale; + + return (vbyte*)_locale; + + } + + } + + + value lime_lzma_compress (value buffer, value bytes) { + + #ifdef LIME_LZMA + Bytes data (buffer); + Bytes result (bytes); + + LZMA::Compress (&data, &result); + + return result.Value (bytes); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_lzma_compress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_LZMA + LZMA::Compress (buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + value lime_lzma_decompress (value buffer, value bytes) { + + #ifdef LIME_LZMA + Bytes data (buffer); + Bytes result (bytes); + + LZMA::Decompress (&data, &result); + + return result.Value (bytes); + #else + return alloc_null (); + #endif + + } + + + HL_PRIM Bytes* HL_NAME(hl_lzma_decompress) (Bytes* buffer, Bytes* bytes) { + + #ifdef LIME_LZMA + LZMA::Decompress (buffer, bytes); + return bytes; + #else + return 0; + #endif + + } + + + void lime_mouse_event_manager_register (value callback, value eventObject) { + + MouseEvent::callback = new ValuePointer (callback); + MouseEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_mouse_event_manager_register) (vclosure* callback, MouseEvent* eventObject) { + + MouseEvent::callback = new ValuePointer (callback); + MouseEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + void lime_neko_execute (HxString module) { + + #ifdef LIME_NEKO + NekoVM::Execute (module.c_str ()); + #endif + + } + + + void lime_orientation_event_manager_register (value callback, value eventObject) { + + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer (eventObject); + System::EnableDeviceOrientationChange(true); + + } + + + HL_PRIM void HL_NAME(hl_orientation_event_manager_register) (vclosure* callback, OrientationEvent* eventObject) { + + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + value lime_png_decode_bytes (value data, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + Bytes bytes (data); + Resource resource = Resource (&bytes); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_png_decode_file (HxString path, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + Resource resource = Resource (hxs_utf8 (path, nullptr)); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (path); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + + + void lime_render_event_manager_register (value callback, value eventObject) { + + RenderEvent::callback = new ValuePointer (callback); + RenderEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_render_event_manager_register) (vclosure* callback, RenderEvent* eventObject) { + + RenderEvent::callback = new ValuePointer (callback); + RenderEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + void lime_sensor_event_manager_register (value callback, value eventObject) { + + SensorEvent::callback = new ValuePointer (callback); + SensorEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_sensor_event_manager_register) (vclosure* callback, SensorEvent* eventObject) { + + SensorEvent::callback = new ValuePointer (callback); + SensorEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + bool lime_system_get_allow_screen_timeout () { + + return System::GetAllowScreenTimeout (); + + } + + + HL_PRIM bool HL_NAME(hl_system_get_allow_screen_timeout) () { + + return System::GetAllowScreenTimeout (); + + } + + + value lime_system_get_device_model () { + + std::wstring* model = System::GetDeviceModel (); + + if (model) { + + value result = alloc_wstring (model->c_str ()); + delete model; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_device_model) () { + + #ifndef EMSCRIPTEN + + std::wstring* model = System::GetDeviceModel (); + + if (model) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*model); + delete model; + return result; + + } + + #endif + + return 0; + + } + + + value lime_system_get_device_vendor () { + + std::wstring* vendor = System::GetDeviceVendor (); + + if (vendor) { + + value result = alloc_wstring (vendor->c_str ()); + delete vendor; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_device_vendor) () { + + #ifndef EMSCRIPTEN + + std::wstring* vendor = System::GetDeviceVendor (); + + if (vendor) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*vendor); + delete vendor; + return result; + + } + + #endif + + return 0; + + } + + + value lime_system_get_directory (int type, HxString company, HxString title) { + + std::wstring* path = System::GetDirectory ((SystemDirectory)type, hxs_utf8 (company, nullptr), hxs_utf8 (title, nullptr)); + + if (path) { + + value result = alloc_wstring (path->c_str ()); + delete path; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_directory) (int type, hl_vstring* company, hl_vstring* title) { + + #ifndef EMSCRIPTEN + + std::wstring* path = System::GetDirectory ((SystemDirectory)type, company ? (char*)hl_to_utf8 ((const uchar*)company->bytes) : NULL, title ? (char*)hl_to_utf8 ((const uchar*)title->bytes) : NULL); + + if (path) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*path); + delete path; + return result; + + } + + #endif + + return 0; + + } + + + value lime_system_get_display (int id) { + + return (value)System::GetDisplay (true, id); + + } + + + HL_PRIM vdynamic* HL_NAME(hl_system_get_display) (int id) { + + return (vdynamic*)System::GetDisplay (false, id); + + } + + + bool lime_system_get_ios_tablet () { + + #ifdef IPHONE + return System::GetIOSTablet (); + #else + return false; + #endif + + } + + + HL_PRIM bool HL_NAME(hl_system_get_ios_tablet) () { + + #ifdef IPHONE + return System::GetIOSTablet (); + #else + return false; + #endif + + } + + + int lime_system_get_num_displays () { + + return System::GetNumDisplays (); + + } + + + HL_PRIM int HL_NAME(hl_system_get_num_displays) () { + + return System::GetNumDisplays (); + + } + + + int lime_system_get_device_orientation () { + + return System::GetDeviceOrientation(); + + } + + + HL_PRIM int HL_NAME(hl_system_get_device_orientation) () { + + return System::GetDeviceOrientation(); + + } + + + value lime_system_get_platform_label () { + + std::wstring* label = System::GetPlatformLabel (); + + if (label) { + + value result = alloc_wstring (label->c_str ()); + delete label; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_label) () { + + #ifndef EMSCRIPTEN + + std::wstring* label = System::GetPlatformLabel (); + + if (label) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*label); + delete label; + return result; + + } + + #endif + + return 0; + + } + + + value lime_system_get_platform_name () { + + std::wstring* name = System::GetPlatformName (); + + if (name) { + + value result = alloc_wstring (name->c_str ()); + delete name; + return result; + + } else { + + return 0; + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_name) () { + + #ifndef EMSCRIPTEN + + std::wstring* name = System::GetPlatformName (); + + if (name) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*name); + delete name; + return result; + + } + + #endif + + return 0; + + } + + + value lime_system_get_platform_version () { + + std::wstring* version = System::GetPlatformVersion (); + + if (version) { + + value result = alloc_wstring (version->c_str ()); + delete version; + return result; + + } else { + + return alloc_null (); + + } + + } + + + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_version) () { + + #ifndef EMSCRIPTEN + + std::wstring* version = System::GetPlatformVersion (); + + if (version) { + + vbyte* const result = hl_wstring_to_utf8_bytes (*version); + delete version; + return result; + } + + #endif + + return 0; + + } + + + double lime_system_get_timer () { + + return System::GetTimer (); + + } + + + HL_PRIM double HL_NAME(hl_system_get_timer) () { + + return System::GetTimer (); + + } + + + int lime_system_get_windows_console_mode (int handleType) { + + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::GetWindowsConsoleMode (handleType); + #else + return 0; + #endif + + } + + + HL_PRIM int HL_NAME(hl_system_get_windows_console_mode) (int handleType) { + + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::GetWindowsConsoleMode (handleType); + #else + return 0; + #endif + + } + + + void lime_system_open_file (HxString path) { + + #ifdef IPHONE + System::OpenFile (path.c_str ()); + #endif + + } + + + HL_PRIM void HL_NAME(hl_system_open_file) (vbyte* path) { + + #ifdef IPHONE + System::OpenFile ((char*)path); + #endif + + } + + + void lime_system_open_url (HxString url, HxString target) { + + #ifdef IPHONE + System::OpenURL (url.c_str (), target.c_str ()); + #endif + + } + + + HL_PRIM void HL_NAME(hl_system_open_url) (vbyte* url, vbyte* target) { + + #ifdef IPHONE + System::OpenURL ((char*)url, (char*)target); + #endif + + } + + + bool lime_system_set_allow_screen_timeout (bool allow) { + + return System::SetAllowScreenTimeout (allow); + + } + + + HL_PRIM bool HL_NAME(hl_system_set_allow_screen_timeout) (bool allow) { + + return System::SetAllowScreenTimeout (allow); + + } + + + bool lime_system_set_windows_console_mode (int handleType, int mode) { + + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::SetWindowsConsoleMode (handleType, mode); + #else + return false; + #endif + + } + + + HL_PRIM bool HL_NAME(hl_system_set_windows_console_mode) (int handleType, int mode) { + + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::SetWindowsConsoleMode (handleType, mode); + #else + return false; + #endif + + } + + + void lime_text_event_manager_register (value callback, value eventObject) { + + TextEvent::callback = new ValuePointer (callback); + TextEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_text_event_manager_register) (vclosure* callback, TextEvent* eventObject) { + + TextEvent::callback = new ValuePointer (callback); + TextEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + void lime_touch_event_manager_register (value callback, value eventObject) { + + TouchEvent::callback = new ValuePointer (callback); + TouchEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_touch_event_manager_register) (vclosure* callback, TouchEvent* eventObject) { + + TouchEvent::callback = new ValuePointer (callback); + TouchEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + void lime_window_alert (value window, HxString message, HxString title) { + + Window* targetWindow = (Window*)val_data (window); + targetWindow->Alert (hxs_utf8 (message, nullptr), hxs_utf8 (title, nullptr)); + + } + + + HL_PRIM void HL_NAME(hl_window_alert) (HL_CFFIPointer* window, hl_vstring* message, hl_vstring* title) { + + Window* targetWindow = (Window*)window->ptr; + const char *cmessage = message ? hl_to_utf8(message->bytes) : nullptr; + const char *ctitle = title ? hl_to_utf8(title->bytes) : nullptr; + targetWindow->Alert (cmessage, ctitle); + + } + + + void lime_window_close (value window) { + + Window* targetWindow = (Window*)val_data (window); + targetWindow->Close (); + + } + + + HL_PRIM void HL_NAME(hl_window_close) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + targetWindow->Close (); + + } + + + void lime_window_context_flip (value window) { + + ((Window*)val_data (window))->ContextFlip (); + + } + + + HL_PRIM void HL_NAME(hl_window_context_flip) (HL_CFFIPointer* window) { + + ((Window*)window->ptr)->ContextFlip (); + + } + + + value lime_window_context_lock (value window) { + + return (value)((Window*)val_data (window))->ContextLock (true); + + } + + + HL_PRIM vdynamic* HL_NAME(hl_window_context_lock) (HL_CFFIPointer* window) { + + return (vdynamic*)((Window*)window->ptr)->ContextLock (false); + + } + + + void lime_window_context_make_current (value window) { + + ((Window*)val_data (window))->ContextMakeCurrent (); + + } + + + HL_PRIM void HL_NAME(hl_window_context_make_current) (HL_CFFIPointer* window) { + + ((Window*)window->ptr)->ContextMakeCurrent (); + + } + + + void lime_window_context_unlock (value window) { + + ((Window*)val_data (window))->ContextUnlock (); + + } + + + HL_PRIM void HL_NAME(hl_window_context_unlock) (HL_CFFIPointer* window) { + + ((Window*)window->ptr)->ContextUnlock (); + + } + + + value lime_window_create (value application, int width, int height, int flags, HxString title) { + + Window* window = CreateWindow ((Application*)val_data (application), width, height, flags, hxs_utf8 (title, nullptr)); + return CFFIPointer (window, gc_window); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_window_create) (HL_CFFIPointer* application, int width, int height, int flags, hl_vstring* title) { + + Window* window = CreateWindow ((Application*)application->ptr, width, height, flags, (const char*)hl_to_utf8 ((const uchar*)title->bytes)); + return HLCFFIPointer (window, (hl_finalizer)hl_gc_window); + + } + + + void lime_window_event_manager_register (value callback, value eventObject) { + + WindowEvent::callback = new ValuePointer (callback); + WindowEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_window_event_manager_register) (vclosure* callback, WindowEvent* eventObject) { + + WindowEvent::callback = new ValuePointer (callback); + WindowEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + void lime_window_focus (value window) { + + Window* targetWindow = (Window*)val_data (window); + targetWindow->Focus (); + + } + + + HL_PRIM void HL_NAME(hl_window_focus) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + targetWindow->Focus (); + + } + + + double lime_window_get_context (value window) { + + Window* targetWindow = (Window*)val_data (window); + return (uintptr_t)targetWindow->GetContext (); + + } + + + HL_PRIM double HL_NAME(hl_window_get_context) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + return (uintptr_t)targetWindow->GetContext (); + + } + + + value lime_window_get_context_type (value window) { + + Window* targetWindow = (Window*)val_data (window); + const char* type = targetWindow->GetContextType (); + return type ? alloc_string (type) : alloc_null (); + + } + + + HL_PRIM vbyte* HL_NAME(hl_window_get_context_type) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + return (vbyte*)targetWindow->GetContextType (); + + } + + + value lime_window_get_vulkan_instance_extensions (value window) { + + Window* targetWindow = (Window*)val_data (window); + unsigned int count = 0; + + if (!targetWindow->GetVulkanInstanceExtensions (&count, 0) || count == 0) { + + return alloc_array (0); + + } + + std::vector names (count); + if (!targetWindow->GetVulkanInstanceExtensions (&count, names.data ())) { + + return alloc_array (0); + + } + + value result = alloc_array (count); + + for (unsigned int i = 0; i < count; ++i) { + + val_array_set_i (result, i, alloc_string (names[i])); + + } + + return result; + + } + + + HL_PRIM hl_varray* HL_NAME(hl_window_get_vulkan_instance_extensions) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + unsigned int count = 0; + + if (!targetWindow->GetVulkanInstanceExtensions (&count, 0) || count == 0) { + + return hl_alloc_array (&hlt_bytes, 0); + + } + + std::vector names (count); + if (!targetWindow->GetVulkanInstanceExtensions (&count, names.data ())) { + + return hl_alloc_array (&hlt_bytes, 0); + + } + + hl_varray* result = (hl_varray*)hl_alloc_array (&hlt_bytes, count); + vbyte** resultData = hl_aptr (result, vbyte*); + + for (unsigned int i = 0; i < count; ++i) { + + *resultData++ = hl_copy_bytes ((const vbyte*)names[i], (int)std::strlen (names[i]) + 1); + + } + + return result; + + } + + + value lime_window_get_vulkan_drawable_size (value window) { + + Window* targetWindow = (Window*)val_data (window); + int width = 0; + int height = 0; + targetWindow->GetVulkanDrawableSize (&width, &height); + + value result = alloc_empty_object (); + alloc_field (result, val_id ("width"), alloc_int (width)); + alloc_field (result, val_id ("height"), alloc_int (height)); + return result; + + } + + + HL_PRIM vdynamic* HL_NAME(hl_window_get_vulkan_drawable_size) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + int width = 0; + int height = 0; + targetWindow->GetVulkanDrawableSize (&width, &height); + + const int id_width = hl_hash_utf8 ("width"); + const int id_height = hl_hash_utf8 ("height"); + vdynamic* result = (vdynamic*)hl_alloc_dynobj(); + hl_dyn_seti (result, id_width, &hlt_i32, width); + hl_dyn_seti (result, id_height, &hlt_i32, height); + return result; + + } + + + value lime_window_get_vulkan_instance_proc_addr (value window) { + + Window* targetWindow = (Window*)val_data (window); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)targetWindow->GetVulkanInstanceProcAddr ()); + + } + + + HL_PRIM vdynamic* HL_NAME(hl_window_get_vulkan_instance_proc_addr) (HL_CFFIPointer* window) { + + Window* targetWindow = (Window*)window->ptr; + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)targetWindow->GetVulkanInstanceProcAddr ()); + + } + + + value lime_window_create_vulkan_surface (value window, int instanceHigh, int instanceLow) { + + Window* targetWindow = (Window*)val_data (window); + uint64_t surface = targetWindow->CreateVulkanSurface ((uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow)); + + if (!surface) { + + return alloc_null (); + + } + + return CreateVulkanHandleValue (surface); + + } + + + HL_PRIM vdynamic* HL_NAME(hl_window_create_vulkan_surface) (HL_CFFIPointer* window, int instanceHigh, int instanceLow) { + + Window* targetWindow = (Window*)window->ptr; + uint64_t surface = targetWindow->CreateVulkanSurface ((uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow)); + + if (!surface) { + + return 0; + + } + + return HLCreateVulkanHandleValue (surface); + + } + + + value lime_vk_create_instance (value window, HxString applicationName) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = VK_NULL_HANDLE; + + if (!CreateManagedVulkanInstance (targetWindow, applicationName.c_str () ? hxs_utf8 (applicationName, nullptr) : 0, &instance)) { + + return alloc_null (); + + } + + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)instance); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_instance) (HL_CFFIPointer* window, hl_vstring* applicationName) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = VK_NULL_HANDLE; + const char* applicationNameUTF8 = applicationName ? (const char*)hl_to_utf8 ((const uchar*)applicationName->bytes) : 0; + + if (!CreateManagedVulkanInstance (targetWindow, applicationNameUTF8, &instance)) { + + return 0; + + } + + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)instance); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_instance (value window, int instanceHigh, int instanceLow) { + +#ifdef LIME_VULKAN + if (instanceHigh == 0 && instanceLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + PFN_vkDestroyInstance vkDestroyInstance = (PFN_vkDestroyInstance)vkGetInstanceProcAddr (instance, "vkDestroyInstance"); + if (vkDestroyInstance) { + + vkDestroyInstance (instance, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_instance) (HL_CFFIPointer* window, int instanceHigh, int instanceLow) { + +#ifdef LIME_VULKAN + if (instanceHigh == 0 && instanceLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + PFN_vkDestroyInstance vkDestroyInstance = (PFN_vkDestroyInstance)vkGetInstanceProcAddr (instance, "vkDestroyInstance"); + if (vkDestroyInstance) { + + vkDestroyInstance (instance, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + void lime_vk_destroy_surface (value window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + +#ifdef LIME_VULKAN + if (instanceHigh == 0 && instanceLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + if (!surface) return; + + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr (instance, "vkDestroySurfaceKHR"); + if (vkDestroySurfaceKHR) { + + vkDestroySurfaceKHR (instance, surface, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_surface) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + +#ifdef LIME_VULKAN + if (instanceHigh == 0 && instanceLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + if (!surface) return; + + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr (instance, "vkDestroySurfaceKHR"); + if (vkDestroySurfaceKHR) { + + vkDestroySurfaceKHR (instance, surface, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_get_physical_devices (value window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + + if (!targetWindow || !instance) { + + lastVKError = "Missing Vulkan window or instance"; + return alloc_null (); + + } + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return alloc_null (); + + } + + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)vkGetInstanceProcAddr (instance, + "vkEnumeratePhysicalDevices"); + PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr (instance, + "vkGetPhysicalDeviceProperties"); + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = + (PFN_vkGetPhysicalDeviceQueueFamilyProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceQueueFamilyProperties"); + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = + (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfaceSupportKHR"); + + if (!vkEnumeratePhysicalDevices || !vkGetPhysicalDeviceProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { + + lastVKError = "Missing required Vulkan instance functions"; + return alloc_null (); + + } + + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + uint32_t deviceCount = 0; + VkResult result = vkEnumeratePhysicalDevices (instance, &deviceCount, 0); + + if (result != VK_SUCCESS) { + + lastVKError = "vkEnumeratePhysicalDevices failed"; + return alloc_null (); + + } + + value devices = alloc_array (deviceCount); + if (deviceCount == 0) { + + lastVKError.clear (); + return devices; + + } + + std::vector physicalDevices (deviceCount); + result = vkEnumeratePhysicalDevices (instance, &deviceCount, physicalDevices.data ()); + + if (result != VK_SUCCESS) { + + lastVKError = "vkEnumeratePhysicalDevices returned incomplete data"; + return alloc_null (); + + } + + const int id_handle = val_id ("handle"); + const int id_name = val_id ("name"); + const int id_apiVersion = val_id ("apiVersion"); + const int id_driverVersion = val_id ("driverVersion"); + const int id_vendorID = val_id ("vendorID"); + const int id_deviceID = val_id ("deviceID"); + const int id_deviceType = val_id ("deviceType"); + const int id_framebufferColorSampleCounts = val_id ("framebufferColorSampleCounts"); + const int id_framebufferDepthSampleCounts = val_id ("framebufferDepthSampleCounts"); + const int id_framebufferNoAttachmentsSampleCounts = val_id ("framebufferNoAttachmentsSampleCounts"); + const int id_framebufferStencilSampleCounts = val_id ("framebufferStencilSampleCounts"); + const int id_maxPushConstantsSize = val_id ("maxPushConstantsSize"); + const int id_minStorageBufferOffsetAlignment = val_id ("minStorageBufferOffsetAlignment"); + const int id_minUniformBufferOffsetAlignment = val_id ("minUniformBufferOffsetAlignment"); + const int id_nonCoherentAtomSize = val_id ("nonCoherentAtomSize"); + const int id_queueFamilies = val_id ("queueFamilies"); + + const int id_index = val_id ("index"); + const int id_flags = val_id ("flags"); + const int id_queueCount = val_id ("queueCount"); + const int id_timestampValidBits = val_id ("timestampValidBits"); + const int id_supportsGraphics = val_id ("supportsGraphics"); + const int id_supportsCompute = val_id ("supportsCompute"); + const int id_supportsTransfer = val_id ("supportsTransfer"); + const int id_supportsPresent = val_id ("supportsPresent"); + + for (uint32_t i = 0; i < deviceCount; ++i) { + + VkPhysicalDeviceProperties properties; + memset (&properties, 0, sizeof (properties)); + vkGetPhysicalDeviceProperties (physicalDevices[i], &properties); + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, 0); + std::vector queueFamilies (queueFamilyCount); + if (queueFamilyCount > 0) { + + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, queueFamilies.data ()); + + } + + value queueFamilyArray = alloc_array (queueFamilyCount); + + for (uint32_t q = 0; q < queueFamilyCount; ++q) { + + VkBool32 supportsPresent = VK_FALSE; + if (surface && vkGetPhysicalDeviceSurfaceSupportKHR) { + + vkGetPhysicalDeviceSurfaceSupportKHR (physicalDevices[i], q, surface, &supportsPresent); + + } + + value queueFamilyObject = alloc_empty_object (); + alloc_field (queueFamilyObject, id_index, alloc_int (q)); + alloc_field (queueFamilyObject, id_flags, alloc_int (queueFamilies[q].queueFlags)); + alloc_field (queueFamilyObject, id_queueCount, alloc_int (queueFamilies[q].queueCount)); + alloc_field (queueFamilyObject, id_timestampValidBits, alloc_int (queueFamilies[q].timestampValidBits)); + alloc_field (queueFamilyObject, id_supportsGraphics, alloc_bool ((queueFamilies[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)); + alloc_field (queueFamilyObject, id_supportsCompute, alloc_bool ((queueFamilies[q].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0)); + alloc_field (queueFamilyObject, id_supportsTransfer, alloc_bool ((queueFamilies[q].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0)); + alloc_field (queueFamilyObject, id_supportsPresent, alloc_bool (supportsPresent != VK_FALSE)); + val_array_set_i (queueFamilyArray, q, queueFamilyObject); + + } + + value deviceObject = alloc_empty_object (); + alloc_field (deviceObject, id_handle, CreateVulkanHandleValue ((uint64_t)(uintptr_t)physicalDevices[i])); + alloc_field (deviceObject, id_name, alloc_string (properties.deviceName)); + alloc_field (deviceObject, id_apiVersion, alloc_int (properties.apiVersion)); + alloc_field (deviceObject, id_driverVersion, alloc_int (properties.driverVersion)); + alloc_field (deviceObject, id_vendorID, alloc_int (properties.vendorID)); + alloc_field (deviceObject, id_deviceID, alloc_int (properties.deviceID)); + alloc_field (deviceObject, id_deviceType, alloc_int (properties.deviceType)); + alloc_field (deviceObject, id_framebufferColorSampleCounts, alloc_int ((int)properties.limits.framebufferColorSampleCounts)); + alloc_field (deviceObject, id_framebufferDepthSampleCounts, alloc_int ((int)properties.limits.framebufferDepthSampleCounts)); + alloc_field (deviceObject, id_framebufferNoAttachmentsSampleCounts, alloc_int ((int)properties.limits.framebufferNoAttachmentsSampleCounts)); + alloc_field (deviceObject, id_framebufferStencilSampleCounts, alloc_int ((int)properties.limits.framebufferStencilSampleCounts)); + alloc_field (deviceObject, id_maxPushConstantsSize, alloc_int ((int)properties.limits.maxPushConstantsSize)); + alloc_field (deviceObject, id_minStorageBufferOffsetAlignment, + CreateVulkanHandleValue ((uint64_t)properties.limits.minStorageBufferOffsetAlignment)); + alloc_field (deviceObject, id_minUniformBufferOffsetAlignment, + CreateVulkanHandleValue ((uint64_t)properties.limits.minUniformBufferOffsetAlignment)); + alloc_field (deviceObject, id_nonCoherentAtomSize, CreateVulkanHandleValue ((uint64_t)properties.limits.nonCoherentAtomSize)); + alloc_field (deviceObject, id_queueFamilies, queueFamilyArray); + val_array_set_i (devices, i, deviceObject); + + } + + lastVKError.clear (); + return devices; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_array (0); +#endif + + } + + + HL_PRIM hl_varray* HL_NAME(hl_vk_get_physical_devices) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + + if (!targetWindow || !instance) { + + lastVKError = "Missing Vulkan window or instance"; + return 0; + + } + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return 0; + + } + + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)vkGetInstanceProcAddr (instance, + "vkEnumeratePhysicalDevices"); + PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr (instance, + "vkGetPhysicalDeviceProperties"); + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = + (PFN_vkGetPhysicalDeviceQueueFamilyProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceQueueFamilyProperties"); + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = + (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceSurfaceSupportKHR"); + + if (!vkEnumeratePhysicalDevices || !vkGetPhysicalDeviceProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { + + lastVKError = "Missing required Vulkan instance functions"; + return 0; + + } + + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + uint32_t deviceCount = 0; + VkResult result = vkEnumeratePhysicalDevices (instance, &deviceCount, 0); + + if (result != VK_SUCCESS) { + + lastVKError = "vkEnumeratePhysicalDevices failed"; + return 0; + + } + + hl_varray* devices = (hl_varray*)hl_alloc_array (&hlt_dynobj, deviceCount); + if (deviceCount == 0) { + + lastVKError.clear (); + return devices; + + } + + std::vector physicalDevices (deviceCount); + result = vkEnumeratePhysicalDevices (instance, &deviceCount, physicalDevices.data ()); + + if (result != VK_SUCCESS) { + + lastVKError = "vkEnumeratePhysicalDevices returned incomplete data"; + return 0; + + } + + vdynamic** deviceData = hl_aptr (devices, vdynamic*); + + const int id_handle = hl_hash_utf8 ("handle"); + const int id_name = hl_hash_utf8 ("name"); + const int id_apiVersion = hl_hash_utf8 ("apiVersion"); + const int id_driverVersion = hl_hash_utf8 ("driverVersion"); + const int id_vendorID = hl_hash_utf8 ("vendorID"); + const int id_deviceID = hl_hash_utf8 ("deviceID"); + const int id_deviceType = hl_hash_utf8 ("deviceType"); + const int id_framebufferColorSampleCounts = hl_hash_utf8 ("framebufferColorSampleCounts"); + const int id_framebufferDepthSampleCounts = hl_hash_utf8 ("framebufferDepthSampleCounts"); + const int id_framebufferNoAttachmentsSampleCounts = hl_hash_utf8 ("framebufferNoAttachmentsSampleCounts"); + const int id_framebufferStencilSampleCounts = hl_hash_utf8 ("framebufferStencilSampleCounts"); + const int id_maxPushConstantsSize = hl_hash_utf8 ("maxPushConstantsSize"); + const int id_minStorageBufferOffsetAlignment = hl_hash_utf8 ("minStorageBufferOffsetAlignment"); + const int id_minUniformBufferOffsetAlignment = hl_hash_utf8 ("minUniformBufferOffsetAlignment"); + const int id_nonCoherentAtomSize = hl_hash_utf8 ("nonCoherentAtomSize"); + const int id_queueFamilies = hl_hash_utf8 ("queueFamilies"); + + const int id_index = hl_hash_utf8 ("index"); + const int id_flags = hl_hash_utf8 ("flags"); + const int id_queueCount = hl_hash_utf8 ("queueCount"); + const int id_timestampValidBits = hl_hash_utf8 ("timestampValidBits"); + const int id_supportsGraphics = hl_hash_utf8 ("supportsGraphics"); + const int id_supportsCompute = hl_hash_utf8 ("supportsCompute"); + const int id_supportsTransfer = hl_hash_utf8 ("supportsTransfer"); + const int id_supportsPresent = hl_hash_utf8 ("supportsPresent"); + + for (uint32_t i = 0; i < deviceCount; ++i) { + + VkPhysicalDeviceProperties properties; + memset (&properties, 0, sizeof (properties)); + vkGetPhysicalDeviceProperties (physicalDevices[i], &properties); + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, 0); + std::vector queueFamilies (queueFamilyCount); + if (queueFamilyCount > 0) { + + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, queueFamilies.data ()); + + } + + hl_varray* queueFamilyArray = (hl_varray*)hl_alloc_array (&hlt_dynobj, queueFamilyCount); + vdynamic** queueFamilyData = hl_aptr (queueFamilyArray, vdynamic*); + + for (uint32_t q = 0; q < queueFamilyCount; ++q) { + + VkBool32 supportsPresent = VK_FALSE; + if (surface && vkGetPhysicalDeviceSurfaceSupportKHR) { + + vkGetPhysicalDeviceSurfaceSupportKHR (physicalDevices[i], q, surface, &supportsPresent); + + } + + vdynamic* queueFamilyObject = (vdynamic*)hl_alloc_dynobj (); + *queueFamilyData++ = queueFamilyObject; + hl_dyn_seti (queueFamilyObject, id_index, &hlt_i32, q); + hl_dyn_seti (queueFamilyObject, id_flags, &hlt_i32, queueFamilies[q].queueFlags); + hl_dyn_seti (queueFamilyObject, id_queueCount, &hlt_i32, queueFamilies[q].queueCount); + hl_dyn_seti (queueFamilyObject, id_timestampValidBits, &hlt_i32, queueFamilies[q].timestampValidBits); + hl_dyn_seti (queueFamilyObject, id_supportsGraphics, &hlt_bool, (queueFamilies[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0); + hl_dyn_seti (queueFamilyObject, id_supportsCompute, &hlt_bool, (queueFamilies[q].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0); + hl_dyn_seti (queueFamilyObject, id_supportsTransfer, &hlt_bool, (queueFamilies[q].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0); + hl_dyn_seti (queueFamilyObject, id_supportsPresent, &hlt_bool, supportsPresent != VK_FALSE); + + } + + vdynamic* deviceObject = (vdynamic*)hl_alloc_dynobj (); + *deviceData++ = deviceObject; + hl_dyn_setp (deviceObject, id_handle, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)physicalDevices[i])); + hl_dyn_setp (deviceObject, id_name, &hlt_bytes, hl_copy_bytes ((const vbyte*)properties.deviceName, (int)std::strlen (properties.deviceName) + 1)); + hl_dyn_seti (deviceObject, id_apiVersion, &hlt_i32, properties.apiVersion); + hl_dyn_seti (deviceObject, id_driverVersion, &hlt_i32, properties.driverVersion); + hl_dyn_seti (deviceObject, id_vendorID, &hlt_i32, properties.vendorID); + hl_dyn_seti (deviceObject, id_deviceID, &hlt_i32, properties.deviceID); + hl_dyn_seti (deviceObject, id_deviceType, &hlt_i32, properties.deviceType); + hl_dyn_seti (deviceObject, id_framebufferColorSampleCounts, &hlt_i32, properties.limits.framebufferColorSampleCounts); + hl_dyn_seti (deviceObject, id_framebufferDepthSampleCounts, &hlt_i32, properties.limits.framebufferDepthSampleCounts); + hl_dyn_seti (deviceObject, id_framebufferNoAttachmentsSampleCounts, &hlt_i32, properties.limits.framebufferNoAttachmentsSampleCounts); + hl_dyn_seti (deviceObject, id_framebufferStencilSampleCounts, &hlt_i32, properties.limits.framebufferStencilSampleCounts); + hl_dyn_seti (deviceObject, id_maxPushConstantsSize, &hlt_i32, properties.limits.maxPushConstantsSize); + hl_dyn_setp (deviceObject, id_minStorageBufferOffsetAlignment, &hlt_dynobj, + HLCreateVulkanHandleValue ((uint64_t)properties.limits.minStorageBufferOffsetAlignment)); + hl_dyn_setp (deviceObject, id_minUniformBufferOffsetAlignment, &hlt_dynobj, + HLCreateVulkanHandleValue ((uint64_t)properties.limits.minUniformBufferOffsetAlignment)); + hl_dyn_setp (deviceObject, id_nonCoherentAtomSize, &hlt_dynobj, + HLCreateVulkanHandleValue ((uint64_t)properties.limits.nonCoherentAtomSize)); + hl_dyn_setp (deviceObject, id_queueFamilies, &hlt_array, queueFamilyArray); + + } + + lastVKError.clear (); + return devices; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return (hl_varray*)hl_alloc_array (&hlt_dynobj, 0); +#endif + + } + + + value lime_vk_create_device (value window, int instanceHigh, int instanceLow, int physicalDeviceHigh, int physicalDeviceLow, int queueFamilyIndex, + value extensions) { + +#ifdef LIME_VULKAN + LogVulkanNativeBootstrap ("lime_vk_create_device: begin"); + if (val_is_null (window)) { + + lastVKError = "Missing Lime window for Vulkan device creation"; + LogVulkanNativeBootstrap ("lime_vk_create_device: null window"); + return alloc_null (); + + } + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + LogVulkanNativeBootstrap ("lime_vk_create_device: decoded handles"); + std::vector deviceExtensions = GetVulkanDeviceExtensions (extensions); + LogVulkanNativeBootstrap ("lime_vk_create_device: decoded extensions"); + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; + + if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { + + LogVulkanNativeBootstrap ("lime_vk_create_device: CreateManagedVulkanDevice failed"); + return alloc_null (); + + } + + LogVulkanNativeBootstrap ("lime_vk_create_device: create result object"); + value result = alloc_empty_object (); + alloc_field (result, val_id ("handle"), CreateVulkanHandleValue ((uint64_t)(uintptr_t)device)); + alloc_field (result, val_id ("queue"), CreateVulkanHandleValue ((uint64_t)(uintptr_t)queue)); + alloc_field (result, val_id ("queueFamilyIndex"), alloc_int (queueFamilyIndex)); + LogVulkanNativeBootstrap ("lime_vk_create_device: success"); + return result; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_device) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int physicalDeviceHigh, + int physicalDeviceLow, int queueFamilyIndex, hl_varray* extensions) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + std::vector deviceExtensions = GetHLVulkanDeviceExtensions (extensions); + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; + + if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { + + return 0; + + } + + const int id_handle = hl_hash_utf8 ("handle"); + const int id_queue = hl_hash_utf8 ("queue"); + const int id_queueFamilyIndex = hl_hash_utf8 ("queueFamilyIndex"); + vdynamic* result = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_setp (result, id_handle, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)device)); + hl_dyn_setp (result, id_queue, &hlt_dynobj, HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)queue)); + hl_dyn_seti (result, id_queueFamilyIndex, &hlt_i32, queueFamilyIndex); + return result; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_device (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + if (deviceHigh == 0 && deviceLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) return; + + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (device, "vkDestroyDevice"); + if (vkDestroyDevice) { + + ClearManagedVulkanDeviceProcCache (device); + vkDestroyDevice (device, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_device) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + if (deviceHigh == 0 && deviceLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr) return; + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) return; + + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (device, "vkDestroyDevice"); + if (vkDestroyDevice) { + + ClearManagedVulkanDeviceProcCache (device); + vkDestroyDevice (device, 0); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_device_wait_idle (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr || !instance || !device) { + + lastVKError = "Missing Vulkan window, instance, or device"; + return false; + + } + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { + + lastVKError = "Missing Vulkan device proc address function"; + return false; + + } + + PFN_vkDeviceWaitIdle vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)vkGetDeviceProcAddr (device, "vkDeviceWaitIdle"); + if (!vkDeviceWaitIdle) { + + lastVKError = "Missing Vulkan device wait idle function"; + return false; + + } + + VkResult result = vkDeviceWaitIdle (device); + if (result != VK_SUCCESS) { + + lastVKError = "vkDeviceWaitIdle failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_device_wait_idle) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr || !instance || !device) { + + lastVKError = "Missing Vulkan window, instance, or device"; + return false; + + } + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { + + lastVKError = "Missing Vulkan device proc address function"; + return false; + + } + + PFN_vkDeviceWaitIdle vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)vkGetDeviceProcAddr (device, "vkDeviceWaitIdle"); + if (!vkDeviceWaitIdle) { + + lastVKError = "Missing Vulkan device wait idle function"; + return false; + + } + + VkResult result = vkDeviceWaitIdle (device); + if (result != VK_SUCCESS) { + + lastVKError = "vkDeviceWaitIdle failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_queue_wait_idle (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, int queueLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr || !instance || !device || !queue) { + + lastVKError = "Missing Vulkan window, instance, device, or queue"; + return false; + + } + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { + + lastVKError = "Missing Vulkan device proc address function"; + return false; + + } + + PFN_vkQueueWaitIdle vkQueueWaitIdle = (PFN_vkQueueWaitIdle)vkGetDeviceProcAddr (device, "vkQueueWaitIdle"); + if (!vkQueueWaitIdle) { + + lastVKError = "Missing Vulkan queue wait idle function"; + return false; + + } + + VkResult result = vkQueueWaitIdle (queue); + if (result != VK_SUCCESS) { + + lastVKError = "vkQueueWaitIdle failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_queue_wait_idle) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, + int queueLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = targetWindow ? (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr () : 0; + if (!vkGetInstanceProcAddr || !instance || !device || !queue) { + + lastVKError = "Missing Vulkan window, instance, device, or queue"; + return false; + + } + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { + + lastVKError = "Missing Vulkan device proc address function"; + return false; + + } + + PFN_vkQueueWaitIdle vkQueueWaitIdle = (PFN_vkQueueWaitIdle)vkGetDeviceProcAddr (device, "vkQueueWaitIdle"); + if (!vkQueueWaitIdle) { + + lastVKError = "Missing Vulkan queue wait idle function"; + return false; + + } + + VkResult result = vkQueueWaitIdle (queue); + if (result != VK_SUCCESS) { + + lastVKError = "vkQueueWaitIdle failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_create_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueFamilyIndex, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateCommandPool vkCreateCommandPool = (PFN_vkCreateCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateCommandPool"); + if (!vkCreateCommandPool) return alloc_null (); + + VkCommandPoolCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.flags = flags; + createInfo.queueFamilyIndex = queueFamilyIndex; + + VkCommandPool commandPool = VK_NULL_HANDLE; + VkResult result = vkCreateCommandPool (device, &createInfo, 0, &commandPool); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateCommandPool failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)commandPool); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_command_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int queueFamilyIndex, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateCommandPool vkCreateCommandPool = (PFN_vkCreateCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateCommandPool"); + if (!vkCreateCommandPool) return 0; + + VkCommandPoolCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.flags = flags; + createInfo.queueFamilyIndex = queueFamilyIndex; + + VkCommandPool commandPool = VK_NULL_HANDLE; + VkResult result = vkCreateCommandPool (device, &createInfo, 0, &commandPool); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateCommandPool failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)commandPool); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, + int commandPoolLow) { + +#ifdef LIME_VULKAN + if (commandPoolHigh == 0 && commandPoolLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkDestroyCommandPool vkDestroyCommandPool = (PFN_vkDestroyCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyCommandPool"); + if (vkDestroyCommandPool) vkDestroyCommandPool (device, commandPool, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_command_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandPoolHigh, int commandPoolLow) { + +#ifdef LIME_VULKAN + if (commandPoolHigh == 0 && commandPoolLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkDestroyCommandPool vkDestroyCommandPool = (PFN_vkDestroyCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyCommandPool"); + if (vkDestroyCommandPool) vkDestroyCommandPool (device, commandPool, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_reset_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, + int commandPoolLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkResetCommandPool vkResetCommandPool = (PFN_vkResetCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkResetCommandPool"); + if (!vkResetCommandPool) return false; + + VkResult result = vkResetCommandPool (device, commandPool, flags); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetCommandPool failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_reset_command_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandPoolHigh, int commandPoolLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkResetCommandPool vkResetCommandPool = (PFN_vkResetCommandPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkResetCommandPool"); + if (!vkResetCommandPool) return false; + + VkResult result = vkResetCommandPool (device, commandPool, flags); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetCommandPool failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_allocate_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, + int commandPoolLow, int level) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkAllocateCommandBuffers"); + if (!vkAllocateCommandBuffers) return alloc_null (); + + VkCommandBufferAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = commandPool; + allocateInfo.level = (VkCommandBufferLevel)level; + allocateInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer = VK_NULL_HANDLE; + VkResult result = vkAllocateCommandBuffers (device, &allocateInfo, &commandBuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateCommandBuffers failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)commandBuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_allocate_command_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandPoolHigh, int commandPoolLow, int level) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkAllocateCommandBuffers"); + if (!vkAllocateCommandBuffers) return 0; + + VkCommandBufferAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = commandPool; + allocateInfo.level = (VkCommandBufferLevel)level; + allocateInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer = VK_NULL_HANDLE; + VkResult result = vkAllocateCommandBuffers (device, &allocateInfo, &commandBuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateCommandBuffers failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)commandBuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_free_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, + int commandPoolLow, int commandBufferHigh, int commandBufferLow) { + +#ifdef LIME_VULKAN + if (commandBufferHigh == 0 && commandBufferLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkFreeCommandBuffers vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkFreeCommandBuffers"); + if (vkFreeCommandBuffers) vkFreeCommandBuffers (device, commandPool, 1, &commandBuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_free_command_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandPoolHigh, int commandPoolLow, int commandBufferHigh, int commandBufferLow) { + +#ifdef LIME_VULKAN + if (commandBufferHigh == 0 && commandBufferLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandPool commandPool = (VkCommandPool)(uintptr_t)CombineVulkanHandle (commandPoolHigh, commandPoolLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkFreeCommandBuffers vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkFreeCommandBuffers"); + if (vkFreeCommandBuffers) vkFreeCommandBuffers (device, commandPool, 1, &commandBuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_begin_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkBeginCommandBuffer vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBeginCommandBuffer"); + if (!vkBeginCommandBuffer) return false; + + VkCommandBufferBeginInfo beginInfo; + memset (&beginInfo, 0, sizeof (beginInfo)); + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = flags; + + VkResult result = vkBeginCommandBuffer (commandBuffer, &beginInfo); + if (result != VK_SUCCESS) { + + lastVKError = "vkBeginCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_begin_command_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkBeginCommandBuffer vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBeginCommandBuffer"); + if (!vkBeginCommandBuffer) return false; + + VkCommandBufferBeginInfo beginInfo; + memset (&beginInfo, 0, sizeof (beginInfo)); + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = flags; + + VkResult result = vkBeginCommandBuffer (commandBuffer, &beginInfo); + if (result != VK_SUCCESS) { + + lastVKError = "vkBeginCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_end_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkEndCommandBuffer vkEndCommandBuffer = (PFN_vkEndCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkEndCommandBuffer"); + if (!vkEndCommandBuffer) return false; + + VkResult result = vkEndCommandBuffer (commandBuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkEndCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_end_command_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkEndCommandBuffer vkEndCommandBuffer = (PFN_vkEndCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkEndCommandBuffer"); + if (!vkEndCommandBuffer) return false; + + VkResult result = vkEndCommandBuffer (commandBuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkEndCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_reset_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkResetCommandBuffer vkResetCommandBuffer = (PFN_vkResetCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkResetCommandBuffer"); + if (!vkResetCommandBuffer) return false; + + VkResult result = vkResetCommandBuffer (commandBuffer, flags); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_reset_command_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + PFN_vkResetCommandBuffer vkResetCommandBuffer = (PFN_vkResetCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkResetCommandBuffer"); + if (!vkResetCommandBuffer) return false; + + VkResult result = vkResetCommandBuffer (commandBuffer, flags); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetCommandBuffer failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_create_semaphore (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateSemaphore vkCreateSemaphore = (PFN_vkCreateSemaphore)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateSemaphore"); + if (!vkCreateSemaphore) return alloc_null (); + + VkSemaphoreCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkSemaphore semaphore = VK_NULL_HANDLE; + VkResult result = vkCreateSemaphore (device, &createInfo, 0, &semaphore); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateSemaphore failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)semaphore); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_semaphore) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateSemaphore vkCreateSemaphore = (PFN_vkCreateSemaphore)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateSemaphore"); + if (!vkCreateSemaphore) return 0; + + VkSemaphoreCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkSemaphore semaphore = VK_NULL_HANDLE; + VkResult result = vkCreateSemaphore (device, &createInfo, 0, &semaphore); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateSemaphore failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)semaphore); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_semaphore (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int semaphoreHigh, + int semaphoreLow) { + +#ifdef LIME_VULKAN + if (semaphoreHigh == 0 && semaphoreLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSemaphore semaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (semaphoreHigh, semaphoreLow); + PFN_vkDestroySemaphore vkDestroySemaphore = (PFN_vkDestroySemaphore)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroySemaphore"); + if (vkDestroySemaphore) vkDestroySemaphore (device, semaphore, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_semaphore) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int semaphoreHigh, int semaphoreLow) { + +#ifdef LIME_VULKAN + if (semaphoreHigh == 0 && semaphoreLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSemaphore semaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (semaphoreHigh, semaphoreLow); + PFN_vkDestroySemaphore vkDestroySemaphore = (PFN_vkDestroySemaphore)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroySemaphore"); + if (vkDestroySemaphore) vkDestroySemaphore (device, semaphore, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_create_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateFence vkCreateFence = (PFN_vkCreateFence)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateFence"); + if (!vkCreateFence) return alloc_null (); + + VkFenceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + createInfo.flags = flags; + + VkFence fence = VK_NULL_HANDLE; + VkResult result = vkCreateFence (device, &createInfo, 0, &fence); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateFence failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)fence); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateFence vkCreateFence = (PFN_vkCreateFence)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateFence"); + if (!vkCreateFence) return 0; + + VkFenceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + createInfo.flags = flags; + + VkFence fence = VK_NULL_HANDLE; + VkResult result = vkCreateFence (device, &createInfo, 0, &fence); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateFence failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)fence); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow) { + +#ifdef LIME_VULKAN + if (fenceHigh == 0 && fenceLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkDestroyFence vkDestroyFence = (PFN_vkDestroyFence)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyFence"); + if (vkDestroyFence) vkDestroyFence (device, fence, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, + int fenceLow) { + +#ifdef LIME_VULKAN + if (fenceHigh == 0 && fenceLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkDestroyFence vkDestroyFence = (PFN_vkDestroyFence)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyFence"); + if (vkDestroyFence) vkDestroyFence (device, fence, 0); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_wait_for_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow, + int timeoutHigh, int timeoutLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + uint64_t timeout = CombineVulkanHandle (timeoutHigh, timeoutLow); + PFN_vkWaitForFences vkWaitForFences = (PFN_vkWaitForFences)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkWaitForFences"); + if (!vkWaitForFences) return false; + + VkResult result = vkWaitForFences (device, 1, &fence, VK_TRUE, timeout); + if (result != VK_SUCCESS) { + + lastVKError = "vkWaitForFences failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_wait_for_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, + int fenceLow, int timeoutHigh, int timeoutLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + uint64_t timeout = CombineVulkanHandle (timeoutHigh, timeoutLow); + PFN_vkWaitForFences vkWaitForFences = (PFN_vkWaitForFences)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkWaitForFences"); + if (!vkWaitForFences) return false; + + VkResult result = vkWaitForFences (device, 1, &fence, VK_TRUE, timeout); + if (result != VK_SUCCESS) { + + lastVKError = "vkWaitForFences failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_reset_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkResetFences vkResetFences = (PFN_vkResetFences)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkResetFences"); + if (!vkResetFences) return false; + + VkResult result = vkResetFences (device, 1, &fence); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetFences failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_reset_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, + int fenceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkResetFences vkResetFences = (PFN_vkResetFences)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkResetFences"); + if (!vkResetFences) return false; + + VkResult result = vkResetFences (device, 1, &fence); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetFences failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_queue_submit (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, int queueLow, + int commandBufferHigh, int commandBufferLow, int fenceHigh, int fenceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkQueueSubmit vkQueueSubmit = (PFN_vkQueueSubmit)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkQueueSubmit"); + if (!vkQueueSubmit) return false; + + VkSubmitInfo submitInfo; + memset (&submitInfo, 0, sizeof (submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { + + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_queue_submit) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, + int queueLow, int commandBufferHigh, int commandBufferLow, int fenceHigh, int fenceLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + PFN_vkQueueSubmit vkQueueSubmit = (PFN_vkQueueSubmit)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkQueueSubmit"); + if (!vkQueueSubmit) return false; + + VkSubmitInfo submitInfo; + memset (&submitInfo, 0, sizeof (submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { + + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_allocate_memory (value window, int instanceHigh, int instanceLow, int physicalDeviceHigh, int physicalDeviceLow, int deviceHigh, + int deviceLow, int sizeHigh, int sizeLow, int memoryTypeBits, int properties) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + uint64_t size = CombineVulkanHandle (sizeHigh, sizeLow); + uint32_t memoryTypeIndex = 0; + if (!FindManagedVulkanMemoryType (targetWindow, instance, physicalDevice, (uint32_t)memoryTypeBits, (VkMemoryPropertyFlags)properties, + &memoryTypeIndex)) { + + return alloc_null (); + + } + + PFN_vkAllocateMemory vkAllocateMemory = (PFN_vkAllocateMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkAllocateMemory"); + if (!vkAllocateMemory) return alloc_null (); + + VkMemoryAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)size; + allocateInfo.memoryTypeIndex = memoryTypeIndex; + + VkDeviceMemory memory = VK_NULL_HANDLE; + VkResult result = vkAllocateMemory (device, &allocateInfo, 0, &memory); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateMemory failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanMemoryValue (memory, memoryTypeIndex); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_allocate_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int physicalDeviceHigh, + int physicalDeviceLow, int deviceHigh, int deviceLow, int sizeHigh, int sizeLow, int memoryTypeBits, int properties) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + uint64_t size = CombineVulkanHandle (sizeHigh, sizeLow); + uint32_t memoryTypeIndex = 0; + if (!FindManagedVulkanMemoryType (targetWindow, instance, physicalDevice, (uint32_t)memoryTypeBits, (VkMemoryPropertyFlags)properties, + &memoryTypeIndex)) { + + return 0; + + } + + PFN_vkAllocateMemory vkAllocateMemory = (PFN_vkAllocateMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkAllocateMemory"); + if (!vkAllocateMemory) return 0; + + VkMemoryAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)size; + allocateInfo.memoryTypeIndex = memoryTypeIndex; + + VkDeviceMemory memory = VK_NULL_HANDLE; + VkResult result = vkAllocateMemory (device, &allocateInfo, 0, &memory); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateMemory failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanMemoryValue (memory, memoryTypeIndex); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_free_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow) { + +#ifdef LIME_VULKAN + if (memoryHigh == 0 && memoryLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkFreeMemory vkFreeMemory = (PFN_vkFreeMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkFreeMemory"); + if (vkFreeMemory) { + + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + std::unordered_map::iterator mapped = mappedVulkanMemory.find (mapKey); + if (mapped != mappedVulkanMemory.end ()) { + + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (vkUnmapMemory) vkUnmapMemory (device, memory); + mappedVulkanMemory.erase (mapped); + + } + + vkFreeMemory (device, memory, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_free_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow) { + +#ifdef LIME_VULKAN + if (memoryHigh == 0 && memoryLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkFreeMemory vkFreeMemory = (PFN_vkFreeMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkFreeMemory"); + if (vkFreeMemory) { + + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + std::unordered_map::iterator mapped = mappedVulkanMemory.find (mapKey); + if (mapped != mappedVulkanMemory.end ()) { + + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (vkUnmapMemory) vkUnmapMemory (device, memory); + mappedVulkanMemory.erase (mapped); + + } + + vkFreeMemory (device, memory, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_upload_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow, + int offsetHigh, int offsetLow, value bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + Bytes data (bytes); + if (!memory || !data.b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > data.length) { + + lastVKError = "Invalid Vulkan memory upload range"; + return false; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkMapMemory || !vkUnmapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, (VkDeviceSize)offset, (VkDeviceSize)byteLength, 0, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + memcpy (mappedData, data.b + byteOffset, byteLength); + vkUnmapMemory (device, memory); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_upload_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, Bytes* bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + if (!memory || !bytes || !bytes->b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > bytes->length) { + + lastVKError = "Invalid Vulkan memory upload range"; + return false; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkMapMemory || !vkUnmapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, (VkDeviceSize)offset, (VkDeviceSize)byteLength, 0, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + memcpy (mappedData, bytes->b + byteOffset, byteLength); + vkUnmapMemory (device, memory); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_download_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow, + int offsetHigh, int offsetLow, value bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + Bytes data (bytes); + if (!memory || !data.b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > data.length) { + + lastVKError = "Invalid Vulkan memory download range"; + return false; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkMapMemory || !vkUnmapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, (VkDeviceSize)offset, (VkDeviceSize)byteLength, 0, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + memcpy (data.b + byteOffset, mappedData, byteLength); + vkUnmapMemory (device, memory); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_download_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, Bytes* bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + if (!memory || !bytes || !bytes->b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > bytes->length) { + + lastVKError = "Invalid Vulkan memory download range"; + return false; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkMapMemory || !vkUnmapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, (VkDeviceSize)offset, (VkDeviceSize)byteLength, 0, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + memcpy (bytes->b + byteOffset, mappedData, byteLength); + vkUnmapMemory (device, memory); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_map_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow, + int offsetHigh, int offsetLow, int sizeHigh, int sizeLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + VkDeviceSize offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + VkDeviceSize size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + if (!memory) return false; + + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + if (mappedVulkanMemory.find (mapKey) != mappedVulkanMemory.end ()) { + + lastVKError.clear (); + return true; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + if (!vkMapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, offset, size, (VkMemoryMapFlags)flags, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + ManagedVulkanMappedMemory mapped; + mapped.device = device; + mapped.memory = memory; + mapped.offset = offset; + mapped.size = size; + mapped.data = mappedData; + mappedVulkanMemory[mapKey] = mapped; + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_map_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, int sizeHigh, int sizeLow, int flags) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + VkDeviceSize offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + VkDeviceSize size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + if (!memory) return false; + + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + if (mappedVulkanMemory.find (mapKey) != mappedVulkanMemory.end ()) { + + lastVKError.clear (); + return true; + + } + + PFN_vkMapMemory vkMapMemory = (PFN_vkMapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkMapMemory"); + if (!vkMapMemory) return false; + + void* mappedData = 0; + VkResult result = vkMapMemory (device, memory, offset, size, (VkMemoryMapFlags)flags, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + lastVKError = "vkMapMemory failed"; + return false; + + } + + ManagedVulkanMappedMemory mapped; + mapped.device = device; + mapped.memory = memory; + mapped.offset = offset; + mapped.size = size; + mapped.data = mappedData; + mappedVulkanMemory[mapKey] = mapped; + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + void lime_vk_unmap_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + std::unordered_map::iterator mapped = mappedVulkanMemory.find (mapKey); + if (mapped == mappedVulkanMemory.end ()) return; + + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkUnmapMemory) return; + + vkUnmapMemory (device, memory); + mappedVulkanMemory.erase (mapped); + lastVKError.clear (); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_unmap_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t mapKey = GetManagedVulkanMappedMemoryKey (memory); + std::unordered_map::iterator mapped = mappedVulkanMemory.find (mapKey); + if (mapped == mappedVulkanMemory.end ()) return; + + PFN_vkUnmapMemory vkUnmapMemory = (PFN_vkUnmapMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUnmapMemory"); + if (!vkUnmapMemory) return; + + vkUnmapMemory (device, memory); + mappedVulkanMemory.erase (mapped); + lastVKError.clear (); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + bool lime_vk_write_mapped_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, int memoryLow, + int offsetHigh, int offsetLow, value bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + Bytes data (bytes); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + if (!memory || !data.b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > data.length) { + + lastVKError = "Invalid mapped Vulkan memory write range"; + return false; + + } + + std::unordered_map::iterator mapped = mappedVulkanMemory.find (GetManagedVulkanMappedMemoryKey (memory)); + if (mapped == mappedVulkanMemory.end ()) { + + lastVKError = "Vulkan memory is not mapped"; + return false; + + } + + if (offset < mapped->second.offset) { + + lastVKError = "Mapped Vulkan memory write offset is outside the mapped range"; + return false; + + } + + uint64_t relativeOffset = offset - mapped->second.offset; + if (mapped->second.size != VK_WHOLE_SIZE && relativeOffset + (uint64_t)byteLength > (uint64_t)mapped->second.size) { + + lastVKError = "Mapped Vulkan memory write exceeds the mapped range"; + return false; + + } + + memcpy ((unsigned char*)mapped->second.data + relativeOffset, data.b + byteOffset, byteLength); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_write_mapped_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, Bytes* bytes, int byteOffset, int byteLength) { + +#ifdef LIME_VULKAN + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + uint64_t offset = CombineVulkanHandle (offsetHigh, offsetLow); + if (!memory || !bytes || !bytes->b || byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > bytes->length) { + + lastVKError = "Invalid mapped Vulkan memory write range"; + return false; + + } + + std::unordered_map::iterator mapped = mappedVulkanMemory.find (GetManagedVulkanMappedMemoryKey (memory)); + if (mapped == mappedVulkanMemory.end ()) { + + lastVKError = "Vulkan memory is not mapped"; + return false; + + } + + if (offset < mapped->second.offset) { + + lastVKError = "Mapped Vulkan memory write offset is outside the mapped range"; + return false; + + } + + uint64_t relativeOffset = offset - mapped->second.offset; + if (mapped->second.size != VK_WHOLE_SIZE && relativeOffset + (uint64_t)byteLength > (uint64_t)mapped->second.size) { + + lastVKError = "Mapped Vulkan memory write exceeds the mapped range"; + return false; + + } + + memcpy ((unsigned char*)mapped->second.data + relativeOffset, bytes->b + byteOffset, byteLength); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_flush_mapped_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, + int memoryLow, int offsetHigh, int offsetLow, int sizeHigh, int sizeLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges = + (PFN_vkFlushMappedMemoryRanges)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkFlushMappedMemoryRanges"); + if (!vkFlushMappedMemoryRanges || !memory) return false; + + VkMappedMemoryRange range; + memset (&range, 0, sizeof (range)); + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = memory; + range.offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + range.size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + VkResult result = vkFlushMappedMemoryRanges (device, 1, &range); + if (result != VK_SUCCESS) { + + lastVKError = "vkFlushMappedMemoryRanges failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_flush_mapped_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, int sizeHigh, int sizeLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges = + (PFN_vkFlushMappedMemoryRanges)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkFlushMappedMemoryRanges"); + if (!vkFlushMappedMemoryRanges || !memory) return false; + + VkMappedMemoryRange range; + memset (&range, 0, sizeof (range)); + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = memory; + range.offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + range.size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + VkResult result = vkFlushMappedMemoryRanges (device, 1, &range); + if (result != VK_SUCCESS) { + + lastVKError = "vkFlushMappedMemoryRanges failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + bool lime_vk_invalidate_mapped_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int memoryHigh, + int memoryLow, int offsetHigh, int offsetLow, int sizeHigh, int sizeLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges = + (PFN_vkInvalidateMappedMemoryRanges)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkInvalidateMappedMemoryRanges"); + if (!vkInvalidateMappedMemoryRanges || !memory) return false; + + VkMappedMemoryRange range; + memset (&range, 0, sizeof (range)); + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = memory; + range.offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + range.size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + VkResult result = vkInvalidateMappedMemoryRanges (device, 1, &range); + if (result != VK_SUCCESS) { + + lastVKError = "vkInvalidateMappedMemoryRanges failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_invalidate_mapped_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int memoryHigh, int memoryLow, int offsetHigh, int offsetLow, int sizeHigh, int sizeLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges = + (PFN_vkInvalidateMappedMemoryRanges)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkInvalidateMappedMemoryRanges"); + if (!vkInvalidateMappedMemoryRanges || !memory) return false; + + VkMappedMemoryRange range; + memset (&range, 0, sizeof (range)); + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = memory; + range.offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + range.size = NormalizeVulkanRangeSize (CombineVulkanHandle (sizeHigh, sizeLow)); + VkResult result = vkInvalidateMappedMemoryRanges (device, 1, &range); + if (result != VK_SUCCESS) { + + lastVKError = "vkInvalidateMappedMemoryRanges failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_create_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int sizeHigh, int sizeLow, int usage) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateBuffer vkCreateBuffer = (PFN_vkCreateBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateBuffer"); + if (!vkCreateBuffer) return alloc_null (); + + VkBufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = (VkDeviceSize)CombineVulkanHandle (sizeHigh, sizeLow); + createInfo.usage = (VkBufferUsageFlags)usage; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer buffer = VK_NULL_HANDLE; + VkResult result = vkCreateBuffer (device, &createInfo, 0, &buffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateBuffer failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)buffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int sizeHigh, int sizeLow, int usage) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateBuffer vkCreateBuffer = (PFN_vkCreateBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateBuffer"); + if (!vkCreateBuffer) return 0; + + VkBufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = (VkDeviceSize)CombineVulkanHandle (sizeHigh, sizeLow); + createInfo.usage = (VkBufferUsageFlags)usage; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer buffer = VK_NULL_HANDLE; + VkResult result = vkCreateBuffer (device, &createInfo, 0, &buffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateBuffer failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)buffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int bufferHigh, int bufferLow) { + +#ifdef LIME_VULKAN + if (bufferHigh == 0 && bufferLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + PFN_vkDestroyBuffer vkDestroyBuffer = (PFN_vkDestroyBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyBuffer"); + if (vkDestroyBuffer) { + + vkDestroyBuffer (device, buffer, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int bufferHigh, int bufferLow) { + +#ifdef LIME_VULKAN + if (bufferHigh == 0 && bufferLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + PFN_vkDestroyBuffer vkDestroyBuffer = (PFN_vkDestroyBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyBuffer"); + if (vkDestroyBuffer) { + + vkDestroyBuffer (device, buffer, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_get_buffer_memory_requirements (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int bufferHigh, + int bufferLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements = + (PFN_vkGetBufferMemoryRequirements)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetBufferMemoryRequirements"); + if (!vkGetBufferMemoryRequirements || !buffer) return alloc_null (); + + VkMemoryRequirements requirements; + memset (&requirements, 0, sizeof (requirements)); + vkGetBufferMemoryRequirements (device, buffer, &requirements); + lastVKError.clear (); + return CreateVulkanMemoryRequirementsValue (requirements); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_get_buffer_memory_requirements) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, + int deviceHigh, int deviceLow, int bufferHigh, int bufferLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements = + (PFN_vkGetBufferMemoryRequirements)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetBufferMemoryRequirements"); + if (!vkGetBufferMemoryRequirements || !buffer) return 0; + + VkMemoryRequirements requirements; + memset (&requirements, 0, sizeof (requirements)); + vkGetBufferMemoryRequirements (device, buffer, &requirements); + lastVKError.clear (); + return HLCreateVulkanMemoryRequirementsValue (requirements); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + bool lime_vk_bind_buffer_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int bufferHigh, int bufferLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkBindBufferMemory vkBindBufferMemory = (PFN_vkBindBufferMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBindBufferMemory"); + if (!vkBindBufferMemory || !buffer || !memory) return false; + + VkResult result = vkBindBufferMemory (device, buffer, memory, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow)); + if (result != VK_SUCCESS) { + + lastVKError = "vkBindBufferMemory failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_bind_buffer_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int bufferHigh, int bufferLow, int memoryHigh, int memoryLow, int offsetHigh, int offsetLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkBindBufferMemory vkBindBufferMemory = (PFN_vkBindBufferMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBindBufferMemory"); + if (!vkBindBufferMemory || !buffer || !memory) return false; + + VkResult result = vkBindBufferMemory (device, buffer, memory, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow)); + if (result != VK_SUCCESS) { + + lastVKError = "vkBindBufferMemory failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_create_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int width, int height, int depth, + int mipLevels, int arrayLayers, int format, int imageType, int tiling, int usage, int samples) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateImage vkCreateImage = (PFN_vkCreateImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImage"); + if (!vkCreateImage) return alloc_null (); + + VkImageCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.imageType = (VkImageType)imageType; + createInfo.format = (VkFormat)format; + createInfo.extent.width = (uint32_t)width; + createInfo.extent.height = (uint32_t)height; + createInfo.extent.depth = (uint32_t)depth; + createInfo.mipLevels = (uint32_t)mipLevels; + createInfo.arrayLayers = (uint32_t)arrayLayers; + createInfo.samples = (VkSampleCountFlagBits)samples; + createInfo.tiling = (VkImageTiling)tiling; + createInfo.usage = (VkImageUsageFlags)usage; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if ((VkImageViewType)imageType == VK_IMAGE_VIEW_TYPE_CUBE || arrayLayers == 6) { + + createInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + } + + VkImage image = VK_NULL_HANDLE; + VkResult result = vkCreateImage (device, &createInfo, 0, &image); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImage failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)image); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int width, int height, int depth, int mipLevels, int arrayLayers, int format, int imageType, int tiling, int usage, int samples) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateImage vkCreateImage = (PFN_vkCreateImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImage"); + if (!vkCreateImage) return 0; + + VkImageCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.imageType = (VkImageType)imageType; + createInfo.format = (VkFormat)format; + createInfo.extent.width = (uint32_t)width; + createInfo.extent.height = (uint32_t)height; + createInfo.extent.depth = (uint32_t)depth; + createInfo.mipLevels = (uint32_t)mipLevels; + createInfo.arrayLayers = (uint32_t)arrayLayers; + createInfo.samples = (VkSampleCountFlagBits)samples; + createInfo.tiling = (VkImageTiling)tiling; + createInfo.usage = (VkImageUsageFlags)usage; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if ((VkImageViewType)imageType == VK_IMAGE_VIEW_TYPE_CUBE || arrayLayers == 6) { + + createInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + } + + VkImage image = VK_NULL_HANDLE; + VkResult result = vkCreateImage (device, &createInfo, 0, &image); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImage failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)image); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageHigh, int imageLow) { + +#ifdef LIME_VULKAN + if (imageHigh == 0 && imageLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + PFN_vkDestroyImage vkDestroyImage = (PFN_vkDestroyImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyImage"); + if (vkDestroyImage) { + + vkDestroyImage (device, image, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int imageHigh, int imageLow) { + +#ifdef LIME_VULKAN + if (imageHigh == 0 && imageLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + PFN_vkDestroyImage vkDestroyImage = (PFN_vkDestroyImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyImage"); + if (vkDestroyImage) { + + vkDestroyImage (device, image, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_get_image_memory_requirements (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageHigh, + int imageLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements = + (PFN_vkGetImageMemoryRequirements)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetImageMemoryRequirements"); + if (!vkGetImageMemoryRequirements || !image) return alloc_null (); + + VkMemoryRequirements requirements; + memset (&requirements, 0, sizeof (requirements)); + vkGetImageMemoryRequirements (device, image, &requirements); + lastVKError.clear (); + return CreateVulkanMemoryRequirementsValue (requirements); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_get_image_memory_requirements) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int imageHigh, int imageLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements = + (PFN_vkGetImageMemoryRequirements)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetImageMemoryRequirements"); + if (!vkGetImageMemoryRequirements || !image) return 0; + + VkMemoryRequirements requirements; + memset (&requirements, 0, sizeof (requirements)); + vkGetImageMemoryRequirements (device, image, &requirements); + lastVKError.clear (); + return HLCreateVulkanMemoryRequirementsValue (requirements); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + bool lime_vk_bind_image_memory (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageHigh, int imageLow, + int memoryHigh, int memoryLow, int offsetHigh, int offsetLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkBindImageMemory vkBindImageMemory = (PFN_vkBindImageMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBindImageMemory"); + if (!vkBindImageMemory || !image || !memory) return false; + + VkResult result = vkBindImageMemory (device, image, memory, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow)); + if (result != VK_SUCCESS) { + + lastVKError = "vkBindImageMemory failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + HL_PRIM bool HL_NAME(hl_vk_bind_image_memory) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int imageHigh, int imageLow, int memoryHigh, int memoryLow, int offsetHigh, int offsetLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + VkDeviceMemory memory = (VkDeviceMemory)(uintptr_t)CombineVulkanHandle (memoryHigh, memoryLow); + PFN_vkBindImageMemory vkBindImageMemory = (PFN_vkBindImageMemory)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkBindImageMemory"); + if (!vkBindImageMemory || !image || !memory) return false; + + VkResult result = vkBindImageMemory (device, image, memory, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow)); + if (result != VK_SUCCESS) { + + lastVKError = "vkBindImageMemory failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + value lime_vk_create_swapchain (value window, int instanceHigh, int instanceLow, int physicalDeviceHigh, int physicalDeviceLow, int deviceHigh, + int deviceLow, int surfaceHigh, int surfaceLow, int queueFamilyIndex, int width, int height, int presentMode, int oldSwapchainHigh, + int oldSwapchainLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + VkSwapchainKHR oldSwapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (oldSwapchainHigh, oldSwapchainLow); + ManagedVulkanSwapchain swapchain; + + if (!CreateManagedVulkanSwapchain (targetWindow, instance, physicalDevice, device, surface, (uint32_t)queueFamilyIndex, width, height, + (VkPresentModeKHR)presentMode, oldSwapchain, &swapchain)) { + + return alloc_null (); + + } + + return CreateVulkanSwapchainValue (swapchain); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_swapchain) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int physicalDeviceHigh, + int physicalDeviceLow, int deviceHigh, int deviceLow, int surfaceHigh, int surfaceLow, int queueFamilyIndex, int width, int height, + int presentMode, int oldSwapchainHigh, int oldSwapchainLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSurfaceKHR surface = UInt64ToVulkanSurface (CombineVulkanHandle (surfaceHigh, surfaceLow)); + VkSwapchainKHR oldSwapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (oldSwapchainHigh, oldSwapchainLow); + ManagedVulkanSwapchain swapchain; + + if (!CreateManagedVulkanSwapchain (targetWindow, instance, physicalDevice, device, surface, (uint32_t)queueFamilyIndex, width, height, + (VkPresentModeKHR)presentMode, oldSwapchain, &swapchain)) { + + return 0; + + } + + return HLCreateVulkanSwapchainValue (swapchain); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_swapchain (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int swapchainHigh, int swapchainLow) { + +#ifdef LIME_VULKAN + if (swapchainHigh == 0 && swapchainLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroySwapchainKHR"); + if (vkDestroySwapchainKHR) { + + vkDestroySwapchainKHR (device, swapchain, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + HL_PRIM void HL_NAME(hl_vk_destroy_swapchain) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int swapchainHigh, int swapchainLow) { + +#ifdef LIME_VULKAN + if (swapchainHigh == 0 && swapchainLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroySwapchainKHR"); + if (vkDestroySwapchainKHR) { + + vkDestroySwapchainKHR (device, swapchain, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_get_swapchain_images (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int swapchainHigh, + int swapchainLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkGetSwapchainImagesKHR"); + if (!vkGetSwapchainImagesKHR || !swapchain) return alloc_null (); + + uint32_t imageCount = 0; + VkResult result = vkGetSwapchainImagesKHR (device, swapchain, &imageCount, 0); + if (result != VK_SUCCESS) { + + lastVKError = "Failed to query Vulkan swapchain image count"; + return alloc_null (); + + } + + value images = alloc_array (imageCount); + if (imageCount == 0) { + + lastVKError.clear (); + return images; + + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetGlyphIndex (hxs_utf8 (character, nullptr)); - #else - return -1; - #endif + std::vector swapchainImages (imageCount); + result = vkGetSwapchainImagesKHR (device, swapchain, &imageCount, swapchainImages.data ()); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetSwapchainImagesKHR failed"; + return alloc_null (); + + } + + for (uint32_t i = 0; i < imageCount; ++i) { + + val_array_set_i (images, i, CreateVulkanHandleValue ((uint64_t)(uintptr_t)swapchainImages[i])); + + } + + lastVKError.clear (); + return images; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_array (0); +#endif } - HL_PRIM int HL_NAME(hl_font_get_glyph_index) (HL_CFFIPointer* fontHandle, hl_vstring* character) { + HL_PRIM hl_varray* HL_NAME(hl_vk_get_swapchain_images) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int swapchainHigh, int swapchainLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetGlyphIndex (character ? (char*)hl_to_utf8 ((const uchar*)character->bytes) : NULL); - #else - return -1; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkGetSwapchainImagesKHR"); + if (!vkGetSwapchainImagesKHR || !swapchain) return 0; + + uint32_t imageCount = 0; + VkResult result = vkGetSwapchainImagesKHR (device, swapchain, &imageCount, 0); + if (result != VK_SUCCESS) { + + lastVKError = "Failed to query Vulkan swapchain image count"; + return 0; + + } + + hl_varray* images = (hl_varray*)hl_alloc_array (&hlt_dynobj, imageCount); + if (imageCount == 0) { + + lastVKError.clear (); + return images; + + } + + std::vector swapchainImages (imageCount); + result = vkGetSwapchainImagesKHR (device, swapchain, &imageCount, swapchainImages.data ()); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetSwapchainImagesKHR failed"; + return 0; + + } + + vdynamic** imageData = hl_aptr (images, vdynamic*); + for (uint32_t i = 0; i < imageCount; ++i) { + + *imageData++ = HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)swapchainImages[i]); + + } + + lastVKError.clear (); + return images; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return (hl_varray*)hl_alloc_array (&hlt_dynobj, 0); +#endif } - value lime_font_get_glyph_indices (value fontHandle, HxString characters) { + value lime_vk_acquire_next_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int swapchainHigh, + int swapchainLow, int timeoutHigh, int timeoutLow, int semaphoreHigh, int semaphoreLow, int fenceHigh, int fenceLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->GetGlyphIndices (true, hxs_utf8 (characters, nullptr)); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + uint64_t timeout = CombineVulkanHandle (timeoutHigh, timeoutLow); + VkSemaphore semaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (semaphoreHigh, semaphoreLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + if (!semaphore && !fence) { + + lastVKError = "Vulkan image acquisition requires a semaphore or fence"; + return CreateVulkanAcquireValue (VK_ERROR_INITIALIZATION_FAILED, -1); + + } + + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkAcquireNextImageKHR"); + if (!vkAcquireNextImageKHR || !swapchain) return CreateVulkanAcquireValue (VK_ERROR_INITIALIZATION_FAILED, -1); + + uint32_t imageIndex = 0; + VkResult result = vkAcquireNextImageKHR (device, swapchain, timeout, semaphore, fence, &imageIndex); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { + + lastVKError.clear (); + return CreateVulkanAcquireValue (result, (int)imageIndex); + + } + + lastVKError = "vkAcquireNextImageKHR failed"; + return CreateVulkanAcquireValue (result, -1); +#else + lastVKError = "Lime was built without lime-vulkan support"; return alloc_null (); - #endif +#endif } - HL_PRIM hl_varray* HL_NAME(hl_font_get_glyph_indices) (HL_CFFIPointer* fontHandle, hl_vstring* characters) { + HL_PRIM vdynamic* HL_NAME(hl_vk_acquire_next_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int swapchainHigh, int swapchainLow, int timeoutHigh, int timeoutLow, int semaphoreHigh, int semaphoreLow, int fenceHigh, int fenceLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (hl_varray*)font->GetGlyphIndices (false, characters ? (char*)hl_to_utf8 ((const uchar*)characters->bytes) : NULL); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + uint64_t timeout = CombineVulkanHandle (timeoutHigh, timeoutLow); + VkSemaphore semaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (semaphoreHigh, semaphoreLow); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (fenceHigh, fenceLow); + if (!semaphore && !fence) { + + lastVKError = "Vulkan image acquisition requires a semaphore or fence"; + return HLCreateVulkanAcquireValue (VK_ERROR_INITIALIZATION_FAILED, -1); + + } + + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkAcquireNextImageKHR"); + if (!vkAcquireNextImageKHR || !swapchain) return HLCreateVulkanAcquireValue (VK_ERROR_INITIALIZATION_FAILED, -1); + + uint32_t imageIndex = 0; + VkResult result = vkAcquireNextImageKHR (device, swapchain, timeout, semaphore, fence, &imageIndex); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { + + lastVKError.clear (); + return HLCreateVulkanAcquireValue (result, (int)imageIndex); + + } + + lastVKError = "vkAcquireNextImageKHR failed"; + return HLCreateVulkanAcquireValue (result, -1); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; - #endif +#endif } - value lime_font_get_glyph_metrics (value fontHandle, int index) { + int lime_vk_queue_present (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, int queueLow, + int swapchainHigh, int swapchainLow, int imageIndex, int waitSemaphoreHigh, int waitSemaphoreLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->GetGlyphMetrics (true, index); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + VkSemaphore waitSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (waitSemaphoreHigh, waitSemaphoreLow); + PFN_vkQueuePresentKHR vkQueuePresentKHR = (PFN_vkQueuePresentKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkQueuePresentKHR"); + if (!vkQueuePresentKHR || !queue || !swapchain) return VK_ERROR_INITIALIZATION_FAILED; + + VkPresentInfoKHR presentInfo; + memset (&presentInfo, 0, sizeof (presentInfo)); + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = waitSemaphore ? 1 : 0; + presentInfo.pWaitSemaphores = waitSemaphore ? &waitSemaphore : 0; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + uint32_t swapchainImageIndex = (uint32_t)imageIndex; + presentInfo.pImageIndices = &swapchainImageIndex; + + VkResult result = vkQueuePresentKHR (queue, &presentInfo); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { + + lastVKError.clear (); + + } else { + + lastVKError = "vkQueuePresentKHR failed"; + + } + + return (int)result; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return -3; +#endif + + } + + + HL_PRIM int HL_NAME(hl_vk_queue_present) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, + int queueLow, int swapchainHigh, int swapchainLow, int imageIndex, int waitSemaphoreHigh, int waitSemaphoreLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkSwapchainKHR swapchain = (VkSwapchainKHR)(uintptr_t)CombineVulkanHandle (swapchainHigh, swapchainLow); + VkSemaphore waitSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (waitSemaphoreHigh, waitSemaphoreLow); + PFN_vkQueuePresentKHR vkQueuePresentKHR = (PFN_vkQueuePresentKHR)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkQueuePresentKHR"); + if (!vkQueuePresentKHR || !queue || !swapchain) return VK_ERROR_INITIALIZATION_FAILED; + + VkPresentInfoKHR presentInfo; + memset (&presentInfo, 0, sizeof (presentInfo)); + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = waitSemaphore ? 1 : 0; + presentInfo.pWaitSemaphores = waitSemaphore ? &waitSemaphore : 0; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + uint32_t swapchainImageIndex = (uint32_t)imageIndex; + presentInfo.pImageIndices = &swapchainImageIndex; + + VkResult result = vkQueuePresentKHR (queue, &presentInfo); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { + + lastVKError.clear (); + + } else { + + lastVKError = "vkQueuePresentKHR failed"; + + } + + return (int)result; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return -3; +#endif + + } + + + value lime_vk_create_image_view (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageHigh, int imageLow, + int format, int aspectMask, int viewType) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + if (!image || format == VK_FORMAT_UNDEFINED) { + + lastVKError = "Missing Vulkan image or image view format"; + return alloc_null (); + + } + + PFN_vkCreateImageView vkCreateImageView = (PFN_vkCreateImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImageView"); + if (!vkCreateImageView) return alloc_null (); + + VkImageViewCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = image; + createInfo.viewType = (VkImageViewType)viewType; + createInfo.format = (VkFormat)format; + createInfo.subresourceRange.aspectMask = (VkImageAspectFlags)aspectMask; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + VkImageView imageView = VK_NULL_HANDLE; + VkResult result = vkCreateImageView (device, &createInfo, 0, &imageView); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImageView failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)imageView); +#else + lastVKError = "Lime was built without lime-vulkan support"; return alloc_null (); - #endif +#endif } - HL_PRIM vdynamic* HL_NAME(hl_font_get_glyph_metrics) (HL_CFFIPointer* fontHandle, int index) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_image_view) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int imageHigh, int imageLow, int format, int aspectMask, int viewType) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->GetGlyphMetrics (false, index); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + if (!image || format == VK_FORMAT_UNDEFINED) { + + lastVKError = "Missing Vulkan image or image view format"; + return 0; + + } + + PFN_vkCreateImageView vkCreateImageView = (PFN_vkCreateImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImageView"); + if (!vkCreateImageView) return 0; + + VkImageViewCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = image; + createInfo.viewType = (VkImageViewType)viewType; + createInfo.format = (VkFormat)format; + createInfo.subresourceRange.aspectMask = (VkImageAspectFlags)aspectMask; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + VkImageView imageView = VK_NULL_HANDLE; + VkResult result = vkCreateImageView (device, &createInfo, 0, &imageView); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImageView failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)imageView); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; - #endif +#endif } - int lime_font_get_height (value fontHandle) { + void lime_vk_destroy_image_view (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageViewHigh, + int imageViewLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetHeight (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + if (imageViewHigh == 0 && imageViewLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImageView imageView = (VkImageView)(uintptr_t)CombineVulkanHandle (imageViewHigh, imageViewLow); + PFN_vkDestroyImageView vkDestroyImageView = (PFN_vkDestroyImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyImageView"); + if (vkDestroyImageView) { + + vkDestroyImageView (device, imageView, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM int HL_NAME(hl_font_get_height) (HL_CFFIPointer* fontHandle) { + HL_PRIM void HL_NAME(hl_vk_destroy_image_view) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int imageViewHigh, int imageViewLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetHeight (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + if (imageViewHigh == 0 && imageViewLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImageView imageView = (VkImageView)(uintptr_t)CombineVulkanHandle (imageViewHigh, imageViewLow); + PFN_vkDestroyImageView vkDestroyImageView = (PFN_vkDestroyImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyImageView"); + if (vkDestroyImageView) { + + vkDestroyImageView (device, imageView, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - int lime_font_get_num_glyphs (value fontHandle) { + value lime_vk_create_image_view_ex (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageHigh, int imageLow, + int format, int aspectMask, int viewType, int baseMipLevel, int levelCount, int baseArrayLayer, int layerCount) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetNumGlyphs (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + if (!image || format == VK_FORMAT_UNDEFINED) { + + lastVKError = "Missing Vulkan image or image view format"; + return alloc_null (); + + } + + PFN_vkCreateImageView vkCreateImageView = (PFN_vkCreateImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImageView"); + if (!vkCreateImageView) return alloc_null (); + + VkImageViewCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = image; + createInfo.viewType = (VkImageViewType)viewType; + createInfo.format = (VkFormat)format; + createInfo.subresourceRange.aspectMask = (VkImageAspectFlags)aspectMask; + createInfo.subresourceRange.baseMipLevel = (uint32_t)baseMipLevel; + createInfo.subresourceRange.levelCount = (uint32_t)levelCount; + createInfo.subresourceRange.baseArrayLayer = (uint32_t)baseArrayLayer; + createInfo.subresourceRange.layerCount = (uint32_t)layerCount; + + VkImageView imageView = VK_NULL_HANDLE; + VkResult result = vkCreateImageView (device, &createInfo, 0, &imageView); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImageView failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)imageView); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif } - HL_PRIM int HL_NAME(hl_font_get_num_glyphs) (HL_CFFIPointer* fontHandle) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_image_view_ex) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int imageHigh, int imageLow, int format, int aspectMask, int viewType, int baseMipLevel, int levelCount, + int baseArrayLayer, int layerCount) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetNumGlyphs (); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkImage image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + if (!image || format == VK_FORMAT_UNDEFINED) { + + lastVKError = "Missing Vulkan image or image view format"; + return 0; + + } + + PFN_vkCreateImageView vkCreateImageView = (PFN_vkCreateImageView)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateImageView"); + if (!vkCreateImageView) return 0; + + VkImageViewCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = image; + createInfo.viewType = (VkImageViewType)viewType; + createInfo.format = (VkFormat)format; + createInfo.subresourceRange.aspectMask = (VkImageAspectFlags)aspectMask; + createInfo.subresourceRange.baseMipLevel = (uint32_t)baseMipLevel; + createInfo.subresourceRange.levelCount = (uint32_t)levelCount; + createInfo.subresourceRange.baseArrayLayer = (uint32_t)baseArrayLayer; + createInfo.subresourceRange.layerCount = (uint32_t)layerCount; + + VkImageView imageView = VK_NULL_HANDLE; + VkResult result = vkCreateImageView (device, &createInfo, 0, &imageView); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateImageView failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)imageView); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; - #endif +#endif } - int lime_font_get_underline_position (value fontHandle) { + value lime_vk_create_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value state) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnderlinePosition (); - #else +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateRenderPass vkCreateRenderPass = (PFN_vkCreateRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateRenderPass"); + if (!vkCreateRenderPass) return alloc_null (); + std::vector packed = GetVulkanIntVector (state); + if (packed.size () < 16) return alloc_null (); + + int colorFormat = packed[0]; + int depthStencilFormat = packed[1]; + int samples = packed[2]; + int colorLoadOp = packed[3]; + int colorStoreOp = packed[4]; + int colorInitialLayout = packed[5]; + int colorFinalLayout = packed[6]; + int depthInitialLayout = packed[7]; + int depthFinalLayout = packed[8]; + int depthLoadOp = packed[9]; + int depthStoreOp = packed[10]; + int resolveFormat = packed[11]; + int resolveLoadOp = packed[12]; + int resolveStoreOp = packed[13]; + int resolveInitialLayout = packed[14]; + int resolveFinalLayout = packed[15]; + + std::vector attachments; + VkAttachmentDescription colorAttachment; + memset (&colorAttachment, 0, sizeof (colorAttachment)); + colorAttachment.format = (VkFormat)colorFormat; + colorAttachment.samples = (VkSampleCountFlagBits)samples; + colorAttachment.loadOp = (VkAttachmentLoadOp)colorLoadOp; + colorAttachment.storeOp = (VkAttachmentStoreOp)colorStoreOp; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = (VkImageLayout)colorInitialLayout; + colorAttachment.finalLayout = (VkImageLayout)colorFinalLayout; + attachments.push_back (colorAttachment); + + VkAttachmentReference colorReference; + memset (&colorReference, 0, sizeof (colorReference)); + colorReference.attachment = 0; + colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthReference; + memset (&depthReference, 0, sizeof (depthReference)); + bool hasDepth = depthStencilFormat != VK_FORMAT_UNDEFINED; + bool hasResolve = resolveFormat != VK_FORMAT_UNDEFINED; + if (hasDepth) { + + VkAttachmentDescription depthAttachment; + memset (&depthAttachment, 0, sizeof (depthAttachment)); + depthAttachment.format = (VkFormat)depthStencilFormat; + depthAttachment.samples = (VkSampleCountFlagBits)samples; + depthAttachment.loadOp = (VkAttachmentLoadOp)depthLoadOp; + depthAttachment.storeOp = (VkAttachmentStoreOp)depthStoreOp; + depthAttachment.stencilLoadOp = (VkAttachmentLoadOp)depthLoadOp; + depthAttachment.stencilStoreOp = (VkAttachmentStoreOp)depthStoreOp; + depthAttachment.initialLayout = (VkImageLayout)depthInitialLayout; + depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; + attachments.push_back (depthAttachment); + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } + + VkAttachmentReference resolveReference; + memset (&resolveReference, 0, sizeof (resolveReference)); + if (hasResolve) { + + VkAttachmentDescription resolveAttachment; + memset (&resolveAttachment, 0, sizeof (resolveAttachment)); + resolveAttachment.format = (VkFormat)resolveFormat; + resolveAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + resolveAttachment.loadOp = (VkAttachmentLoadOp)resolveLoadOp; + resolveAttachment.storeOp = (VkAttachmentStoreOp)resolveStoreOp; + resolveAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + resolveAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + resolveAttachment.initialLayout = (VkImageLayout)resolveInitialLayout; + resolveAttachment.finalLayout = (VkImageLayout)resolveFinalLayout; + attachments.push_back (resolveAttachment); + resolveReference.attachment = (uint32_t)(attachments.size () - 1); + resolveReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + } + + VkSubpassDescription subpass; + memset (&subpass, 0, sizeof (subpass)); + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + subpass.pResolveAttachments = hasResolve ? &resolveReference : 0; + subpass.pDepthStencilAttachment = hasDepth ? &depthReference : 0; + + VkSubpassDependency dependency; + memset (&dependency, 0, sizeof (dependency)); + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = (uint32_t)attachments.size (); + createInfo.pAttachments = attachments.data (); + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpass; + createInfo.dependencyCount = 1; + createInfo.pDependencies = &dependency; + + VkRenderPass renderPass = VK_NULL_HANDLE; + VkResult result = vkCreateRenderPass (device, &createInfo, 0, &renderPass); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateRenderPass failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)renderPass); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* state) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateRenderPass vkCreateRenderPass = (PFN_vkCreateRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateRenderPass"); + if (!vkCreateRenderPass) return 0; + std::vector packed = GetHLVulkanIntVector (state); + if (packed.size () < 16) return 0; + + int colorFormat = packed[0]; + int depthStencilFormat = packed[1]; + int samples = packed[2]; + int colorLoadOp = packed[3]; + int colorStoreOp = packed[4]; + int colorInitialLayout = packed[5]; + int colorFinalLayout = packed[6]; + int depthInitialLayout = packed[7]; + int depthFinalLayout = packed[8]; + int depthLoadOp = packed[9]; + int depthStoreOp = packed[10]; + int resolveFormat = packed[11]; + int resolveLoadOp = packed[12]; + int resolveStoreOp = packed[13]; + int resolveInitialLayout = packed[14]; + int resolveFinalLayout = packed[15]; + + std::vector attachments; + VkAttachmentDescription colorAttachment; + memset (&colorAttachment, 0, sizeof (colorAttachment)); + colorAttachment.format = (VkFormat)colorFormat; + colorAttachment.samples = (VkSampleCountFlagBits)samples; + colorAttachment.loadOp = (VkAttachmentLoadOp)colorLoadOp; + colorAttachment.storeOp = (VkAttachmentStoreOp)colorStoreOp; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = (VkImageLayout)colorInitialLayout; + colorAttachment.finalLayout = (VkImageLayout)colorFinalLayout; + attachments.push_back (colorAttachment); + + VkAttachmentReference colorReference; + memset (&colorReference, 0, sizeof (colorReference)); + colorReference.attachment = 0; + colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthReference; + memset (&depthReference, 0, sizeof (depthReference)); + bool hasDepth = depthStencilFormat != VK_FORMAT_UNDEFINED; + bool hasResolve = resolveFormat != VK_FORMAT_UNDEFINED; + if (hasDepth) { + + VkAttachmentDescription depthAttachment; + memset (&depthAttachment, 0, sizeof (depthAttachment)); + depthAttachment.format = (VkFormat)depthStencilFormat; + depthAttachment.samples = (VkSampleCountFlagBits)samples; + depthAttachment.loadOp = (VkAttachmentLoadOp)depthLoadOp; + depthAttachment.storeOp = (VkAttachmentStoreOp)depthStoreOp; + depthAttachment.stencilLoadOp = (VkAttachmentLoadOp)depthLoadOp; + depthAttachment.stencilStoreOp = (VkAttachmentStoreOp)depthStoreOp; + depthAttachment.initialLayout = (VkImageLayout)depthInitialLayout; + depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; + attachments.push_back (depthAttachment); + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } + + VkAttachmentReference resolveReference; + memset (&resolveReference, 0, sizeof (resolveReference)); + if (hasResolve) { + + VkAttachmentDescription resolveAttachment; + memset (&resolveAttachment, 0, sizeof (resolveAttachment)); + resolveAttachment.format = (VkFormat)resolveFormat; + resolveAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + resolveAttachment.loadOp = (VkAttachmentLoadOp)resolveLoadOp; + resolveAttachment.storeOp = (VkAttachmentStoreOp)resolveStoreOp; + resolveAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + resolveAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + resolveAttachment.initialLayout = (VkImageLayout)resolveInitialLayout; + resolveAttachment.finalLayout = (VkImageLayout)resolveFinalLayout; + attachments.push_back (resolveAttachment); + resolveReference.attachment = (uint32_t)(attachments.size () - 1); + resolveReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + } + + VkSubpassDescription subpass; + memset (&subpass, 0, sizeof (subpass)); + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + subpass.pResolveAttachments = hasResolve ? &resolveReference : 0; + subpass.pDepthStencilAttachment = hasDepth ? &depthReference : 0; + + VkSubpassDependency dependency; + memset (&dependency, 0, sizeof (dependency)); + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = (uint32_t)attachments.size (); + createInfo.pAttachments = attachments.data (); + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpass; + createInfo.dependencyCount = 1; + createInfo.pDependencies = &dependency; + + VkRenderPass renderPass = VK_NULL_HANDLE; + VkResult result = vkCreateRenderPass (device, &createInfo, 0, &renderPass); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateRenderPass failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)renderPass); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; - #endif +#endif + + } + + value lime_vk_get_last_error () { + + return alloc_string (lastVKError.c_str ()); + + } + + + void lime_vk_destroy_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int renderPassHigh, + int renderPassLow) { + +#ifdef LIME_VULKAN + if (renderPassHigh == 0 && renderPassLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkRenderPass renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + PFN_vkDestroyRenderPass vkDestroyRenderPass = (PFN_vkDestroyRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyRenderPass"); + if (vkDestroyRenderPass) { + + vkDestroyRenderPass (device, renderPass, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM int HL_NAME(hl_font_get_underline_position) (HL_CFFIPointer* fontHandle) { + HL_PRIM void HL_NAME(hl_vk_destroy_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int renderPassHigh, int renderPassLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnderlinePosition (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + if (renderPassHigh == 0 && renderPassLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkRenderPass renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + PFN_vkDestroyRenderPass vkDestroyRenderPass = (PFN_vkDestroyRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyRenderPass"); + if (vkDestroyRenderPass) { + + vkDestroyRenderPass (device, renderPass, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - int lime_font_get_underline_thickness (value fontHandle) { + value lime_vk_create_framebuffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int renderPassHigh, + int renderPassLow, value attachments, int width, int height, int layers) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnderlineThickness (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkRenderPass renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + std::vector packed = GetVulkanIntVector (attachments); + if (packed.empty () || packed.size () < (size_t)(1 + packed[0] * 2)) { - } + lastVKError = "Invalid Vulkan framebuffer attachment list"; + return alloc_null (); + } - HL_PRIM int HL_NAME(hl_font_get_underline_thickness) (HL_CFFIPointer* fontHandle) { + std::vector imageViews; + imageViews.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnderlineThickness (); - #else - return 0; - #endif + imageViews.push_back ((VkImageView)(uintptr_t)CombineVulkanHandle (packed[1 + i * 2], packed[2 + i * 2])); - } + } + PFN_vkCreateFramebuffer vkCreateFramebuffer = (PFN_vkCreateFramebuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateFramebuffer"); + if (!vkCreateFramebuffer || !renderPass) return alloc_null (); + + VkFramebufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + createInfo.renderPass = renderPass; + createInfo.attachmentCount = (uint32_t)imageViews.size (); + createInfo.pAttachments = imageViews.data (); + createInfo.width = (uint32_t)width; + createInfo.height = (uint32_t)height; + createInfo.layers = (uint32_t)layers; + + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkResult result = vkCreateFramebuffer (device, &createInfo, 0, &framebuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateFramebuffer failed"; + return alloc_null (); - int lime_font_get_strikethrough_position (value fontHandle) { + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetStrikethroughPosition (); - #else - return 0; - #endif + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)framebuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif } - HL_PRIM int HL_NAME(hl_font_get_strikethrough_position) (HL_CFFIPointer* fontHandle) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_framebuffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int renderPassHigh, int renderPassLow, hl_varray* attachments, int width, int height, int layers) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetStrikethroughPosition (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkRenderPass renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + std::vector packed = GetHLVulkanIntVector (attachments); + if (packed.empty () || packed.size () < (size_t)(1 + packed[0] * 2)) { - } + lastVKError = "Invalid Vulkan framebuffer attachment list"; + return 0; + } - int lime_font_get_strikethrough_thickness (value fontHandle) { + std::vector imageViews; + imageViews.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetStrikethroughThickness (); - #else - return 0; - #endif + imageViews.push_back ((VkImageView)(uintptr_t)CombineVulkanHandle (packed[1 + i * 2], packed[2 + i * 2])); - } + } + PFN_vkCreateFramebuffer vkCreateFramebuffer = (PFN_vkCreateFramebuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateFramebuffer"); + if (!vkCreateFramebuffer || !renderPass) return 0; + + VkFramebufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + createInfo.renderPass = renderPass; + createInfo.attachmentCount = (uint32_t)imageViews.size (); + createInfo.pAttachments = imageViews.data (); + createInfo.width = (uint32_t)width; + createInfo.height = (uint32_t)height; + createInfo.layers = (uint32_t)layers; + + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkResult result = vkCreateFramebuffer (device, &createInfo, 0, &framebuffer); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateFramebuffer failed"; + return 0; - HL_PRIM int HL_NAME(hl_font_get_strikethrough_thickness) (HL_CFFIPointer* fontHandle) { + } - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetStrikethroughThickness (); - #else + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)framebuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; - #endif +#endif } - int lime_font_get_units_per_em (value fontHandle) { + void lime_vk_destroy_framebuffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int framebufferHigh, + int framebufferLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnitsPerEM (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + if (framebufferHigh == 0 && framebufferLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFramebuffer framebuffer = (VkFramebuffer)(uintptr_t)CombineVulkanHandle (framebufferHigh, framebufferLow); + PFN_vkDestroyFramebuffer vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyFramebuffer"); + if (vkDestroyFramebuffer) { + + vkDestroyFramebuffer (device, framebuffer, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM int HL_NAME(hl_font_get_units_per_em) (HL_CFFIPointer* fontHandle) { + HL_PRIM void HL_NAME(hl_vk_destroy_framebuffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int framebufferHigh, int framebufferLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnitsPerEM (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + if (framebufferHigh == 0 && framebufferLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkFramebuffer framebuffer = (VkFramebuffer)(uintptr_t)CombineVulkanHandle (framebufferHigh, framebufferLow); + PFN_vkDestroyFramebuffer vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyFramebuffer"); + if (vkDestroyFramebuffer) { - } + vkDestroyFramebuffer (device, framebuffer, 0); + lastVKError.clear (); + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - value lime_font_load_bytes (value data) { + } - #ifdef LIME_FREETYPE - Resource resource; - Bytes bytes; - bytes.Set (data); - resource = Resource (&bytes); + value lime_vk_create_shader_module (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bytes, int byteOffset, + int byteLength) { - Font *font = new Font (&resource, 0); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + Bytes data (bytes); + if (!data.b || byteOffset < 0 || byteLength <= 0 || byteOffset + byteLength > data.length || (byteLength % 4) != 0) { - if (font) { + lastVKError = "Invalid Vulkan shader module bytes"; + return alloc_null (); - if (font->face) { + } - return CFFIPointer (font, gc_font); + PFN_vkCreateShaderModule vkCreateShaderModule = (PFN_vkCreateShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateShaderModule"); + if (!vkCreateShaderModule) return alloc_null (); - } else { + VkShaderModuleCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = (size_t)byteLength; + createInfo.pCode = (const uint32_t*)(data.b + byteOffset); - delete font; + VkShaderModule shaderModule = VK_NULL_HANDLE; + VkResult result = vkCreateShaderModule (device, &createInfo, 0, &shaderModule); + if (result != VK_SUCCESS) { - } + lastVKError = "vkCreateShaderModule failed"; + return alloc_null (); } - #endif + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)shaderModule); +#else + lastVKError = "Lime was built without lime-vulkan support"; return alloc_null (); +#endif } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_bytes) (Bytes* data) { - - #ifdef LIME_FREETYPE - Resource resource = Resource (data); + HL_PRIM vdynamic* HL_NAME(hl_vk_create_shader_module) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, Bytes* bytes, int byteOffset, int byteLength) { - Font *font = new Font (&resource, 0); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + if (!bytes || !bytes->b || byteOffset < 0 || byteLength <= 0 || byteOffset + byteLength > bytes->length || (byteLength % 4) != 0) { - if (font) { + lastVKError = "Invalid Vulkan shader module bytes"; + return 0; - if (font->face) { + } - return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + PFN_vkCreateShaderModule vkCreateShaderModule = (PFN_vkCreateShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateShaderModule"); + if (!vkCreateShaderModule) return 0; - } else { + VkShaderModuleCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = (size_t)byteLength; + createInfo.pCode = (const uint32_t*)(bytes->b + byteOffset); - delete font; + VkShaderModule shaderModule = VK_NULL_HANDLE; + VkResult result = vkCreateShaderModule (device, &createInfo, 0, &shaderModule); + if (result != VK_SUCCESS) { - } + lastVKError = "vkCreateShaderModule failed"; + return 0; } - #endif + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)shaderModule); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; +#endif } - value lime_font_load_file (value data) { + void lime_vk_destroy_shader_module (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int shaderModuleHigh, + int shaderModuleLow) { - #ifdef LIME_FREETYPE - Resource resource = Resource (val_string (data)); +#ifdef LIME_VULKAN + if (shaderModuleHigh == 0 && shaderModuleLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkShaderModule shaderModule = (VkShaderModule)(uintptr_t)CombineVulkanHandle (shaderModuleHigh, shaderModuleLow); + PFN_vkDestroyShaderModule vkDestroyShaderModule = (PFN_vkDestroyShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyShaderModule"); + if (vkDestroyShaderModule) { - Font *font = new Font (&resource, 0); + vkDestroyShaderModule (device, shaderModule, 0); + lastVKError.clear (); - if (font) { + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - if (font->face) { + } - return CFFIPointer (font, gc_font); - } else { + HL_PRIM void HL_NAME(hl_vk_destroy_shader_module) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int shaderModuleHigh, int shaderModuleLow) { - delete font; +#ifdef LIME_VULKAN + if (shaderModuleHigh == 0 && shaderModuleLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkShaderModule shaderModule = (VkShaderModule)(uintptr_t)CombineVulkanHandle (shaderModuleHigh, shaderModuleLow); + PFN_vkDestroyShaderModule vkDestroyShaderModule = (PFN_vkDestroyShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyShaderModule"); + if (vkDestroyShaderModule) { - } + vkDestroyShaderModule (device, shaderModule, 0); + lastVKError.clear (); } - #endif - - return alloc_null (); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_file) (hl_vstring* data) { - - #ifdef LIME_FREETYPE - Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + value lime_vk_create_sampler (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int filter, int addressMode, + int mipmapMode, bool anisotropyEnable, double maxAnisotropy, int compareOp, double minLod, double maxLod) { - Font *font = new Font (&resource, 0); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateSampler vkCreateSampler = (PFN_vkCreateSampler)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateSampler"); + if (!vkCreateSampler) return alloc_null (); + + VkSamplerCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + createInfo.magFilter = (VkFilter)filter; + createInfo.minFilter = (VkFilter)filter; + createInfo.mipmapMode = (VkSamplerMipmapMode)mipmapMode; + createInfo.addressModeU = (VkSamplerAddressMode)addressMode; + createInfo.addressModeV = (VkSamplerAddressMode)addressMode; + createInfo.addressModeW = (VkSamplerAddressMode)addressMode; + createInfo.anisotropyEnable = anisotropyEnable ? VK_TRUE : VK_FALSE; + createInfo.maxAnisotropy = (float)maxAnisotropy; + createInfo.compareEnable = compareOp >= 0 ? VK_TRUE : VK_FALSE; + createInfo.compareOp = compareOp >= 0 ? (VkCompareOp)compareOp : VK_COMPARE_OP_ALWAYS; + createInfo.minLod = (float)minLod; + createInfo.maxLod = (float)maxLod; + createInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + + VkSampler sampler = VK_NULL_HANDLE; + VkResult result = vkCreateSampler (device, &createInfo, 0, &sampler); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateSampler failed"; + return alloc_null (); - if (font) { + } - if (font->face) { + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)sampler); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif - return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + } - } else { - delete font; + HL_PRIM vdynamic* HL_NAME(hl_vk_create_sampler) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int filter, int addressMode, int mipmapMode, bool anisotropyEnable, double maxAnisotropy, int compareOp, double minLod, double maxLod) { - } +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreateSampler vkCreateSampler = (PFN_vkCreateSampler)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateSampler"); + if (!vkCreateSampler) return 0; + + VkSamplerCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + createInfo.magFilter = (VkFilter)filter; + createInfo.minFilter = (VkFilter)filter; + createInfo.mipmapMode = (VkSamplerMipmapMode)mipmapMode; + createInfo.addressModeU = (VkSamplerAddressMode)addressMode; + createInfo.addressModeV = (VkSamplerAddressMode)addressMode; + createInfo.addressModeW = (VkSamplerAddressMode)addressMode; + createInfo.anisotropyEnable = anisotropyEnable ? VK_TRUE : VK_FALSE; + createInfo.maxAnisotropy = (float)maxAnisotropy; + createInfo.compareEnable = compareOp >= 0 ? VK_TRUE : VK_FALSE; + createInfo.compareOp = compareOp >= 0 ? (VkCompareOp)compareOp : VK_COMPARE_OP_ALWAYS; + createInfo.minLod = (float)minLod; + createInfo.maxLod = (float)maxLod; + createInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + + VkSampler sampler = VK_NULL_HANDLE; + VkResult result = vkCreateSampler (device, &createInfo, 0, &sampler); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateSampler failed"; + return 0; } - #endif + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)sampler); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; +#endif } - value lime_font_load (value data) { - - if (val_is_string (data)) { - - return lime_font_load_file (data); + void lime_vk_destroy_sampler (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int samplerHigh, int samplerLow) { - } else { +#ifdef LIME_VULKAN + if (samplerHigh == 0 && samplerLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSampler sampler = (VkSampler)(uintptr_t)CombineVulkanHandle (samplerHigh, samplerLow); + PFN_vkDestroySampler vkDestroySampler = (PFN_vkDestroySampler)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroySampler"); + if (vkDestroySampler) { - return lime_font_load_bytes (data); + vkDestroySampler (device, sampler, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - value lime_font_outline_decompose (value fontHandle, int size) { + HL_PRIM void HL_NAME(hl_vk_destroy_sampler) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int samplerHigh, int samplerLow) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->Decompose (true, size); - #else - return alloc_null (); - #endif +#ifdef LIME_VULKAN + if (samplerHigh == 0 && samplerLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkSampler sampler = (VkSampler)(uintptr_t)CombineVulkanHandle (samplerHigh, samplerLow); + PFN_vkDestroySampler vkDestroySampler = (PFN_vkDestroySampler)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroySampler"); + if (vkDestroySampler) { - } + vkDestroySampler (device, sampler, 0); + lastVKError.clear (); + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - value lime_font_outline_decompose_no_hint (value fontHandle, int size) { + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->Decompose (true, size, false); - #else - return alloc_null (); - #endif - } + value lime_vk_create_descriptor_set_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bindings) { +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetVulkanIntVector (bindings); + if (packed.size () < 2 || packed.size () < (size_t)(2 + packed[1] * 4)) return alloc_null (); + + std::vector nativeBindings; + nativeBindings.reserve ((size_t)packed[1]); + for (int i = 0; i < packed[1]; ++i) { + + int base = 2 + i * 4; + VkDescriptorSetLayoutBinding binding; + memset (&binding, 0, sizeof (binding)); + binding.binding = (uint32_t)packed[base]; + binding.descriptorType = (VkDescriptorType)packed[base + 1]; + binding.descriptorCount = (uint32_t)packed[base + 2]; + binding.stageFlags = (VkShaderStageFlags)packed[base + 3]; + nativeBindings.push_back (binding); - HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose) (HL_CFFIPointer* fontHandle, int size) { + } - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->Decompose (false, size); - #else - return 0; - #endif + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout = + (PFN_vkCreateDescriptorSetLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateDescriptorSetLayout"); + if (!vkCreateDescriptorSetLayout) return alloc_null (); - } + VkDescriptorSetLayoutCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.flags = (VkDescriptorSetLayoutCreateFlags)packed[0]; + createInfo.bindingCount = (uint32_t)nativeBindings.size (); + createInfo.pBindings = nativeBindings.empty () ? 0 : nativeBindings.data (); + VkDescriptorSetLayout layout = VK_NULL_HANDLE; + VkResult result = vkCreateDescriptorSetLayout (device, &createInfo, 0, &layout); + if (result != VK_SUCCESS) { - HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose_no_hint) (HL_CFFIPointer* fontHandle, int size) { + lastVKError = "vkCreateDescriptorSetLayout failed"; + return alloc_null (); - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->Decompose (false, size, false); - #else - return 0; - #endif + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif } - value lime_font_render_glyph (value fontHandle, int index, value data) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_descriptor_set_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* bindings) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetHLVulkanIntVector (bindings); + if (packed.size () < 2 || packed.size () < (size_t)(2 + packed[1] * 4)) return 0; + + std::vector nativeBindings; + nativeBindings.reserve ((size_t)packed[1]); + for (int i = 0; i < packed[1]; ++i) { + + int base = 2 + i * 4; + VkDescriptorSetLayoutBinding binding; + memset (&binding, 0, sizeof (binding)); + binding.binding = (uint32_t)packed[base]; + binding.descriptorType = (VkDescriptorType)packed[base + 1]; + binding.descriptorCount = (uint32_t)packed[base + 2]; + binding.stageFlags = (VkShaderStageFlags)packed[base + 3]; + nativeBindings.push_back (binding); - if (font->RenderGlyph (index, &bytes)) { + } - return bytes.Value (data); + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout = + (PFN_vkCreateDescriptorSetLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateDescriptorSetLayout"); + if (!vkCreateDescriptorSetLayout) return 0; + + VkDescriptorSetLayoutCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.flags = (VkDescriptorSetLayoutCreateFlags)packed[0]; + createInfo.bindingCount = (uint32_t)nativeBindings.size (); + createInfo.pBindings = nativeBindings.empty () ? 0 : nativeBindings.data (); + + VkDescriptorSetLayout layout = VK_NULL_HANDLE; + VkResult result = vkCreateDescriptorSetLayout (device, &createInfo, 0, &layout); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateDescriptorSetLayout failed"; + return 0; } - #endif - return alloc_null (); + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif } - value lime_font_render_glyph_with_flags (value fontHandle, int index, int loadFlags, value data) { - - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); + void lime_vk_destroy_descriptor_set_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { - if (font->RenderGlyphWithFlags (index, loadFlags, &bytes)) { +#ifdef LIME_VULKAN + if (layoutHigh == 0 && layoutLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSetLayout layout = (VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout = + (PFN_vkDestroyDescriptorSetLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyDescriptorSetLayout"); + if (vkDestroyDescriptorSetLayout) { - return bytes.Value (data); + vkDestroyDescriptorSetLayout (device, layout, 0); + lastVKError.clear (); } - #endif - - return alloc_null (); +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyph) (HL_CFFIPointer* fontHandle, int index, Bytes* data) { - - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; + HL_PRIM void HL_NAME(hl_vk_destroy_descriptor_set_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int layoutHigh, int layoutLow) { - if (font->RenderGlyph (index, data)) { +#ifdef LIME_VULKAN + if (layoutHigh == 0 && layoutLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSetLayout layout = (VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout = + (PFN_vkDestroyDescriptorSetLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyDescriptorSetLayout"); + if (vkDestroyDescriptorSetLayout) { - return data; + vkDestroyDescriptorSetLayout (device, layout, 0); + lastVKError.clear (); } - #endif - - return NULL; +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyph_with_flags) (HL_CFFIPointer* fontHandle, int index, int loadFlags, Bytes* data) { + value lime_vk_create_descriptor_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value poolSizes) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetVulkanIntVector (poolSizes); + if (packed.size () < 3 || packed.size () < (size_t)(3 + packed[2] * 2)) return alloc_null (); - if (font->RenderGlyphWithFlags (index, loadFlags, data)) { + std::vector nativeSizes; + nativeSizes.reserve ((size_t)packed[2]); + for (int i = 0; i < packed[2]; ++i) { - return data; + int base = 3 + i * 2; + VkDescriptorPoolSize size; + size.type = (VkDescriptorType)packed[base]; + size.descriptorCount = (uint32_t)packed[base + 1]; + nativeSizes.push_back (size); } - #endif - - return NULL; - - } + PFN_vkCreateDescriptorPool vkCreateDescriptorPool = + (PFN_vkCreateDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateDescriptorPool"); + if (!vkCreateDescriptorPool) return alloc_null (); - value lime_font_render_glyphs (value fontHandle, value indices, value data) { - - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); + VkDescriptorPoolCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + createInfo.flags = (VkDescriptorPoolCreateFlags)packed[0]; + createInfo.maxSets = (uint32_t)packed[1]; + createInfo.poolSizeCount = (uint32_t)nativeSizes.size (); + createInfo.pPoolSizes = nativeSizes.empty () ? 0 : nativeSizes.data (); - if (font->RenderGlyphs (indices, &bytes)) { + VkDescriptorPool pool = VK_NULL_HANDLE; + VkResult result = vkCreateDescriptorPool (device, &createInfo, 0, &pool); + if (result != VK_SUCCESS) { - return bytes.Value (data); + lastVKError = "vkCreateDescriptorPool failed"; + return alloc_null (); } - #endif + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)pool); +#else + lastVKError = "Lime was built without lime-vulkan support"; return alloc_null (); +#endif } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyphs) (HL_CFFIPointer* fontHandle, hl_varray* indices, Bytes* data) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_descriptor_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* poolSizes) { - // #ifdef LIME_FREETYPE - // Font *font = (Font*)fontHandle->ptr; - // return font->RenderGlyphs (indices, &bytes); - // #else - return NULL; - // #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetHLVulkanIntVector (poolSizes); + if (packed.size () < 3 || packed.size () < (size_t)(3 + packed[2] * 2)) return 0; - } + std::vector nativeSizes; + nativeSizes.reserve ((size_t)packed[2]); + for (int i = 0; i < packed[2]; ++i) { + int base = 3 + i * 2; + VkDescriptorPoolSize size; + size.type = (VkDescriptorType)packed[base]; + size.descriptorCount = (uint32_t)packed[base + 1]; + nativeSizes.push_back (size); - void lime_font_set_size (value fontHandle, int fontSize, int dpi) { + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - font->SetSize (fontSize, dpi); - #endif + PFN_vkCreateDescriptorPool vkCreateDescriptorPool = + (PFN_vkCreateDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateDescriptorPool"); + if (!vkCreateDescriptorPool) return 0; - } + VkDescriptorPoolCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + createInfo.flags = (VkDescriptorPoolCreateFlags)packed[0]; + createInfo.maxSets = (uint32_t)packed[1]; + createInfo.poolSizeCount = (uint32_t)nativeSizes.size (); + createInfo.pPoolSizes = nativeSizes.empty () ? 0 : nativeSizes.data (); + VkDescriptorPool pool = VK_NULL_HANDLE; + VkResult result = vkCreateDescriptorPool (device, &createInfo, 0, &pool); + if (result != VK_SUCCESS) { - HL_PRIM void HL_NAME(hl_font_set_size) (HL_CFFIPointer* fontHandle, int fontSize, int dpi) { + lastVKError = "vkCreateDescriptorPool failed"; + return 0; - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - font->SetSize (fontSize, dpi); - #endif + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)pool); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif } + HL_PRIM vbyte* HL_NAME(hl_vk_get_last_error) () { - void lime_gamepad_add_mappings (value mappings) { + return hl_copy_bytes ((const vbyte*)lastVKError.c_str (), (int)lastVKError.size () + 1); - int length = val_array_size (mappings); + } - for (int i = 0; i < length; i++) { - Gamepad::AddMapping (val_string (val_array_i (mappings, i))); + void lime_vk_destroy_descriptor_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, int poolLow) { + +#ifdef LIME_VULKAN + if (poolHigh == 0 && poolLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool = + (PFN_vkDestroyDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyDescriptorPool"); + if (vkDestroyDescriptorPool) { + + vkDestroyDescriptorPool (device, pool, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - HL_PRIM void HL_NAME(hl_gamepad_add_mappings) (hl_varray* mappings) { - - int length = mappings->size; - hl_vstring** mappingsData = hl_aptr (mappings, hl_vstring*); + HL_PRIM void HL_NAME(hl_vk_destroy_descriptor_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int poolHigh, int poolLow) { - for (int i = 0; i < length; i++) { +#ifdef LIME_VULKAN + if (poolHigh == 0 && poolLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool = + (PFN_vkDestroyDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyDescriptorPool"); + if (vkDestroyDescriptorPool) { - Gamepad::AddMapping (hl_to_utf8 ((const uchar*)((*mappingsData++)->bytes))); + vkDestroyDescriptorPool (device, pool, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - void lime_gamepad_event_manager_register (value callback, value eventObject) { + bool lime_vk_reset_descriptor_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, int poolLow, + int flags) { - GamepadEvent::callback = new ValuePointer (callback); - GamepadEvent::eventObject = new ValuePointer (eventObject); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + PFN_vkResetDescriptorPool vkResetDescriptorPool = + (PFN_vkResetDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkResetDescriptorPool"); + if (!vkResetDescriptorPool || !pool) return false; - } + VkResult result = vkResetDescriptorPool (device, pool, (VkDescriptorPoolResetFlags)flags); + if (result != VK_SUCCESS) { + lastVKError = "vkResetDescriptorPool failed"; + return false; - HL_PRIM void HL_NAME(hl_gamepad_event_manager_register) (vclosure* callback, GamepadEvent* eventObject) { + } - GamepadEvent::callback = new ValuePointer (callback); - GamepadEvent::eventObject = new ValuePointer ((vobj*)eventObject); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_gamepad_get_device_guid (int id) { - - const char* guid = Gamepad::GetDeviceGUID (id); - - if (guid) { + HL_PRIM bool HL_NAME(hl_vk_reset_descriptor_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int poolHigh, int poolLow, int flags) { - value result = alloc_string (guid); - delete guid; - return result; +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + PFN_vkResetDescriptorPool vkResetDescriptorPool = + (PFN_vkResetDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkResetDescriptorPool"); + if (!vkResetDescriptorPool || !pool) return false; - } else { + VkResult result = vkResetDescriptorPool (device, pool, (VkDescriptorPoolResetFlags)flags); + if (result != VK_SUCCESS) { - return alloc_null (); + lastVKError = "vkResetDescriptorPool failed"; + return false; } + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + } - HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_guid) (int id) { + value lime_vk_allocate_descriptor_set (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, + int poolLow, int layoutHigh, int layoutLow) { - const char* guid = Gamepad::GetDeviceGUID (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + VkDescriptorSetLayout layout = (VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets = + (PFN_vkAllocateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkAllocateDescriptorSets"); + if (!vkAllocateDescriptorSets || !pool || !layout) return alloc_null (); + + VkDescriptorSetAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = pool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &layout; + + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + VkResult result = vkAllocateDescriptorSets (device, &allocateInfo, &descriptorSet); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateDescriptorSets failed"; + return alloc_null (); - if (guid) { + } - return (vbyte*)guid; + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)descriptorSet); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif - } else { + } + + HL_PRIM vdynamic* HL_NAME(hl_vk_allocate_descriptor_set) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int poolHigh, int poolLow, int layoutHigh, int layoutLow) { + +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorPool pool = (VkDescriptorPool)(uintptr_t)CombineVulkanHandle (poolHigh, poolLow); + VkDescriptorSetLayout layout = (VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets = + (PFN_vkAllocateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkAllocateDescriptorSets"); + if (!vkAllocateDescriptorSets || !pool || !layout) return 0; + + VkDescriptorSetAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = pool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &layout; + + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + VkResult result = vkAllocateDescriptorSets (device, &allocateInfo, &descriptorSet); + if (result != VK_SUCCESS) { + + lastVKError = "vkAllocateDescriptorSets failed"; return 0; } + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)descriptorSet); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + } - value lime_gamepad_get_device_name (int id) { + bool lime_vk_update_descriptor_set_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int setHigh, + int setLow, int binding, int descriptorType, int imageViewHigh, int imageViewLow, int samplerHigh, int samplerLow, int imageLayout) { - const char* name = Gamepad::GetDeviceName (id); - return name ? alloc_string (name) : alloc_null (); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = + (PFN_vkUpdateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUpdateDescriptorSets"); + if (!vkUpdateDescriptorSets || !descriptorSet) return false; + + VkDescriptorImageInfo imageInfo; + memset (&imageInfo, 0, sizeof (imageInfo)); + imageInfo.sampler = (VkSampler)(uintptr_t)CombineVulkanHandle (samplerHigh, samplerLow); + imageInfo.imageView = (VkImageView)(uintptr_t)CombineVulkanHandle (imageViewHigh, imageViewLow); + imageInfo.imageLayout = (VkImageLayout)imageLayout; + + VkWriteDescriptorSet write; + memset (&write, 0, sizeof (write)); + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = descriptorSet; + write.dstBinding = (uint32_t)binding; + write.descriptorCount = 1; + write.descriptorType = (VkDescriptorType)descriptorType; + write.pImageInfo = &imageInfo; + vkUpdateDescriptorSets (device, 1, &write, 0, 0); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_name) (int id) { + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_set_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int setHigh, int setLow, int binding, int descriptorType, int imageViewHigh, int imageViewLow, int samplerHigh, + int samplerLow, int imageLayout) { - return (vbyte*)Gamepad::GetDeviceName (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = + (PFN_vkUpdateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUpdateDescriptorSets"); + if (!vkUpdateDescriptorSets || !descriptorSet) return false; + + VkDescriptorImageInfo imageInfo; + memset (&imageInfo, 0, sizeof (imageInfo)); + imageInfo.sampler = (VkSampler)(uintptr_t)CombineVulkanHandle (samplerHigh, samplerLow); + imageInfo.imageView = (VkImageView)(uintptr_t)CombineVulkanHandle (imageViewHigh, imageViewLow); + imageInfo.imageLayout = (VkImageLayout)imageLayout; + + VkWriteDescriptorSet write; + memset (&write, 0, sizeof (write)); + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = descriptorSet; + write.dstBinding = (uint32_t)binding; + write.descriptorCount = 1; + write.descriptorType = (VkDescriptorType)descriptorType; + write.pImageInfo = &imageInfo; + vkUpdateDescriptorSets (device, 1, &write, 0, 0); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } +#ifdef LIME_VULKAN + value lime_vulkan_renderer_create (value window, HxString applicationName) { - void lime_gamepad_rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { - - Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + Window* targetWindow = (Window*)val_data (window); + VulkanRenderer* renderer = new VulkanRenderer (targetWindow); - } + if (!renderer->Create (applicationName.c_str () ? hxs_utf8 (applicationName, nullptr) : 0)) { + lastVulkanRendererError = renderer->GetLastError (); + delete renderer; + return alloc_null (); - HL_PRIM void HL_NAME(hl_gamepad_rumble) (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { + } - Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + lastVulkanRendererError.clear (); + return CFFIPointer (renderer); } - value lime_gzip_compress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Compress (GZIP, &data, &result); + bool lime_vk_update_descriptor_set_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int setHigh, + int setLow, int binding, int descriptorType, int bufferHigh, int bufferLow, int offset, int range) { - return result.Value (bytes); - #else - return alloc_null (); - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = + (PFN_vkUpdateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUpdateDescriptorSets"); + if (!vkUpdateDescriptorSets || !descriptorSet) return false; + + VkDescriptorBufferInfo bufferInfo; + memset (&bufferInfo, 0, sizeof (bufferInfo)); + bufferInfo.buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + bufferInfo.offset = (VkDeviceSize)(uint32_t)offset; + bufferInfo.range = range > 0 ? (VkDeviceSize)(uint32_t)range : VK_WHOLE_SIZE; + + VkWriteDescriptorSet write; + memset (&write, 0, sizeof (write)); + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = descriptorSet; + write.dstBinding = (uint32_t)binding; + write.descriptorCount = 1; + write.descriptorType = (VkDescriptorType)descriptorType; + write.pBufferInfo = &bufferInfo; + vkUpdateDescriptorSets (device, 1, &write, 0, 0); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM Bytes* HL_NAME(hl_gzip_compress) (Bytes* buffer, Bytes* bytes) { + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_set_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int setHigh, int setLow, int binding, int descriptorType, int bufferHigh, int bufferLow, int offset, int range) { - #ifdef LIME_ZLIB - Zlib::Compress (GZIP, buffer, bytes); - return bytes; - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = + (PFN_vkUpdateDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkUpdateDescriptorSets"); + if (!vkUpdateDescriptorSets || !descriptorSet) return false; + + VkDescriptorBufferInfo bufferInfo; + memset (&bufferInfo, 0, sizeof (bufferInfo)); + bufferInfo.buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + bufferInfo.offset = (VkDeviceSize)(uint32_t)offset; + bufferInfo.range = range > 0 ? (VkDeviceSize)(uint32_t)range : VK_WHOLE_SIZE; + + VkWriteDescriptorSet write; + memset (&write, 0, sizeof (write)); + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = descriptorSet; + write.dstBinding = (uint32_t)binding; + write.descriptorCount = 1; + write.descriptorType = (VkDescriptorType)descriptorType; + write.pBufferInfo = &bufferInfo; + vkUpdateDescriptorSets (device, 1, &write, 0, 0); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_gzip_decompress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Decompress (GZIP, &data, &result); + bool lime_vk_update_descriptor_sets (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value writes) { - return result.Value (bytes); - #else - return alloc_null (); - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + return UpdateManagedVulkanDescriptorSets (targetWindow, instance, device, GetVulkanIntVector (writes)); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM Bytes* HL_NAME(hl_gzip_decompress) (Bytes* buffer, Bytes* bytes) { + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_sets) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* writes) { - #ifdef LIME_ZLIB - Zlib::Decompress (GZIP, buffer, bytes); - return bytes; - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + return UpdateManagedVulkanDescriptorSets (targetWindow, instance, device, GetHLVulkanIntVector (writes)); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_haptic_vibrate (int period, int duration) { + value lime_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, + int pushConstantStages, int pushConstantSize) { - #ifdef IPHONE - Haptic::Vibrate (period, duration); - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetVulkanIntVector (setLayouts); + if (packed.empty () || packed.size () < (size_t)(1 + packed[0] * 2)) return alloc_null (); - } + std::vector layouts; + layouts.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { + layouts.push_back ((VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (packed[1 + i * 2], packed[2 + i * 2])); - HL_PRIM void HL_NAME(hl_haptic_vibrate) (int period, int duration) { + } - #ifdef IPHONE - Haptic::Vibrate (period, duration); - #endif + VkPushConstantRange pushRange; + memset (&pushRange, 0, sizeof (pushRange)); + pushRange.stageFlags = (VkShaderStageFlags)pushConstantStages; + pushRange.offset = 0; + pushRange.size = (uint32_t)pushConstantSize; + + PFN_vkCreatePipelineLayout vkCreatePipelineLayout = + (PFN_vkCreatePipelineLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineLayout"); + if (!vkCreatePipelineLayout) return alloc_null (); + + VkPipelineLayoutCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + createInfo.setLayoutCount = (uint32_t)layouts.size (); + createInfo.pSetLayouts = layouts.empty () ? 0 : layouts.data (); + createInfo.pushConstantRangeCount = pushConstantSize > 0 ? 1 : 0; + createInfo.pPushConstantRanges = pushConstantSize > 0 ? &pushRange : 0; + + VkPipelineLayout layout = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineLayout (device, &createInfo, 0, &layout); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreatePipelineLayout failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif } - value lime_image_encode (value buffer, int type, int quality, value bytes) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* setLayouts, int pushConstantStages, int pushConstantSize) { - ImageBuffer imageBuffer = ImageBuffer (buffer); - Bytes data = Bytes (bytes); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + std::vector packed = GetHLVulkanIntVector (setLayouts); + if (packed.empty () || packed.size () < (size_t)(1 + packed[0] * 2)) return 0; - switch (type) { + std::vector layouts; + layouts.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { - case 0: + layouts.push_back ((VkDescriptorSetLayout)(uintptr_t)CombineVulkanHandle (packed[1 + i * 2], packed[2 + i * 2])); - #ifdef LIME_PNG - if (PNG::Encode (&imageBuffer, &data)) { + } - return data.Value (bytes); + VkPushConstantRange pushRange; + memset (&pushRange, 0, sizeof (pushRange)); + pushRange.stageFlags = (VkShaderStageFlags)pushConstantStages; + pushRange.offset = 0; + pushRange.size = (uint32_t)pushConstantSize; + + PFN_vkCreatePipelineLayout vkCreatePipelineLayout = + (PFN_vkCreatePipelineLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineLayout"); + if (!vkCreatePipelineLayout) return 0; + + VkPipelineLayoutCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + createInfo.setLayoutCount = (uint32_t)layouts.size (); + createInfo.pSetLayouts = layouts.empty () ? 0 : layouts.data (); + createInfo.pushConstantRangeCount = pushConstantSize > 0 ? 1 : 0; + createInfo.pPushConstantRanges = pushConstantSize > 0 ? &pushRange : 0; + + VkPipelineLayout layout = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineLayout (device, &createInfo, 0, &layout); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreatePipelineLayout failed"; + return 0; - } - #endif - break; + } - case 1: + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } - #ifdef LIME_JPEG - if (JPEG::Encode (&imageBuffer, &data, quality)) { + HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { - return data.Value (bytes); + Window* targetWindow = (Window*)window->ptr; + VulkanRenderer* renderer = new VulkanRenderer (targetWindow); + const char* applicationNameUTF8 = applicationName ? (const char*)hl_to_utf8 ((const uchar*)applicationName->bytes) : 0; - } - #endif - break; + if (!renderer->Create (applicationNameUTF8)) { - default: break; + lastVulkanRendererError = renderer->GetLastError (); + delete renderer; + return 0; } - return alloc_null (); + lastVulkanRendererError.clear (); + return HLCFFIPointer (renderer); } - HL_PRIM Bytes* HL_NAME(hl_image_encode) (ImageBuffer* buffer, int type, int quality, Bytes* bytes) { - - switch (type) { - - case 0: + void lime_vk_destroy_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { - #ifdef LIME_PNG - if (PNG::Encode (buffer, bytes)) { +#ifdef LIME_VULKAN + if (layoutHigh == 0 && layoutLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout = + (PFN_vkDestroyPipelineLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyPipelineLayout"); + if (vkDestroyPipelineLayout) { - return bytes; + vkDestroyPipelineLayout (device, layout, 0); + lastVKError.clear (); - } - #endif - break; + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - case 1: + } - #ifdef LIME_JPEG - if (JPEG::Encode (buffer, bytes, quality)) { - return bytes; + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int layoutHigh, int layoutLow) { - } - #endif - break; +#ifdef LIME_VULKAN + if (layoutHigh == 0 && layoutLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout = + (PFN_vkDestroyPipelineLayout)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyPipelineLayout"); + if (vkDestroyPipelineLayout) { - default: break; + vkDestroyPipelineLayout (device, layout, 0); + lastVKError.clear (); } - - return 0; +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - value lime_image_load_bytes (value data, value buffer) { + value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bytes, int byteOffset, + int byteLength) { - Resource resource; - Bytes bytes; +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreatePipelineCache vkCreatePipelineCache = + (PFN_vkCreatePipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineCache"); + if (!vkCreatePipelineCache) return alloc_null (); - ImageBuffer imageBuffer = ImageBuffer (buffer); + VkPipelineCacheCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + Bytes initialData (bytes); + if (initialData.b && byteLength > 0) { - bytes.Set (data); - resource = Resource (&bytes); + if (byteOffset < 0 || byteOffset + byteLength > initialData.length) { - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer)) { + lastVKError = "Invalid Vulkan pipeline cache data range"; + return alloc_null (); - return imageBuffer.Value (buffer); + } + + createInfo.initialDataSize = (size_t)byteLength; + createInfo.pInitialData = initialData.b + byteOffset; } - #endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer)) { + VkPipelineCache cache = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); + if (result != VK_SUCCESS) { - return imageBuffer.Value (buffer); + lastVKError = "vkCreatePipelineCache failed"; + return alloc_null (); } - #endif + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)cache); +#else + lastVKError = "Lime was built without lime-vulkan support"; return alloc_null (); +#endif } - HL_PRIM ImageBuffer* HL_NAME(hl_image_load_bytes) (Bytes* data, ImageBuffer* buffer) { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, Bytes* bytes, int byteOffset, int byteLength) { - Resource resource = Resource (data); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCreatePipelineCache vkCreatePipelineCache = + (PFN_vkCreatePipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineCache"); + if (!vkCreatePipelineCache) return 0; - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer)) { + VkPipelineCacheCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + if (bytes && bytes->b && byteLength > 0) { - return buffer; + if (byteOffset < 0 || byteOffset + byteLength > bytes->length) { + + lastVKError = "Invalid Vulkan pipeline cache data range"; + return 0; + + } + + createInfo.initialDataSize = (size_t)byteLength; + createInfo.pInitialData = bytes->b + byteOffset; } - #endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer)) { + VkPipelineCache cache = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); + if (result != VK_SUCCESS) { - return buffer; + lastVKError = "vkCreatePipelineCache failed"; + return 0; } - #endif + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)cache); +#else + lastVKError = "Lime was built without lime-vulkan support"; return 0; +#endif } - value lime_image_load_file (value data, value buffer) { + bool lime_vk_get_pipeline_cache_data (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow, value bytes) { - Resource resource = Resource (val_string (data)); - ImageBuffer imageBuffer = ImageBuffer (buffer); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (cacheHigh, cacheLow); + PFN_vkGetPipelineCacheData vkGetPipelineCacheData = + (PFN_vkGetPipelineCacheData)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetPipelineCacheData"); + if (!vkGetPipelineCacheData || !cache) return false; - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer)) { + size_t size = 0; + VkResult result = vkGetPipelineCacheData (device, cache, &size, 0); + if (result != VK_SUCCESS) { - return imageBuffer.Value (buffer); + lastVKError = "vkGetPipelineCacheData failed"; + return false; } - #endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer)) { + Bytes data (bytes); + data.Resize ((int)size); + if (size > 0 && !data.b) return false; - return imageBuffer.Value (buffer); + result = vkGetPipelineCacheData (device, cache, &size, data.b); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; } - #endif - return alloc_null (); + data.Value (bytes); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM ImageBuffer* HL_NAME(hl_image_load_file) (hl_vstring* data, ImageBuffer* buffer) { + HL_PRIM bool HL_NAME(hl_vk_get_pipeline_cache_data) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int cacheHigh, int cacheLow, Bytes* bytes) { - Resource resource = Resource (data); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (cacheHigh, cacheLow); + PFN_vkGetPipelineCacheData vkGetPipelineCacheData = + (PFN_vkGetPipelineCacheData)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetPipelineCacheData"); + if (!vkGetPipelineCacheData || !cache || !bytes) return false; - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer)) { + size_t size = 0; + VkResult result = vkGetPipelineCacheData (device, cache, &size, 0); + if (result != VK_SUCCESS) { - return buffer; + lastVKError = "vkGetPipelineCacheData failed"; + return false; } - #endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer)) { + bytes->Resize ((int)size); + if (size > 0 && !bytes->b) return false; - return buffer; + result = vkGetPipelineCacheData (device, cache, &size, bytes->b); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; } - #endif - return 0; + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_image_load (value data, value buffer) { - - if (val_is_string (data)) { - - return lime_image_load_file (data, buffer); + void lime_vk_destroy_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow) { - } else { +#ifdef LIME_VULKAN + if (cacheHigh == 0 && cacheLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (cacheHigh, cacheLow); + PFN_vkDestroyPipelineCache vkDestroyPipelineCache = + (PFN_vkDestroyPipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyPipelineCache"); + if (vkDestroyPipelineCache) { - return lime_image_load_bytes (data, buffer); + vkDestroyPipelineCache (device, cache, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - void lime_image_data_util_color_transform (value image, value rect, value colorMatrix) { + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int cacheHigh, int cacheLow) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); - ImageDataUtil::ColorTransform (&_image, &_rect, &_colorMatrix); +#ifdef LIME_VULKAN + if (cacheHigh == 0 && cacheLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (cacheHigh, cacheLow); + PFN_vkDestroyPipelineCache vkDestroyPipelineCache = + (PFN_vkDestroyPipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkDestroyPipelineCache"); + if (vkDestroyPipelineCache) { - } + vkDestroyPipelineCache (device, cache, 0); + lastVKError.clear (); + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - HL_PRIM void HL_NAME(hl_image_data_util_color_transform) (Image* image, Rectangle* rect, ArrayBufferView* colorMatrix) { + } - ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); - ImageDataUtil::ColorTransform (image, rect, &_colorMatrix); + void lime_vulkan_renderer_destroy (value handle) { + + if (val_is_null (handle)) return; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + delete renderer; } - void lime_image_data_util_copy_channel (value image, value sourceImage, value sourceRect, value destPoint, int srcChannel, int destChannel) { +#ifdef LIME_VULKAN + static VkPipeline CreateManagedVulkanGraphicsPipeline (Window* targetWindow, VkInstance instance, VkDevice device, VkRenderPass renderPass, + VkPipelineLayout layout, VkShaderModule vertexShader, VkShaderModule fragmentShader, const std::vector& state) { - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); - ImageDataUtil::CopyChannel (&_image, &_sourceImage, &_sourceRect, &_destPoint, srcChannel, destChannel); + if (state.size () < 41 || !renderPass || !layout || !vertexShader || !fragmentShader) { - } + lastVKError = "Invalid Vulkan graphics pipeline state"; + return VK_NULL_HANDLE; + } - HL_PRIM void HL_NAME(hl_image_data_util_copy_channel) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) { + int cursor = 0; + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (state[cursor], state[cursor + 1]); + cursor += 2; + int topology = state[cursor++]; + bool primitiveRestart = state[cursor++] != 0; + int polygonMode = state[cursor++]; + int cullMode = state[cursor++]; + int frontFace = state[cursor++]; + bool depthTest = state[cursor++] != 0; + bool depthWrite = state[cursor++] != 0; + int depthCompareOp = state[cursor++]; + bool blend = state[cursor++] != 0; + int srcColorBlendFactor = state[cursor++]; + int dstColorBlendFactor = state[cursor++]; + int colorBlendOp = state[cursor++]; + int srcAlphaBlendFactor = state[cursor++]; + int dstAlphaBlendFactor = state[cursor++]; + int alphaBlendOp = state[cursor++]; + int dynamicStateFlags = state[cursor++]; + int colorWriteMask = state[cursor++]; + bool stencilTest = state[cursor++] != 0; + int frontFailOp = state[cursor++]; + int frontPassOp = state[cursor++]; + int frontDepthFailOp = state[cursor++]; + int frontCompareOp = state[cursor++]; + int frontCompareMask = state[cursor++]; + int frontWriteMask = state[cursor++]; + int frontReference = state[cursor++]; + int backFailOp = state[cursor++]; + int backPassOp = state[cursor++]; + int backDepthFailOp = state[cursor++]; + int backCompareOp = state[cursor++]; + int backCompareMask = state[cursor++]; + int backWriteMask = state[cursor++]; + int backReference = state[cursor++]; + int rasterizationSamples = state[cursor++]; + bool sampleShading = state[cursor++] != 0; + int minSampleShading = state[cursor++]; + int sampleMask = state[cursor++]; + bool alphaToCoverage = state[cursor++] != 0; + bool alphaToOne = state[cursor++] != 0; + int bindingCount = state[cursor++]; + + if ((int)state.size () < cursor + bindingCount * 3 + 1) { + + lastVKError = "Invalid Vulkan vertex binding state"; + return VK_NULL_HANDLE; - ImageDataUtil::CopyChannel (image, sourceImage, sourceRect, destPoint, srcChannel, destChannel); + } - } + std::vector bindings; + bindings.reserve ((size_t)bindingCount); + for (int i = 0; i < bindingCount; ++i) { + VkVertexInputBindingDescription binding; + binding.binding = (uint32_t)state[cursor++]; + binding.stride = (uint32_t)state[cursor++]; + binding.inputRate = (VkVertexInputRate)state[cursor++]; + bindings.push_back (binding); - void lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value alphaImage, value alphaPoint, bool mergeAlpha) { + } - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); + int attributeCount = state[cursor++]; + if ((int)state.size () < cursor + attributeCount * 4) { - if (val_is_null (alphaImage)) { + lastVKError = "Invalid Vulkan vertex attribute state"; + return VK_NULL_HANDLE; - ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, 0, 0, mergeAlpha); + } - } else { + std::vector attributes; + attributes.reserve ((size_t)attributeCount); + for (int i = 0; i < attributeCount; ++i) { - Image _alphaImage = Image (alphaImage); - Vector2 _alphaPoint = Vector2 (alphaPoint); + VkVertexInputAttributeDescription attribute; + attribute.location = (uint32_t)state[cursor++]; + attribute.binding = (uint32_t)state[cursor++]; + attribute.format = (VkFormat)state[cursor++]; + attribute.offset = (uint32_t)state[cursor++]; + attributes.push_back (attribute); - ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, &_alphaImage, &_alphaPoint, mergeAlpha); + } + + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines = + (PFN_vkCreateGraphicsPipelines)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateGraphicsPipelines"); + if (!vkCreateGraphicsPipelines) return VK_NULL_HANDLE; + + VkPipelineShaderStageCreateInfo stages[2]; + memset (stages, 0, sizeof (stages)); + stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[0].module = vertexShader; + stages[0].pName = "main"; + stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[1].module = fragmentShader; + stages[1].pName = "main"; + + VkPipelineVertexInputStateCreateInfo vertexInput; + memset (&vertexInput, 0, sizeof (vertexInput)); + vertexInput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInput.vertexBindingDescriptionCount = (uint32_t)bindings.size (); + vertexInput.pVertexBindingDescriptions = bindings.empty () ? 0 : bindings.data (); + vertexInput.vertexAttributeDescriptionCount = (uint32_t)attributes.size (); + vertexInput.pVertexAttributeDescriptions = attributes.empty () ? 0 : attributes.data (); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly; + memset (&inputAssembly, 0, sizeof (inputAssembly)); + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = (VkPrimitiveTopology)topology; + inputAssembly.primitiveRestartEnable = primitiveRestart ? VK_TRUE : VK_FALSE; + + VkViewport viewport; + memset (&viewport, 0, sizeof (viewport)); + viewport.width = 1.0f; + viewport.height = 1.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor; + memset (&scissor, 0, sizeof (scissor)); + scissor.extent.width = 1; + scissor.extent.height = 1; + + VkPipelineViewportStateCreateInfo viewportState; + memset (&viewportState, 0, sizeof (viewportState)); + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterization; + memset (&rasterization, 0, sizeof (rasterization)); + rasterization.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization.polygonMode = (VkPolygonMode)polygonMode; + rasterization.cullMode = (VkCullModeFlags)cullMode; + rasterization.frontFace = (VkFrontFace)frontFace; + rasterization.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisample; + memset (&multisample, 0, sizeof (multisample)); + multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample.rasterizationSamples = (VkSampleCountFlagBits)rasterizationSamples; + multisample.sampleShadingEnable = sampleShading ? VK_TRUE : VK_FALSE; + multisample.minSampleShading = (float)minSampleShading / 1000000.0f; + VkSampleMask sampleMaskValue = (VkSampleMask)sampleMask; + multisample.pSampleMask = sampleMask != 0 ? &sampleMaskValue : 0; + multisample.alphaToCoverageEnable = alphaToCoverage ? VK_TRUE : VK_FALSE; + multisample.alphaToOneEnable = alphaToOne ? VK_TRUE : VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depthStencil; + memset (&depthStencil, 0, sizeof (depthStencil)); + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = depthTest ? VK_TRUE : VK_FALSE; + depthStencil.depthWriteEnable = depthWrite ? VK_TRUE : VK_FALSE; + depthStencil.depthCompareOp = (VkCompareOp)depthCompareOp; + depthStencil.stencilTestEnable = stencilTest ? VK_TRUE : VK_FALSE; + depthStencil.front.failOp = (VkStencilOp)frontFailOp; + depthStencil.front.passOp = (VkStencilOp)frontPassOp; + depthStencil.front.depthFailOp = (VkStencilOp)frontDepthFailOp; + depthStencil.front.compareOp = (VkCompareOp)frontCompareOp; + depthStencil.front.compareMask = (uint32_t)frontCompareMask; + depthStencil.front.writeMask = (uint32_t)frontWriteMask; + depthStencil.front.reference = (uint32_t)frontReference; + depthStencil.back.failOp = (VkStencilOp)backFailOp; + depthStencil.back.passOp = (VkStencilOp)backPassOp; + depthStencil.back.depthFailOp = (VkStencilOp)backDepthFailOp; + depthStencil.back.compareOp = (VkCompareOp)backCompareOp; + depthStencil.back.compareMask = (uint32_t)backCompareMask; + depthStencil.back.writeMask = (uint32_t)backWriteMask; + depthStencil.back.reference = (uint32_t)backReference; + + VkPipelineColorBlendAttachmentState colorAttachment; + memset (&colorAttachment, 0, sizeof (colorAttachment)); + colorAttachment.colorWriteMask = (VkColorComponentFlags)colorWriteMask; + colorAttachment.blendEnable = blend ? VK_TRUE : VK_FALSE; + colorAttachment.srcColorBlendFactor = (VkBlendFactor)srcColorBlendFactor; + colorAttachment.dstColorBlendFactor = (VkBlendFactor)dstColorBlendFactor; + colorAttachment.colorBlendOp = (VkBlendOp)colorBlendOp; + colorAttachment.srcAlphaBlendFactor = (VkBlendFactor)srcAlphaBlendFactor; + colorAttachment.dstAlphaBlendFactor = (VkBlendFactor)dstAlphaBlendFactor; + colorAttachment.alphaBlendOp = (VkBlendOp)alphaBlendOp; + + VkPipelineColorBlendStateCreateInfo colorBlend; + memset (&colorBlend, 0, sizeof (colorBlend)); + colorBlend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlend.attachmentCount = 1; + colorBlend.pAttachments = &colorAttachment; + + std::vector dynamicStates; + if (dynamicStateFlags & 0x1) dynamicStates.push_back (VK_DYNAMIC_STATE_VIEWPORT); + if (dynamicStateFlags & 0x2) dynamicStates.push_back (VK_DYNAMIC_STATE_SCISSOR); + VkPipelineDynamicStateCreateInfo dynamicState; + memset (&dynamicState, 0, sizeof (dynamicState)); + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = (uint32_t)dynamicStates.size (); + dynamicState.pDynamicStates = dynamicStates.empty () ? 0 : dynamicStates.data (); + + VkGraphicsPipelineCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.stageCount = 2; + createInfo.pStages = stages; + createInfo.pVertexInputState = &vertexInput; + createInfo.pInputAssemblyState = &inputAssembly; + createInfo.pViewportState = &viewportState; + createInfo.pRasterizationState = &rasterization; + createInfo.pMultisampleState = &multisample; + createInfo.pDepthStencilState = &depthStencil; + createInfo.pColorBlendState = &colorBlend; + createInfo.pDynamicState = dynamicStates.empty () ? 0 : &dynamicState; + createInfo.layout = layout; + createInfo.renderPass = renderPass; + createInfo.subpass = 0; + + VkPipeline pipeline = VK_NULL_HANDLE; + VkResult result = vkCreateGraphicsPipelines (device, cache, 1, &createInfo, 0, &pipeline); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateGraphicsPipelines failed"; + return VK_NULL_HANDLE; } + lastVKError.clear (); + return pipeline; + } +#endif - HL_PRIM void HL_NAME(hl_image_data_util_copy_pixels) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, Image* alphaImage, Vector2* alphaPoint, bool mergeAlpha) { - if (!alphaImage) { + value lime_vk_create_graphics_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int renderPassHigh, + int renderPassLow, int layoutHigh, int layoutLow, int vertexShaderHigh, int vertexShaderLow, int fragmentShaderHigh, int fragmentShaderLow, + value state) { - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, NULL, NULL, mergeAlpha); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipeline pipeline = CreateManagedVulkanGraphicsPipeline (targetWindow, instance, device, + (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow), + (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow), + (VkShaderModule)(uintptr_t)CombineVulkanHandle (vertexShaderHigh, vertexShaderLow), + (VkShaderModule)(uintptr_t)CombineVulkanHandle (fragmentShaderHigh, fragmentShaderLow), + GetVulkanIntVector (state)); + return pipeline ? CreateVulkanHandleValue ((uint64_t)(uintptr_t)pipeline) : alloc_null (); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif - } else { + } - if (!alphaPoint) { - Vector2 _alphaPoint = Vector2 (0, 0); + HL_PRIM vdynamic* HL_NAME(hl_vk_create_graphics_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int renderPassHigh, int renderPassLow, int layoutHigh, int layoutLow, int vertexShaderHigh, int vertexShaderLow, + int fragmentShaderHigh, int fragmentShaderLow, hl_varray* state) { - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, &_alphaPoint, mergeAlpha); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipeline pipeline = CreateManagedVulkanGraphicsPipeline (targetWindow, instance, device, + (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow), + (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow), + (VkShaderModule)(uintptr_t)CombineVulkanHandle (vertexShaderHigh, vertexShaderLow), + (VkShaderModule)(uintptr_t)CombineVulkanHandle (fragmentShaderHigh, fragmentShaderLow), + GetHLVulkanIntVector (state)); + return pipeline ? HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)pipeline) : 0; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif - } else { + } - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha); - } + void lime_vk_destroy_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int pipelineHigh, int pipelineLow) { + +#ifdef LIME_VULKAN + if (pipelineHigh == 0 && pipelineLow == 0) return; + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipeline pipeline = (VkPipeline)(uintptr_t)CombineVulkanHandle (pipelineHigh, pipelineLow); + PFN_vkDestroyPipeline vkDestroyPipeline = (PFN_vkDestroyPipeline)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyPipeline"); + if (vkDestroyPipeline) { + + vkDestroyPipeline (device, pipeline, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif } - void lime_image_data_util_fill_rect (value image, value rect, int rg, int ba) { + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int pipelineHigh, int pipelineLow) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - int32_t color = (rg << 16) | ba; - ImageDataUtil::FillRect (&_image, &_rect, color); +#ifdef LIME_VULKAN + if (pipelineHigh == 0 && pipelineLow == 0) return; + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkPipeline pipeline = (VkPipeline)(uintptr_t)CombineVulkanHandle (pipelineHigh, pipelineLow); + PFN_vkDestroyPipeline vkDestroyPipeline = (PFN_vkDestroyPipeline)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkDestroyPipeline"); + if (vkDestroyPipeline) { - } + vkDestroyPipeline (device, pipeline, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + } - HL_PRIM void HL_NAME(hl_image_data_util_fill_rect) (Image* image, Rectangle* rect, int rg, int ba) { + HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) { - int32_t color = (rg << 16) | ba; - ImageDataUtil::FillRect (image, rect, color); + if (!handle || !handle->ptr) return; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + handle->ptr = 0; + delete renderer; } - void lime_image_data_util_flood_fill (value image, int x, int y, int rg, int ba) { + bool lime_vk_queue_submit_synced (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, + int queueLow, int commandBufferHigh, int commandBufferLow, value state) { - Image _image = Image (image); - int32_t color = (rg << 16) | ba; - ImageDataUtil::FloodFill (&_image, x, y, color); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (packed.size () < 7) return false; + + VkSemaphore waitSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (packed[0], packed[1]); + VkPipelineStageFlags waitStage = (VkPipelineStageFlags)packed[2]; + VkSemaphore signalSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (packed[3], packed[4]); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (packed[5], packed[6]); + PFN_vkQueueSubmit vkQueueSubmit = (PFN_vkQueueSubmit)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkQueueSubmit"); + if (!vkQueueSubmit || !queue || !commandBuffer) return false; + + VkSubmitInfo submitInfo; + memset (&submitInfo, 0, sizeof (submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = waitSemaphore ? 1 : 0; + submitInfo.pWaitSemaphores = waitSemaphore ? &waitSemaphore : 0; + submitInfo.pWaitDstStageMask = waitSemaphore ? &waitStage : 0; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.signalSemaphoreCount = signalSemaphore ? 1 : 0; + submitInfo.pSignalSemaphores = signalSemaphore ? &signalSemaphore : 0; + + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { + + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_flood_fill) (Image* image, int x, int y, int rg, int ba) { + HL_PRIM bool HL_NAME(hl_vk_queue_submit_synced) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int queueHigh, int queueLow, int commandBufferHigh, int commandBufferLow, hl_varray* state) { - int32_t color = (rg << 16) | ba; - ImageDataUtil::FloodFill (image, x, y, color); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + VkQueue queue = (VkQueue)(uintptr_t)CombineVulkanHandle (queueHigh, queueLow); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (packed.size () < 7) return false; + + VkSemaphore waitSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (packed[0], packed[1]); + VkPipelineStageFlags waitStage = (VkPipelineStageFlags)packed[2]; + VkSemaphore signalSemaphore = (VkSemaphore)(uintptr_t)CombineVulkanHandle (packed[3], packed[4]); + VkFence fence = (VkFence)(uintptr_t)CombineVulkanHandle (packed[5], packed[6]); + PFN_vkQueueSubmit vkQueueSubmit = (PFN_vkQueueSubmit)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkQueueSubmit"); + if (!vkQueueSubmit || !queue || !commandBuffer) return false; + + VkSubmitInfo submitInfo; + memset (&submitInfo, 0, sizeof (submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = waitSemaphore ? 1 : 0; + submitInfo.pWaitSemaphores = waitSemaphore ? &waitSemaphore : 0; + submitInfo.pWaitDstStageMask = waitSemaphore ? &waitStage : 0; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.signalSemaphoreCount = signalSemaphore ? 1 : 0; + submitInfo.pSignalSemaphores = signalSemaphore ? &signalSemaphore : 0; + + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { + + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_get_pixels (value image, value rect, int format, value bytes) { + bool lime_vk_cmd_begin_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int renderPassHigh, int renderPassLow, int framebufferHigh, int framebufferLow, value state, value clear) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - PixelFormat _format = (PixelFormat)format; - Bytes pixels = Bytes (bytes); - ImageDataUtil::GetPixels (&_image, &_rect, _format, &pixels); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdBeginRenderPass"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + std::vector clearValues = GetVulkanDoubleVector (clear); + if (!vkCmdBeginRenderPass || !commandBuffer || packed.size () < 5 || clearValues.size () < 5) return false; + uint32_t clearValueCount = packed.size () > 5 ? (uint32_t)packed[5] : 2; + if (clearValueCount < 1) clearValueCount = 1; + if (clearValueCount > 2) clearValueCount = 2; + + VkClearValue clears[2]; + memset (clears, 0, sizeof (clears)); + clears[0].color.float32[0] = (float)clearValues[0]; + clears[0].color.float32[1] = (float)clearValues[1]; + clears[0].color.float32[2] = (float)clearValues[2]; + clears[0].color.float32[3] = (float)clearValues[3]; + clears[1].depthStencil.depth = (float)clearValues[4]; + clears[1].depthStencil.stencil = (uint32_t)packed[4]; + + VkRenderPassBeginInfo beginInfo; + memset (&beginInfo, 0, sizeof (beginInfo)); + beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + beginInfo.renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + beginInfo.framebuffer = (VkFramebuffer)(uintptr_t)CombineVulkanHandle (framebufferHigh, framebufferLow); + beginInfo.renderArea.offset.x = packed[0]; + beginInfo.renderArea.offset.y = packed[1]; + beginInfo.renderArea.extent.width = (uint32_t)packed[2]; + beginInfo.renderArea.extent.height = (uint32_t)packed[3]; + beginInfo.clearValueCount = clearValueCount; + beginInfo.pClearValues = clears; + + vkCmdBeginRenderPass (commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_get_pixels) (Image* image, Rectangle* rect, PixelFormat format, Bytes* bytes) { + HL_PRIM bool HL_NAME(hl_vk_cmd_begin_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int renderPassHigh, int renderPassLow, int framebufferHigh, int framebufferLow, + hl_varray* state, hl_varray* clear) { - ImageDataUtil::GetPixels (image, rect, format, bytes); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdBeginRenderPass"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + std::vector clearValues = GetHLVulkanDoubleVector (clear); + if (!vkCmdBeginRenderPass || !commandBuffer || packed.size () < 5 || clearValues.size () < 5) return false; + uint32_t clearValueCount = packed.size () > 5 ? (uint32_t)packed[5] : 2; + if (clearValueCount < 1) clearValueCount = 1; + if (clearValueCount > 2) clearValueCount = 2; + + VkClearValue clears[2]; + memset (clears, 0, sizeof (clears)); + clears[0].color.float32[0] = (float)clearValues[0]; + clears[0].color.float32[1] = (float)clearValues[1]; + clears[0].color.float32[2] = (float)clearValues[2]; + clears[0].color.float32[3] = (float)clearValues[3]; + clears[1].depthStencil.depth = (float)clearValues[4]; + clears[1].depthStencil.stencil = (uint32_t)packed[4]; + + VkRenderPassBeginInfo beginInfo; + memset (&beginInfo, 0, sizeof (beginInfo)); + beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + beginInfo.renderPass = (VkRenderPass)(uintptr_t)CombineVulkanHandle (renderPassHigh, renderPassLow); + beginInfo.framebuffer = (VkFramebuffer)(uintptr_t)CombineVulkanHandle (framebufferHigh, framebufferLow); + beginInfo.renderArea.offset.x = packed[0]; + beginInfo.renderArea.offset.y = packed[1]; + beginInfo.renderArea.extent.width = (uint32_t)packed[2]; + beginInfo.renderArea.extent.height = (uint32_t)packed[3]; + beginInfo.clearValueCount = clearValueCount; + beginInfo.pClearValues = clears; + + vkCmdBeginRenderPass (commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_merge (value image, value sourceImage, value sourceRect, value destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { + bool lime_vk_cmd_end_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow) { - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); - ImageDataUtil::Merge (&_image, &_sourceImage, &_sourceRect, &_destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdEndRenderPass vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdEndRenderPass"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdEndRenderPass || !commandBuffer) return false; + vkCmdEndRenderPass (commandBuffer); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_merge) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { + HL_PRIM bool HL_NAME(hl_vk_cmd_end_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow) { - ImageDataUtil::Merge (image, sourceImage, sourceRect, destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdEndRenderPass vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdEndRenderPass"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdEndRenderPass || !commandBuffer) return false; + vkCmdEndRenderPass (commandBuffer); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_multiply_alpha (value image) { + bool lime_vk_cmd_bind_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int pipelineHigh, int pipelineLow, int bindPoint) { - Image _image = Image (image); - ImageDataUtil::MultiplyAlpha (&_image); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindPipeline vkCmdBindPipeline = (PFN_vkCmdBindPipeline)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdBindPipeline"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipeline pipeline = (VkPipeline)(uintptr_t)CombineVulkanHandle (pipelineHigh, pipelineLow); + if (!vkCmdBindPipeline || !commandBuffer || !pipeline) return false; + vkCmdBindPipeline (commandBuffer, (VkPipelineBindPoint)bindPoint, pipeline); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_multiply_alpha) (Image* image) { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int pipelineHigh, int pipelineLow, int bindPoint) { - ImageDataUtil::MultiplyAlpha (image); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindPipeline vkCmdBindPipeline = (PFN_vkCmdBindPipeline)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdBindPipeline"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipeline pipeline = (VkPipeline)(uintptr_t)CombineVulkanHandle (pipelineHigh, pipelineLow); + if (!vkCmdBindPipeline || !commandBuffer || !pipeline) return false; + vkCmdBindPipeline (commandBuffer, (VkPipelineBindPoint)bindPoint, pipeline); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_resize (value image, value buffer, int width, int height) { + bool lime_vk_cmd_bind_descriptor_set (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int bindPoint, int firstSet) { - Image _image = Image (image); - ImageBuffer _buffer = ImageBuffer (buffer); - ImageDataUtil::Resize (&_image, &_buffer, width, height); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet) return false; + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)bindPoint, layout, (uint32_t)firstSet, 1, &descriptorSet, 0, 0); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_resize) (Image* image, ImageBuffer* buffer, int width, int height) { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int bindPoint, + int firstSet) { - ImageDataUtil::Resize (image, buffer, width, height); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet) return false; + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)bindPoint, layout, (uint32_t)firstSet, 1, &descriptorSet, 0, 0); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } + bool lime_vk_cmd_bind_descriptor_set_ex (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, value state) { - void lime_image_data_util_set_format (value image, int format) { - - Image _image = Image (image); - PixelFormat _format = (PixelFormat)format; - ImageDataUtil::SetFormat (&_image, _format); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet || packed.size () < 3) return false; + + int dynamicOffsetCount = packed[2]; + if ((int)packed.size () < 3 + dynamicOffsetCount) return false; + std::vector dynamicOffsets; + dynamicOffsets.reserve ((size_t)dynamicOffsetCount); + for (int i = 0; i < dynamicOffsetCount; ++i) dynamicOffsets.push_back ((uint32_t)packed[3 + i]); + + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)packed[0], layout, (uint32_t)packed[1], 1, &descriptorSet, + (uint32_t)dynamicOffsets.size (), dynamicOffsets.empty () ? 0 : dynamicOffsets.data ()); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_set_format) (Image* image, PixelFormat format) { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set_ex) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, hl_varray* state) { - ImageDataUtil::SetFormat (image, format); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet || packed.size () < 3) return false; + + int dynamicOffsetCount = packed[2]; + if ((int)packed.size () < 3 + dynamicOffsetCount) return false; + std::vector dynamicOffsets; + dynamicOffsets.reserve ((size_t)dynamicOffsetCount); + for (int i = 0; i < dynamicOffsetCount; ++i) dynamicOffsets.push_back ((uint32_t)packed[3 + i]); + + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)packed[0], layout, (uint32_t)packed[1], 1, &descriptorSet, + (uint32_t)dynamicOffsets.size (), dynamicOffsets.empty () ? 0 : dynamicOffsets.data ()); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format, int endian) { + bool lime_vk_cmd_bind_descriptor_set_dynamic_offset (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int dynamicOffset, int firstSet, + int bindPoint) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - Bytes _bytes (bytes); - PixelFormat _format = (PixelFormat)format; - Endian _endian = (Endian)endian; - ImageDataUtil::SetPixels (&_image, &_rect, &_bytes, offset, _format, _endian); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + uint32_t offset = (uint32_t)dynamicOffset; + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet) return false; + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)bindPoint, layout, (uint32_t)firstSet, 1, &descriptorSet, 1, &offset); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_set_pixels) (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format, Endian endian) { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set_dynamic_offset) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, + int deviceHigh, int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, + int dynamicOffset, int firstSet, int bindPoint) { - ImageDataUtil::SetPixels (image, rect, bytes, offset, format, endian); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets = + (PFN_vkCmdBindDescriptorSets)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindDescriptorSets"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + VkDescriptorSet descriptorSet = (VkDescriptorSet)(uintptr_t)CombineVulkanHandle (setHigh, setLow); + uint32_t offset = (uint32_t)dynamicOffset; + if (!vkCmdBindDescriptorSets || !commandBuffer || !layout || !descriptorSet) return false; + vkCmdBindDescriptorSets (commandBuffer, (VkPipelineBindPoint)bindPoint, layout, (uint32_t)firstSet, 1, &descriptorSet, 1, &offset); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - int lime_image_data_util_threshold (value image, value sourceImage, value sourceRect, value destPoint, int operation, int thresholdRG, int thresholdBA, int colorRG, int colorBA, int maskRG, int maskBA, bool copySource) { + value lime_vulkan_renderer_get_info (value handle) { - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); - int32_t threshold = (thresholdRG << 16) | thresholdBA; - int32_t color = (colorRG << 16) | colorBA; - int32_t mask = (maskRG << 16) | maskBA; - return ImageDataUtil::Threshold (&_image, &_sourceImage, &_sourceRect, &_destPoint, operation, threshold, color, mask, copySource); + if (val_is_null (handle)) return alloc_string (""); + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + return alloc_string (renderer->GetInfo ().c_str ()); } - HL_PRIM int HL_NAME(hl_image_data_util_threshold) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int operation, int thresholdRG, int thresholdBA, int colorRG, int colorBA, int maskRG, int maskBA, bool copySource) { + bool lime_vk_cmd_bind_vertex_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int binding, int offsetHigh, int offsetLow) { - int32_t threshold = (thresholdRG << 16) | thresholdBA; - int32_t color = (colorRG << 16) | colorBA; - int32_t mask = (maskRG << 16) | maskBA; - return ImageDataUtil::Threshold (image, sourceImage, sourceRect, destPoint, operation, threshold, color, mask, copySource); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers = + (PFN_vkCmdBindVertexBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindVertexBuffers"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + VkDeviceSize offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + if (!vkCmdBindVertexBuffers || !commandBuffer || !buffer) return false; + vkCmdBindVertexBuffers (commandBuffer, (uint32_t)binding, 1, &buffer, &offset); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_image_data_util_unmultiply_alpha (value image) { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_vertex_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int binding, int offsetHigh, int offsetLow) { - Image _image = Image (image); - ImageDataUtil::UnmultiplyAlpha (&_image); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers = + (PFN_vkCmdBindVertexBuffers)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindVertexBuffers"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + VkDeviceSize offset = (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow); + if (!vkCmdBindVertexBuffers || !commandBuffer || !buffer) return false; + vkCmdBindVertexBuffers (commandBuffer, (uint32_t)binding, 1, &buffer, &offset); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_image_data_util_unmultiply_alpha) (Image* image) { + bool lime_vk_cmd_bind_index_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int indexType) { - ImageDataUtil::UnmultiplyAlpha (image); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer = + (PFN_vkCmdBindIndexBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindIndexBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdBindIndexBuffer || !commandBuffer || !buffer) return false; + vkCmdBindIndexBuffer (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (VkIndexType)indexType); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - double lime_jni_getenv () { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_index_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int indexType) { - #ifdef ANDROID - return (uintptr_t)JNI::GetEnv (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer = + (PFN_vkCmdBindIndexBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBindIndexBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdBindIndexBuffer || !commandBuffer || !buffer) return false; + vkCmdBindIndexBuffer (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (VkIndexType)indexType); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM double HL_NAME(hl_jni_getenv) () { + bool lime_vk_cmd_set_viewport (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, double x, double y, double width, double height, double minDepth, double maxDepth) { - #ifdef ANDROID - return (uintptr_t)JNI::GetEnv (); - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdSetViewport vkCmdSetViewport = (PFN_vkCmdSetViewport)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdSetViewport"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdSetViewport || !commandBuffer) return false; + VkViewport viewport; + viewport.x = (float)x; + viewport.y = (float)y; + viewport.width = (float)width; + viewport.height = (float)height; + viewport.minDepth = (float)minDepth; + viewport.maxDepth = (float)maxDepth; + vkCmdSetViewport (commandBuffer, 0, 1, &viewport); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_joystick_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vk_cmd_set_viewport) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, double x, double y, double width, double height, double minDepth, double maxDepth) { - JoystickEvent::callback = new ValuePointer (callback); - JoystickEvent::eventObject = new ValuePointer (eventObject); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdSetViewport vkCmdSetViewport = (PFN_vkCmdSetViewport)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdSetViewport"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdSetViewport || !commandBuffer) return false; + VkViewport viewport; + viewport.x = (float)x; + viewport.y = (float)y; + viewport.width = (float)width; + viewport.height = (float)height; + viewport.minDepth = (float)minDepth; + viewport.maxDepth = (float)maxDepth; + vkCmdSetViewport (commandBuffer, 0, 1, &viewport); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { - HL_PRIM void HL_NAME(hl_joystick_event_manager_register) (vclosure* callback, JoystickEvent* eventObject) { - - JoystickEvent::callback = new ValuePointer (callback); - JoystickEvent::eventObject = new ValuePointer ((vobj*)eventObject); + if (!handle || !handle->ptr) return 0; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + return hl_copy_bytes ((const vbyte*)renderer->GetInfo ().c_str (), (int)renderer->GetInfo ().size () + 1); } - value lime_joystick_get_device_guid (int id) { + bool lime_vk_cmd_set_scissor (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int x, int y, int width, int height) { - const char* guid = Joystick::GetDeviceGUID (id); - return guid ? alloc_string (guid) : alloc_null (); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdSetScissor vkCmdSetScissor = (PFN_vkCmdSetScissor)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdSetScissor"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdSetScissor || !commandBuffer) return false; + VkRect2D scissor; + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = (uint32_t)width; + scissor.extent.height = (uint32_t)height; + vkCmdSetScissor (commandBuffer, 0, 1, &scissor); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_guid) (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_set_scissor) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int x, int y, int width, int height) { - return (vbyte*)Joystick::GetDeviceGUID (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdSetScissor vkCmdSetScissor = (PFN_vkCmdSetScissor)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdSetScissor"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdSetScissor || !commandBuffer) return false; + VkRect2D scissor; + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = (uint32_t)width; + scissor.extent.height = (uint32_t)height; + vkCmdSetScissor (commandBuffer, 0, 1, &scissor); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_joystick_get_device_name (int id) { + bool lime_vk_cmd_draw (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - const char* name = Joystick::GetDeviceName (id); - return name ? alloc_string (name) : alloc_null (); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDraw vkCmdDraw = (PFN_vkCmdDraw)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdDraw"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdDraw || !commandBuffer) return false; + vkCmdDraw (commandBuffer, (uint32_t)vertexCount, (uint32_t)instanceCount, (uint32_t)firstVertex, (uint32_t)firstInstance); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_name) (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - return (vbyte*)Joystick::GetDeviceName (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDraw vkCmdDraw = (PFN_vkCmdDraw)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdDraw"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdDraw || !commandBuffer) return false; + vkCmdDraw (commandBuffer, (uint32_t)vertexCount, (uint32_t)instanceCount, (uint32_t)firstVertex, (uint32_t)firstInstance); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - int lime_joystick_get_num_axes (int id) { + bool lime_vk_cmd_draw_indexed (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) { - return Joystick::GetNumAxes (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndexed vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdDrawIndexed"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdDrawIndexed || !commandBuffer) return false; + vkCmdDrawIndexed (commandBuffer, (uint32_t)indexCount, (uint32_t)instanceCount, (uint32_t)firstIndex, vertexOffset, (uint32_t)firstInstance); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM int HL_NAME(hl_joystick_get_num_axes) (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indexed) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) { - return Joystick::GetNumAxes (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndexed vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdDrawIndexed"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + if (!vkCmdDrawIndexed || !commandBuffer) return false; + vkCmdDrawIndexed (commandBuffer, (uint32_t)indexCount, (uint32_t)instanceCount, (uint32_t)firstIndex, vertexOffset, (uint32_t)firstInstance); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - int lime_joystick_get_num_buttons (int id) { + bool lime_vk_cmd_draw_indirect (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - return Joystick::GetNumButtons (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndirect vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdDrawIndirect"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdDrawIndirect || !commandBuffer || !buffer) return false; + vkCmdDrawIndirect (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (uint32_t)drawCount, + (uint32_t)stride); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM int HL_NAME(hl_joystick_get_num_buttons) (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indirect) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - return Joystick::GetNumButtons (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndirect vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCmdDrawIndirect"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdDrawIndirect || !commandBuffer || !buffer) return false; + vkCmdDrawIndirect (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (uint32_t)drawCount, + (uint32_t)stride); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - int lime_joystick_get_num_hats (int id) { + bool lime_vk_cmd_draw_indexed_indirect (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - return Joystick::GetNumHats (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect = + (PFN_vkCmdDrawIndexedIndirect)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdDrawIndexedIndirect"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdDrawIndexedIndirect || !commandBuffer || !buffer) return false; + vkCmdDrawIndexedIndirect (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (uint32_t)drawCount, + (uint32_t)stride); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM int HL_NAME(hl_joystick_get_num_hats) (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indexed_indirect) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, + int stride) { - return Joystick::GetNumHats (id); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect = + (PFN_vkCmdDrawIndexedIndirect)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdDrawIndexedIndirect"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkBuffer buffer = (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow); + if (!vkCmdDrawIndexedIndirect || !commandBuffer || !buffer) return false; + vkCmdDrawIndexedIndirect (commandBuffer, buffer, (VkDeviceSize)CombineVulkanHandle (offsetHigh, offsetLow), (uint32_t)drawCount, + (uint32_t)stride); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } + value lime_vulkan_renderer_get_last_error () { - value lime_jpeg_decode_bytes (value data, bool decodeData, value buffer) { - - ImageBuffer imageBuffer (buffer); - - Bytes bytes (data); - Resource resource = Resource (&bytes); + return alloc_string (lastVulkanRendererError.c_str ()); - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + bool lime_vk_cmd_copy_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, value state) { - return alloc_null (); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyBuffer vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdCopyBuffer || !commandBuffer || packed.size () < 6) return false; + + VkBufferCopy region; + region.size = (VkDeviceSize)CombineVulkanHandle (packed[0], packed[1]); + region.srcOffset = (VkDeviceSize)CombineVulkanHandle (packed[2], packed[3]); + region.dstOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + vkCmdCopyBuffer (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), + (VkBuffer)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { - - Resource resource = Resource (data); + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, hl_varray* state) { - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer, decodeData)) { +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyBuffer vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdCopyBuffer || !commandBuffer || packed.size () < 6) return false; + + VkBufferCopy region; + region.size = (VkDeviceSize)CombineVulkanHandle (packed[0], packed[1]); + region.srcOffset = (VkDeviceSize)CombineVulkanHandle (packed[2], packed[3]); + region.dstOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + vkCmdCopyBuffer (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), + (VkBuffer)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - return buffer; + } - } - #endif + bool lime_vk_cmd_copy_buffer_to_image_region (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, value state) { - return 0; +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage = + (PFN_vkCmdCopyBufferToImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBufferToImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdCopyBufferToImage || !commandBuffer || packed.size () < 15) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.bufferOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + region.bufferRowLength = (uint32_t)packed[6]; + region.bufferImageHeight = (uint32_t)packed[7]; + region.imageSubresource.aspectMask = (VkImageAspectFlags)packed[14]; + region.imageSubresource.mipLevel = (uint32_t)packed[11]; + region.imageSubresource.baseArrayLayer = (uint32_t)packed[12]; + region.imageSubresource.layerCount = (uint32_t)packed[13]; + region.imageOffset.x = packed[8]; + region.imageOffset.y = packed[9]; + region.imageOffset.z = packed[10]; + region.imageExtent.width = (uint32_t)packed[0]; + region.imageExtent.height = (uint32_t)packed[1]; + region.imageExtent.depth = (uint32_t)packed[2]; + vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), + (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[3], 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_jpeg_decode_file (HxString path, bool decodeData, value buffer) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image_region) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, hl_varray* state) { - ImageBuffer imageBuffer (buffer); - Resource resource = Resource (hxs_utf8 (path, nullptr)); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage = + (PFN_vkCmdCopyBufferToImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBufferToImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdCopyBufferToImage || !commandBuffer || packed.size () < 15) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.bufferOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + region.bufferRowLength = (uint32_t)packed[6]; + region.bufferImageHeight = (uint32_t)packed[7]; + region.imageSubresource.aspectMask = (VkImageAspectFlags)packed[14]; + region.imageSubresource.mipLevel = (uint32_t)packed[11]; + region.imageSubresource.baseArrayLayer = (uint32_t)packed[12]; + region.imageSubresource.layerCount = (uint32_t)packed[13]; + region.imageOffset.x = packed[8]; + region.imageOffset.y = packed[9]; + region.imageOffset.z = packed[10]; + region.imageExtent.width = (uint32_t)packed[0]; + region.imageExtent.height = (uint32_t)packed[1]; + region.imageExtent.depth = (uint32_t)packed[2]; + vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), + (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[3], 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + bool lime_vk_cmd_copy_image_to_buffer_region (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int bufferHigh, int bufferLow, value state) { - return alloc_null (); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer = + (PFN_vkCmdCopyImageToBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyImageToBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdCopyImageToBuffer || !commandBuffer || packed.size () < 15) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.bufferOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + region.bufferRowLength = (uint32_t)packed[6]; + region.bufferImageHeight = (uint32_t)packed[7]; + region.imageSubresource.aspectMask = (VkImageAspectFlags)packed[14]; + region.imageSubresource.mipLevel = (uint32_t)packed[11]; + region.imageSubresource.baseArrayLayer = (uint32_t)packed[12]; + region.imageSubresource.layerCount = (uint32_t)packed[13]; + region.imageOffset.x = packed[8]; + region.imageOffset.y = packed[9]; + region.imageOffset.z = packed[10]; + region.imageExtent.width = (uint32_t)packed[0]; + region.imageExtent.height = (uint32_t)packed[1]; + region.imageExtent.depth = (uint32_t)packed[2]; + vkCmdCopyImageToBuffer (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[3], + (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { - - Resource resource = Resource (path); + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_image_to_buffer_region) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int bufferHigh, int bufferLow, hl_varray* state) { - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer, decodeData)) { +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer = + (PFN_vkCmdCopyImageToBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyImageToBuffer"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdCopyImageToBuffer || !commandBuffer || packed.size () < 15) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.bufferOffset = (VkDeviceSize)CombineVulkanHandle (packed[4], packed[5]); + region.bufferRowLength = (uint32_t)packed[6]; + region.bufferImageHeight = (uint32_t)packed[7]; + region.imageSubresource.aspectMask = (VkImageAspectFlags)packed[14]; + region.imageSubresource.mipLevel = (uint32_t)packed[11]; + region.imageSubresource.baseArrayLayer = (uint32_t)packed[12]; + region.imageSubresource.layerCount = (uint32_t)packed[13]; + region.imageOffset.x = packed[8]; + region.imageOffset.y = packed[9]; + region.imageOffset.z = packed[10]; + region.imageExtent.width = (uint32_t)packed[0]; + region.imageExtent.height = (uint32_t)packed[1]; + region.imageExtent.depth = (uint32_t)packed[2]; + vkCmdCopyImageToBuffer (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[3], + (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), 1, ®ion); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - return buffer; + } - } - #endif + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { - return 0; + return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); } - int lime_key_code_from_scan_code (int scanCode) { + bool lime_vk_cmd_pipeline_barrier_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, value state) { - return KeyCode::FromScanCode (scanCode); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdPipelineBarrier"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdPipelineBarrier || !commandBuffer || packed.size () < 11) return false; + + VkImageMemoryBarrier barrier; + memset (&barrier, 0, sizeof (barrier)); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = (VkImageLayout)packed[0]; + barrier.newLayout = (VkImageLayout)packed[1]; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + barrier.srcAccessMask = (VkAccessFlags)packed[4]; + barrier.dstAccessMask = (VkAccessFlags)packed[5]; + barrier.subresourceRange.aspectMask = (VkImageAspectFlags)packed[6]; + barrier.subresourceRange.baseMipLevel = (uint32_t)packed[7]; + barrier.subresourceRange.levelCount = (uint32_t)packed[8]; + barrier.subresourceRange.baseArrayLayer = (uint32_t)packed[9]; + barrier.subresourceRange.layerCount = (uint32_t)packed[10]; + + vkCmdPipelineBarrier (commandBuffer, (VkPipelineStageFlags)packed[2], (VkPipelineStageFlags)packed[3], 0, 0, 0, 0, 0, 1, &barrier); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM int HL_NAME(hl_key_code_from_scan_code) (int scanCode) { + HL_PRIM bool HL_NAME(hl_vk_cmd_pipeline_barrier_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, hl_varray* state) { - return KeyCode::FromScanCode (scanCode); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdPipelineBarrier"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdPipelineBarrier || !commandBuffer || packed.size () < 11) return false; + + VkImageMemoryBarrier barrier; + memset (&barrier, 0, sizeof (barrier)); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = (VkImageLayout)packed[0]; + barrier.newLayout = (VkImageLayout)packed[1]; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow); + barrier.srcAccessMask = (VkAccessFlags)packed[4]; + barrier.dstAccessMask = (VkAccessFlags)packed[5]; + barrier.subresourceRange.aspectMask = (VkImageAspectFlags)packed[6]; + barrier.subresourceRange.baseMipLevel = (uint32_t)packed[7]; + barrier.subresourceRange.levelCount = (uint32_t)packed[8]; + barrier.subresourceRange.baseArrayLayer = (uint32_t)packed[9]; + barrier.subresourceRange.layerCount = (uint32_t)packed[10]; + + vkCmdPipelineBarrier (commandBuffer, (VkPipelineStageFlags)packed[2], (VkPipelineStageFlags)packed[3], 0, 0, 0, 0, 0, 1, &barrier); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - int lime_key_code_to_scan_code (int keyCode) { + bool lime_vk_cmd_clear_color_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int imageHigh, int imageLow, int layout, int aspectMask, value clear) { - return KeyCode::ToScanCode (keyCode); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearColorImage vkCmdClearColorImage = + (PFN_vkCmdClearColorImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearColorImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector clearValues = GetVulkanDoubleVector (clear); + if (!vkCmdClearColorImage || !commandBuffer || clearValues.size () < 4) return false; + + VkClearColorValue color; + color.float32[0] = (float)clearValues[0]; + color.float32[1] = (float)clearValues[1]; + color.float32[2] = (float)clearValues[2]; + color.float32[3] = (float)clearValues[3]; + VkImageSubresourceRange range; + memset (&range, 0, sizeof (range)); + range.aspectMask = (VkImageAspectFlags)aspectMask; + range.levelCount = 1; + range.layerCount = 1; + vkCmdClearColorImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, &color, 1, &range); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM int HL_NAME(hl_key_code_to_scan_code) (int keyCode) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_color_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int layout, int aspectMask, hl_varray* clear) { - return KeyCode::ToScanCode (keyCode); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearColorImage vkCmdClearColorImage = + (PFN_vkCmdClearColorImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearColorImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector clearValues = GetHLVulkanDoubleVector (clear); + if (!vkCmdClearColorImage || !commandBuffer || clearValues.size () < 4) return false; + + VkClearColorValue color; + color.float32[0] = (float)clearValues[0]; + color.float32[1] = (float)clearValues[1]; + color.float32[2] = (float)clearValues[2]; + color.float32[3] = (float)clearValues[3]; + VkImageSubresourceRange range; + memset (&range, 0, sizeof (range)); + range.aspectMask = (VkImageAspectFlags)aspectMask; + range.levelCount = 1; + range.layerCount = 1; + vkCmdClearColorImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, &color, 1, &range); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_key_event_manager_register (value callback, value eventObject) { + bool lime_vk_cmd_clear_depth_stencil_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, value state, value clear) { - KeyEvent::callback = new ValuePointer (callback); - KeyEvent::eventObject = new ValuePointer (eventObject); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage = + (PFN_vkCmdClearDepthStencilImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearDepthStencilImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + std::vector clearValues = GetVulkanDoubleVector (clear); + if (!vkCmdClearDepthStencilImage || !commandBuffer || packed.size () < 7 || clearValues.size () < 1) return false; + + VkClearDepthStencilValue depthStencil; + depthStencil.depth = (float)clearValues[0]; + depthStencil.stencil = (uint32_t)packed[1]; + VkImageSubresourceRange range; + memset (&range, 0, sizeof (range)); + range.aspectMask = (VkImageAspectFlags)packed[2]; + range.baseMipLevel = (uint32_t)packed[3]; + range.levelCount = (uint32_t)packed[4]; + range.baseArrayLayer = (uint32_t)packed[5]; + range.layerCount = (uint32_t)packed[6]; + vkCmdClearDepthStencilImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[0], + &depthStencil, 1, &range); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM void HL_NAME(hl_key_event_manager_register) (vclosure* callback, KeyEvent* eventObject) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_depth_stencil_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, hl_varray* state, hl_varray* clear) { - KeyEvent::callback = new ValuePointer (callback); - KeyEvent::eventObject = new ValuePointer ((vobj*)eventObject); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage = + (PFN_vkCmdClearDepthStencilImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearDepthStencilImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + std::vector clearValues = GetHLVulkanDoubleVector (clear); + if (!vkCmdClearDepthStencilImage || !commandBuffer || packed.size () < 7 || clearValues.size () < 1) return false; + + VkClearDepthStencilValue depthStencil; + depthStencil.depth = (float)clearValues[0]; + depthStencil.stencil = (uint32_t)packed[1]; + VkImageSubresourceRange range; + memset (&range, 0, sizeof (range)); + range.aspectMask = (VkImageAspectFlags)packed[2]; + range.baseMipLevel = (uint32_t)packed[3]; + range.levelCount = (uint32_t)packed[4]; + range.baseArrayLayer = (uint32_t)packed[5]; + range.layerCount = (uint32_t)packed[6]; + vkCmdClearDepthStencilImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)packed[0], + &depthStencil, 1, &range); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_locale_get_system_locale () { - - std::string* locale = Locale::GetSystemLocale (); + bool lime_vk_cmd_clear_attachments (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, value state, value clear) { - if (!locale) { +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearAttachments vkCmdClearAttachments = + (PFN_vkCmdClearAttachments)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearAttachments"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + std::vector clearValues = GetVulkanDoubleVector (clear); + if (!vkCmdClearAttachments || !commandBuffer || packed.size () < 8 || clearValues.size () < 5) return false; + + VkClearAttachment attachments[2]; + memset (attachments, 0, sizeof (attachments)); + uint32_t attachmentCount = 0; + + if (packed[0] != 0) { + + attachments[attachmentCount].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attachments[attachmentCount].colorAttachment = 0; + attachments[attachmentCount].clearValue.color.float32[0] = (float)clearValues[0]; + attachments[attachmentCount].clearValue.color.float32[1] = (float)clearValues[1]; + attachments[attachmentCount].clearValue.color.float32[2] = (float)clearValues[2]; + attachments[attachmentCount].clearValue.color.float32[3] = (float)clearValues[3]; + attachmentCount++; - return alloc_null (); + } - } else { + if (packed[1] != 0 || packed[2] != 0) { - value result = alloc_string (locale->c_str ()); - delete locale; - return result; + attachments[attachmentCount].aspectMask = 0; + if (packed[1] != 0) attachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (packed[2] != 0) attachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + attachments[attachmentCount].clearValue.depthStencil.depth = (float)clearValues[4]; + attachments[attachmentCount].clearValue.depthStencil.stencil = (uint32_t)packed[7]; + attachmentCount++; } - } - + if (attachmentCount == 0) return true; + + VkClearRect rect; + memset (&rect, 0, sizeof (rect)); + rect.rect.offset.x = packed[3]; + rect.rect.offset.y = packed[4]; + rect.rect.extent.width = (uint32_t)packed[5]; + rect.rect.extent.height = (uint32_t)packed[6]; + rect.baseArrayLayer = 0; + rect.layerCount = 1; + vkCmdClearAttachments (commandBuffer, attachmentCount, attachments, 1, &rect); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - HL_PRIM vbyte* HL_NAME(hl_locale_get_system_locale) () { + } - std::string* locale = Locale::GetSystemLocale (); - if (!locale) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_attachments) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, hl_varray* state, hl_varray* clear) { - return 0; +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdClearAttachments vkCmdClearAttachments = + (PFN_vkCmdClearAttachments)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdClearAttachments"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + std::vector clearValues = GetHLVulkanDoubleVector (clear); + if (!vkCmdClearAttachments || !commandBuffer || packed.size () < 8 || clearValues.size () < 5) return false; + + VkClearAttachment attachments[2]; + memset (attachments, 0, sizeof (attachments)); + uint32_t attachmentCount = 0; + + if (packed[0] != 0) { + + attachments[attachmentCount].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attachments[attachmentCount].colorAttachment = 0; + attachments[attachmentCount].clearValue.color.float32[0] = (float)clearValues[0]; + attachments[attachmentCount].clearValue.color.float32[1] = (float)clearValues[1]; + attachments[attachmentCount].clearValue.color.float32[2] = (float)clearValues[2]; + attachments[attachmentCount].clearValue.color.float32[3] = (float)clearValues[3]; + attachmentCount++; - } else { + } - int size = locale->size (); - char* _locale = (char*)malloc (size + 1); - strncpy (_locale, locale->c_str (), size); - _locale[size] = '\0'; - delete locale; + if (packed[1] != 0 || packed[2] != 0) { - return (vbyte*)_locale; + attachments[attachmentCount].aspectMask = 0; + if (packed[1] != 0) attachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (packed[2] != 0) attachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + attachments[attachmentCount].clearValue.depthStencil.depth = (float)clearValues[4]; + attachments[attachmentCount].clearValue.depthStencil.stencil = (uint32_t)packed[7]; + attachmentCount++; } - } - + if (attachmentCount == 0) return true; + + VkClearRect rect; + memset (&rect, 0, sizeof (rect)); + rect.rect.offset.x = packed[3]; + rect.rect.offset.y = packed[4]; + rect.rect.extent.width = (uint32_t)packed[5]; + rect.rect.extent.height = (uint32_t)packed[6]; + rect.baseArrayLayer = 0; + rect.layerCount = 1; + vkCmdClearAttachments (commandBuffer, attachmentCount, attachments, 1, &rect); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - value lime_lzma_compress (value buffer, value bytes) { + } - #ifdef LIME_LZMA - Bytes data (buffer); - Bytes result (bytes); - LZMA::Compress (&data, &result); + bool lime_vk_cmd_blit_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, value state) { - return result.Value (bytes); - #else - return alloc_null (); - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBlitImage vkCmdBlitImage = (PFN_vkCmdBlitImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBlitImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdBlitImage || !commandBuffer || packed.size () < 21) return false; + + VkImageBlit blit; + memset (&blit, 0, sizeof (blit)); + blit.srcOffsets[0].x = packed[0]; + blit.srcOffsets[0].y = packed[1]; + blit.srcOffsets[0].z = packed[2]; + blit.srcOffsets[1].x = packed[3]; + blit.srcOffsets[1].y = packed[4]; + blit.srcOffsets[1].z = packed[5]; + blit.dstOffsets[0].x = packed[6]; + blit.dstOffsets[0].y = packed[7]; + blit.dstOffsets[0].z = packed[8]; + blit.dstOffsets[1].x = packed[9]; + blit.dstOffsets[1].y = packed[10]; + blit.dstOffsets[1].z = packed[11]; + int sourceLayout = packed[12]; + int destinationLayout = packed[13]; + int filter = packed[14]; + blit.srcSubresource.mipLevel = (uint32_t)packed[15]; + blit.dstSubresource.mipLevel = (uint32_t)packed[16]; + blit.srcSubresource.baseArrayLayer = (uint32_t)packed[17]; + blit.dstSubresource.baseArrayLayer = (uint32_t)packed[18]; + blit.srcSubresource.layerCount = (uint32_t)packed[19]; + blit.dstSubresource.layerCount = (uint32_t)packed[19]; + blit.srcSubresource.aspectMask = (VkImageAspectFlags)packed[20]; + blit.dstSubresource.aspectMask = (VkImageAspectFlags)packed[20]; + vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)sourceLayout, + (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)destinationLayout, 1, &blit, + (VkFilter)filter); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM Bytes* HL_NAME(hl_lzma_compress) (Bytes* buffer, Bytes* bytes) { + HL_PRIM bool HL_NAME(hl_vk_cmd_blit_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, hl_varray* state) { - #ifdef LIME_LZMA - LZMA::Compress (buffer, bytes); - return bytes; - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdBlitImage vkCmdBlitImage = (PFN_vkCmdBlitImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdBlitImage"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdBlitImage || !commandBuffer || packed.size () < 21) return false; + + VkImageBlit blit; + memset (&blit, 0, sizeof (blit)); + blit.srcOffsets[0].x = packed[0]; + blit.srcOffsets[0].y = packed[1]; + blit.srcOffsets[0].z = packed[2]; + blit.srcOffsets[1].x = packed[3]; + blit.srcOffsets[1].y = packed[4]; + blit.srcOffsets[1].z = packed[5]; + blit.dstOffsets[0].x = packed[6]; + blit.dstOffsets[0].y = packed[7]; + blit.dstOffsets[0].z = packed[8]; + blit.dstOffsets[1].x = packed[9]; + blit.dstOffsets[1].y = packed[10]; + blit.dstOffsets[1].z = packed[11]; + int sourceLayout = packed[12]; + int destinationLayout = packed[13]; + int filter = packed[14]; + blit.srcSubresource.mipLevel = (uint32_t)packed[15]; + blit.dstSubresource.mipLevel = (uint32_t)packed[16]; + blit.srcSubresource.baseArrayLayer = (uint32_t)packed[17]; + blit.dstSubresource.baseArrayLayer = (uint32_t)packed[18]; + blit.srcSubresource.layerCount = (uint32_t)packed[19]; + blit.dstSubresource.layerCount = (uint32_t)packed[19]; + blit.srcSubresource.aspectMask = (VkImageAspectFlags)packed[20]; + blit.dstSubresource.aspectMask = (VkImageAspectFlags)packed[20]; + vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)sourceLayout, + (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)destinationLayout, 1, &blit, + (VkFilter)filter); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - value lime_lzma_decompress (value buffer, value bytes) { - - #ifdef LIME_LZMA - Bytes data (buffer); - Bytes result (bytes); + bool lime_vk_cmd_push_constants (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int layoutHigh, int layoutLow, value state, value bytes) { - LZMA::Decompress (&data, &result); +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdPushConstants vkCmdPushConstants = + (PFN_vkCmdPushConstants)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdPushConstants"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + std::vector packed = GetVulkanIntVector (state); + Bytes data (bytes); + if (!vkCmdPushConstants || !commandBuffer || !layout || !data.b || packed.size () < 4) return false; + if (packed[2] < 0 || packed[3] < 0 || packed[2] + packed[3] > data.length) return false; - return result.Value (bytes); - #else - return alloc_null (); - #endif + vkCmdPushConstants (commandBuffer, layout, (VkShaderStageFlags)packed[0], (uint32_t)packed[1], (uint32_t)packed[3], data.b + packed[2]); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - HL_PRIM Bytes* HL_NAME(hl_lzma_decompress) (Bytes* buffer, Bytes* bytes) { + HL_PRIM bool HL_NAME(hl_vk_cmd_push_constants) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, hl_varray* state, Bytes* bytes) { - #ifdef LIME_LZMA - LZMA::Decompress (buffer, bytes); - return bytes; - #else - return 0; - #endif +#ifdef LIME_VULKAN + Window* targetWindow = (Window*)window->ptr; + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkDevice device = (VkDevice)(uintptr_t)CombineVulkanHandle (deviceHigh, deviceLow); + PFN_vkCmdPushConstants vkCmdPushConstants = + (PFN_vkCmdPushConstants)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdPushConstants"); + VkCommandBuffer commandBuffer = (VkCommandBuffer)(uintptr_t)CombineVulkanHandle (commandBufferHigh, commandBufferLow); + VkPipelineLayout layout = (VkPipelineLayout)(uintptr_t)CombineVulkanHandle (layoutHigh, layoutLow); + std::vector packed = GetHLVulkanIntVector (state); + if (!vkCmdPushConstants || !commandBuffer || !layout || !bytes || !bytes->b || packed.size () < 4) return false; + if (packed[2] < 0 || packed[3] < 0 || packed[2] + packed[3] > bytes->length) return false; + + vkCmdPushConstants (commandBuffer, layout, (VkShaderStageFlags)packed[0], (uint32_t)packed[1], (uint32_t)packed[3], bytes->b + packed[2]); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif } - void lime_mouse_event_manager_register (value callback, value eventObject) { + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { - MouseEvent::callback = new ValuePointer (callback); - MouseEvent::eventObject = new ValuePointer (eventObject); + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + Bytes data (bytes); + bool result = renderer->SetOverlay (data.b, width, height, x, y); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - HL_PRIM void HL_NAME(hl_mouse_event_manager_register) (vclosure* callback, MouseEvent* eventObject) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { - MouseEvent::callback = new ValuePointer (callback); - MouseEvent::eventObject = new ValuePointer ((vobj*)eventObject); + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->SetOverlay (bytes ? bytes->b : 0, width, height, x, y); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - void lime_neko_execute (HxString module) { + bool lime_vulkan_renderer_clear_overlay (value handle) { - #ifdef LIME_NEKO - NekoVM::Execute (module.c_str ()); - #endif + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - void lime_orientation_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { - OrientationEvent::callback = new ValuePointer (callback); - OrientationEvent::eventObject = new ValuePointer (eventObject); - System::EnableDeviceOrientationChange(true); + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - HL_PRIM void HL_NAME(hl_orientation_event_manager_register) (vclosure* callback, OrientationEvent* eventObject) { + bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { - OrientationEvent::callback = new ValuePointer (callback); - OrientationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->Render (red, green, blue, alpha); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - value lime_png_decode_bytes (value data, bool decodeData, value buffer) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { - ImageBuffer imageBuffer (buffer); - Bytes bytes (data); - Resource resource = Resource (&bytes); + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Render (red, green, blue, alpha); + lastVulkanRendererError = renderer->GetLastError (); + return result; - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + bool lime_vulkan_renderer_resize (value handle) { - return alloc_null (); + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { - - Resource resource = Resource (data); - - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer, decodeData)) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { - return buffer; + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; - } - #endif + } +#else + static inline bool LimeVulkanUnavailableBool () { - return 0; + lastVKError = "Lime was built without lime-vulkan support"; + return false; } - value lime_png_decode_file (HxString path, bool decodeData, value buffer) { + static inline value LimeVulkanUnavailableValue () { - ImageBuffer imageBuffer (buffer); - Resource resource = Resource (hxs_utf8 (path, nullptr)); + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + static inline vdynamic* HLLimeVulkanUnavailableValue () { - return alloc_null (); + lastVKError = "Lime was built without lime-vulkan support"; + return 0; } - HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + static inline void LimeVulkanUnavailableVoid () { - Resource resource = Resource (path); + lastVKError = "Lime was built without lime-vulkan support"; - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer, decodeData)) { + } - return buffer; - } - #endif + bool lime_vk_update_descriptor_set_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int setHigh, + int setLow, int binding, int descriptorType, int bufferHigh, int bufferLow, int offset, int range) { - return 0; + return LimeVulkanUnavailableBool (); } - void lime_render_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_set_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int setHigh, int setLow, int binding, int descriptorType, int bufferHigh, int bufferLow, int offset, int range) { - RenderEvent::callback = new ValuePointer (callback); - RenderEvent::eventObject = new ValuePointer (eventObject); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_render_event_manager_register) (vclosure* callback, RenderEvent* eventObject) { + bool lime_vk_update_descriptor_sets (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value writes) { - RenderEvent::callback = new ValuePointer (callback); - RenderEvent::eventObject = new ValuePointer ((vobj*)eventObject); + return LimeVulkanUnavailableBool (); } - void lime_sensor_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_sets) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* writes) { - SensorEvent::callback = new ValuePointer (callback); - SensorEvent::eventObject = new ValuePointer (eventObject); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_sensor_event_manager_register) (vclosure* callback, SensorEvent* eventObject) { + value lime_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, + int pushConstantStages, int pushConstantSize) { - SensorEvent::callback = new ValuePointer (callback); - SensorEvent::eventObject = new ValuePointer ((vobj*)eventObject); + return LimeVulkanUnavailableValue (); } - bool lime_system_get_allow_screen_timeout () { + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* setLayouts, int pushConstantStages, int pushConstantSize) { - return System::GetAllowScreenTimeout (); + return HLLimeVulkanUnavailableValue (); } - HL_PRIM bool HL_NAME(hl_system_get_allow_screen_timeout) () { + void lime_vk_destroy_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { - return System::GetAllowScreenTimeout (); + LimeVulkanUnavailableVoid (); } - value lime_system_get_device_model () { - - std::wstring* model = System::GetDeviceModel (); + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline_layout) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int layoutHigh, int layoutLow) { - if (model) { + LimeVulkanUnavailableVoid (); - value result = alloc_wstring (model->c_str ()); - delete model; - return result; + } - } else { - return alloc_null (); + value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bytes, int byteOffset, + int byteLength) { - } + return LimeVulkanUnavailableValue (); } - HL_PRIM vbyte* HL_NAME(hl_system_get_device_model) () { - - #ifndef EMSCRIPTEN - - std::wstring* model = System::GetDeviceModel (); + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, Bytes* bytes, int byteOffset, int byteLength) { - if (model) { + return HLLimeVulkanUnavailableValue (); - vbyte* const result = hl_wstring_to_utf8_bytes (*model); - delete model; - return result; + } - } - #endif + void lime_vk_destroy_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow) { - return 0; + LimeVulkanUnavailableVoid (); } - value lime_system_get_device_vendor () { - - std::wstring* vendor = System::GetDeviceVendor (); + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int cacheHigh, int cacheLow) { - if (vendor) { + LimeVulkanUnavailableVoid (); - value result = alloc_wstring (vendor->c_str ()); - delete vendor; - return result; + } - } else { - return alloc_null (); + bool lime_vk_get_pipeline_cache_data (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow, value bytes) { - } + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_system_get_device_vendor) () { + HL_PRIM bool HL_NAME(hl_vk_get_pipeline_cache_data) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int cacheHigh, int cacheLow, Bytes* bytes) { - #ifndef EMSCRIPTEN + return LimeVulkanUnavailableBool (); - std::wstring* vendor = System::GetDeviceVendor (); + } - if (vendor) { - vbyte* const result = hl_wstring_to_utf8_bytes (*vendor); - delete vendor; - return result; + value lime_vk_create_graphics_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int renderPassHigh, + int renderPassLow, int layoutHigh, int layoutLow, int vertexShaderHigh, int vertexShaderLow, int fragmentShaderHigh, int fragmentShaderLow, + value state) { - } + return LimeVulkanUnavailableValue (); - #endif + } - return 0; + + HL_PRIM vdynamic* HL_NAME(hl_vk_create_graphics_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int renderPassHigh, int renderPassLow, int layoutHigh, int layoutLow, int vertexShaderHigh, int vertexShaderLow, + int fragmentShaderHigh, int fragmentShaderLow, hl_varray* state) { + + return HLLimeVulkanUnavailableValue (); } - value lime_system_get_directory (int type, HxString company, HxString title) { - - std::wstring* path = System::GetDirectory ((SystemDirectory)type, hxs_utf8 (company, nullptr), hxs_utf8 (title, nullptr)); + void lime_vk_destroy_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int pipelineHigh, + int pipelineLow) { - if (path) { + LimeVulkanUnavailableVoid (); - value result = alloc_wstring (path->c_str ()); - delete path; - return result; + } - } else { - return alloc_null (); + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int pipelineHigh, int pipelineLow) { - } + LimeVulkanUnavailableVoid (); } - HL_PRIM vbyte* HL_NAME(hl_system_get_directory) (int type, hl_vstring* company, hl_vstring* title) { + bool lime_vk_queue_submit_synced (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, + int queueLow, int commandBufferHigh, int commandBufferLow, value state) { - #ifndef EMSCRIPTEN + return LimeVulkanUnavailableBool (); - std::wstring* path = System::GetDirectory ((SystemDirectory)type, company ? (char*)hl_to_utf8 ((const uchar*)company->bytes) : NULL, title ? (char*)hl_to_utf8 ((const uchar*)title->bytes) : NULL); + } - if (path) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + HL_PRIM bool HL_NAME(hl_vk_queue_submit_synced) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int queueHigh, int queueLow, int commandBufferHigh, int commandBufferLow, hl_varray* state) { - } + return LimeVulkanUnavailableBool (); - #endif + } - return 0; + + bool lime_vk_cmd_begin_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int renderPassHigh, int renderPassLow, int framebufferHigh, int framebufferLow, value state, value clear) { + + return LimeVulkanUnavailableBool (); } - value lime_system_get_display (int id) { + HL_PRIM bool HL_NAME(hl_vk_cmd_begin_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int renderPassHigh, int renderPassLow, int framebufferHigh, int framebufferLow, + hl_varray* state, hl_varray* clear) { - return (value)System::GetDisplay (true, id); + return LimeVulkanUnavailableBool (); } - HL_PRIM vdynamic* HL_NAME(hl_system_get_display) (int id) { + bool lime_vk_cmd_end_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow) { - return (vdynamic*)System::GetDisplay (false, id); + return LimeVulkanUnavailableBool (); } - bool lime_system_get_ios_tablet () { + HL_PRIM bool HL_NAME(hl_vk_cmd_end_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow) { - #ifdef IPHONE - return System::GetIOSTablet (); - #else - return false; - #endif + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_system_get_ios_tablet) () { + bool lime_vk_cmd_bind_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int pipelineHigh, int pipelineLow, int bindPoint) { - #ifdef IPHONE - return System::GetIOSTablet (); - #else - return false; - #endif + return LimeVulkanUnavailableBool (); } - int lime_system_get_num_displays () { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int pipelineHigh, int pipelineLow, int bindPoint) { - return System::GetNumDisplays (); + return LimeVulkanUnavailableBool (); } - HL_PRIM int HL_NAME(hl_system_get_num_displays) () { + bool lime_vk_cmd_bind_descriptor_set (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int bindPoint, int firstSet) { - return System::GetNumDisplays (); + return LimeVulkanUnavailableBool (); } - int lime_system_get_device_orientation () { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int bindPoint, + int firstSet) { - return System::GetDeviceOrientation(); + return LimeVulkanUnavailableBool (); } - HL_PRIM int HL_NAME(hl_system_get_device_orientation) () { + bool lime_vk_cmd_bind_descriptor_set_ex (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, value state) { - return System::GetDeviceOrientation(); + return LimeVulkanUnavailableBool (); } - value lime_system_get_platform_label () { - - std::wstring* label = System::GetPlatformLabel (); + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set_ex) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, hl_varray* state) { - if (label) { + return LimeVulkanUnavailableBool (); - value result = alloc_wstring (label->c_str ()); - delete label; - return result; + } - } else { - return alloc_null (); + bool lime_vk_cmd_bind_descriptor_set_dynamic_offset (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, int dynamicOffset, int firstSet, + int bindPoint) { - } + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_system_get_platform_label) () { + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_descriptor_set_dynamic_offset) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, + int deviceHigh, int deviceLow, int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, int setHigh, int setLow, + int dynamicOffset, int firstSet, int bindPoint) { - #ifndef EMSCRIPTEN + return LimeVulkanUnavailableBool (); - std::wstring* label = System::GetPlatformLabel (); + } - if (label) { - vbyte* const result = hl_wstring_to_utf8_bytes (*label); - delete label; - return result; + bool lime_vk_cmd_bind_vertex_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int binding, int offsetHigh, int offsetLow) { - } + return LimeVulkanUnavailableBool (); - #endif + } - return 0; - } + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_vertex_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int binding, int offsetHigh, int offsetLow) { + return LimeVulkanUnavailableBool (); - value lime_system_get_platform_name () { + } - std::wstring* name = System::GetPlatformName (); - if (name) { + bool lime_vk_cmd_bind_index_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int indexType) { - value result = alloc_wstring (name->c_str ()); - delete name; - return result; + return LimeVulkanUnavailableBool (); - } else { + } - return 0; - } + HL_PRIM bool HL_NAME(hl_vk_cmd_bind_index_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int indexType) { + + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_system_get_platform_name) () { + bool lime_vk_cmd_set_viewport (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, double x, double y, double width, double height, double minDepth, double maxDepth) { - #ifndef EMSCRIPTEN + return LimeVulkanUnavailableBool (); - std::wstring* name = System::GetPlatformName (); + } - if (name) { - vbyte* const result = hl_wstring_to_utf8_bytes (*name); - delete name; - return result; + HL_PRIM bool HL_NAME(hl_vk_cmd_set_viewport) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, double x, double y, double width, double height, double minDepth, double maxDepth) { - } + return LimeVulkanUnavailableBool (); - #endif + } - return 0; - } + bool lime_vk_cmd_set_scissor (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int x, int y, int width, int height) { + return LimeVulkanUnavailableBool (); - value lime_system_get_platform_version () { + } - std::wstring* version = System::GetPlatformVersion (); - if (version) { + HL_PRIM bool HL_NAME(hl_vk_cmd_set_scissor) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int x, int y, int width, int height) { - value result = alloc_wstring (version->c_str ()); - delete version; - return result; + return LimeVulkanUnavailableBool (); - } else { + } - return alloc_null (); - } + bool lime_vk_cmd_draw (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - } + return LimeVulkanUnavailableBool (); + } - HL_PRIM vbyte* HL_NAME(hl_system_get_platform_version) () { - #ifndef EMSCRIPTEN + HL_PRIM bool HL_NAME(hl_vk_cmd_draw) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - std::wstring* version = System::GetPlatformVersion (); + return LimeVulkanUnavailableBool (); - if (version) { + } - vbyte* const result = hl_wstring_to_utf8_bytes (*version); - delete version; - return result; - } - #endif + bool lime_vk_cmd_draw_indexed (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) { - return 0; + return LimeVulkanUnavailableBool (); } - double lime_system_get_timer () { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indexed) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) { - return System::GetTimer (); + return LimeVulkanUnavailableBool (); } - HL_PRIM double HL_NAME(hl_system_get_timer) () { + bool lime_vk_cmd_draw_indirect (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - return System::GetTimer (); + return LimeVulkanUnavailableBool (); } - int lime_system_get_windows_console_mode (int handleType) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indirect) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::GetWindowsConsoleMode (handleType); - #else - return 0; - #endif + return LimeVulkanUnavailableBool (); } - HL_PRIM int HL_NAME(hl_system_get_windows_console_mode) (int handleType) { + bool lime_vk_cmd_draw_indexed_indirect (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, int stride) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::GetWindowsConsoleMode (handleType); - #else - return 0; - #endif + return LimeVulkanUnavailableBool (); } - void lime_system_open_file (HxString path) { + HL_PRIM bool HL_NAME(hl_vk_cmd_draw_indexed_indirect) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int offsetHigh, int offsetLow, int drawCount, + int stride) { - #ifdef IPHONE - System::OpenFile (path.c_str ()); - #endif + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_system_open_file) (vbyte* path) { + bool lime_vk_cmd_copy_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, value state) { - #ifdef IPHONE - System::OpenFile ((char*)path); - #endif + return LimeVulkanUnavailableBool (); } - void lime_system_open_url (HxString url, HxString target) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, hl_varray* state) { - #ifdef IPHONE - System::OpenURL (url.c_str (), target.c_str ()); - #endif + return LimeVulkanUnavailableBool (); } + bool lime_vk_cmd_copy_buffer_to_image_region (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, value state) { - HL_PRIM void HL_NAME(hl_system_open_url) (vbyte* url, vbyte* target) { - - #ifdef IPHONE - System::OpenURL ((char*)url, (char*)target); - #endif + return LimeVulkanUnavailableBool (); } - bool lime_system_set_allow_screen_timeout (bool allow) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image_region) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, hl_varray* state) { - return System::SetAllowScreenTimeout (allow); + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_system_set_allow_screen_timeout) (bool allow) { + bool lime_vk_cmd_copy_image_to_buffer_region (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int bufferHigh, int bufferLow, value state) { - return System::SetAllowScreenTimeout (allow); + return LimeVulkanUnavailableBool (); } - bool lime_system_set_windows_console_mode (int handleType, int mode) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_image_to_buffer_region) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int bufferHigh, int bufferLow, hl_varray* state) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::SetWindowsConsoleMode (handleType, mode); - #else - return false; - #endif + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_system_set_windows_console_mode) (int handleType, int mode) { + bool lime_vk_cmd_pipeline_barrier_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, value state) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::SetWindowsConsoleMode (handleType, mode); - #else - return false; - #endif + return LimeVulkanUnavailableBool (); } - void lime_text_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vk_cmd_pipeline_barrier_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, hl_varray* state) { - TextEvent::callback = new ValuePointer (callback); - TextEvent::eventObject = new ValuePointer (eventObject); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_text_event_manager_register) (vclosure* callback, TextEvent* eventObject) { + bool lime_vk_cmd_clear_color_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int imageHigh, int imageLow, int layout, int aspectMask, value clear) { - TextEvent::callback = new ValuePointer (callback); - TextEvent::eventObject = new ValuePointer ((vobj*)eventObject); + return LimeVulkanUnavailableBool (); } - void lime_touch_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_color_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, int layout, int aspectMask, hl_varray* clear) { - TouchEvent::callback = new ValuePointer (callback); - TouchEvent::eventObject = new ValuePointer (eventObject); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_touch_event_manager_register) (vclosure* callback, TouchEvent* eventObject) { + bool lime_vk_cmd_clear_depth_stencil_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, value state, value clear) { - TouchEvent::callback = new ValuePointer (callback); - TouchEvent::eventObject = new ValuePointer ((vobj*)eventObject); + return LimeVulkanUnavailableBool (); } - void lime_window_alert (value window, HxString message, HxString title) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_depth_stencil_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int imageHigh, int imageLow, hl_varray* state, hl_varray* clear) { - Window* targetWindow = (Window*)val_data (window); - targetWindow->Alert (hxs_utf8 (message, nullptr), hxs_utf8 (title, nullptr)); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_window_alert) (HL_CFFIPointer* window, hl_vstring* message, hl_vstring* title) { + bool lime_vk_cmd_clear_attachments (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, value state, value clear) { - Window* targetWindow = (Window*)window->ptr; - const char *cmessage = message ? hl_to_utf8(message->bytes) : nullptr; - const char *ctitle = title ? hl_to_utf8(title->bytes) : nullptr; - targetWindow->Alert (cmessage, ctitle); + return LimeVulkanUnavailableBool (); } - void lime_window_close (value window) { + HL_PRIM bool HL_NAME(hl_vk_cmd_clear_attachments) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, hl_varray* state, hl_varray* clear) { - Window* targetWindow = (Window*)val_data (window); - targetWindow->Close (); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_window_close) (HL_CFFIPointer* window) { + bool lime_vk_cmd_blit_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, value state) { - Window* targetWindow = (Window*)window->ptr; - targetWindow->Close (); + return LimeVulkanUnavailableBool (); } - void lime_window_context_flip (value window) { + HL_PRIM bool HL_NAME(hl_vk_cmd_blit_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int sourceHigh, int sourceLow, int destinationHigh, int destinationLow, hl_varray* state) { - ((Window*)val_data (window))->ContextFlip (); + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_window_context_flip) (HL_CFFIPointer* window) { + bool lime_vk_cmd_push_constants (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, int layoutHigh, int layoutLow, value state, value bytes) { - ((Window*)window->ptr)->ContextFlip (); + return LimeVulkanUnavailableBool (); } - value lime_window_context_lock (value window) { + HL_PRIM bool HL_NAME(hl_vk_cmd_push_constants) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int layoutHigh, int layoutLow, hl_varray* state, Bytes* bytes) { - return (value)((Window*)val_data (window))->ContextLock (true); + return LimeVulkanUnavailableBool (); } - HL_PRIM vdynamic* HL_NAME(hl_window_context_lock) (HL_CFFIPointer* window) { + value lime_vulkan_renderer_create (value window, HxString applicationName) { - return (vdynamic*)((Window*)window->ptr)->ContextLock (false); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return alloc_null (); } - void lime_window_context_make_current (value window) { + HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { - ((Window*)val_data (window))->ContextMakeCurrent (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return 0; } - HL_PRIM void HL_NAME(hl_window_context_make_current) (HL_CFFIPointer* window) { + void lime_vulkan_renderer_destroy (value handle) {} - ((Window*)window->ptr)->ContextMakeCurrent (); - } + HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) {} - void lime_window_context_unlock (value window) { + value lime_vulkan_renderer_get_info (value handle) { - ((Window*)val_data (window))->ContextUnlock (); + return alloc_string (""); } - HL_PRIM void HL_NAME(hl_window_context_unlock) (HL_CFFIPointer* window) { + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { - ((Window*)window->ptr)->ContextUnlock (); + return hl_copy_bytes ((const vbyte*)"", 1); } - value lime_window_create (value application, int width, int height, int flags, HxString title) { + value lime_vulkan_renderer_get_last_error () { - Window* window = CreateWindow ((Application*)val_data (application), width, height, flags, hxs_utf8 (title, nullptr)); - return CFFIPointer (window, gc_window); + return alloc_string (lastVulkanRendererError.c_str ()); } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_window_create) (HL_CFFIPointer* application, int width, int height, int flags, hl_vstring* title) { + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { - Window* window = CreateWindow ((Application*)application->ptr, width, height, flags, (const char*)hl_to_utf8 ((const uchar*)title->bytes)); - return HLCFFIPointer (window, (hl_finalizer)hl_gc_window); + return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); } - void lime_window_event_manager_register (value callback, value eventObject) { + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { - WindowEvent::callback = new ValuePointer (callback); - WindowEvent::eventObject = new ValuePointer (eventObject); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - HL_PRIM void HL_NAME(hl_window_event_manager_register) (vclosure* callback, WindowEvent* eventObject) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { - WindowEvent::callback = new ValuePointer (callback); - WindowEvent::eventObject = new ValuePointer ((vobj*)eventObject); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - void lime_window_focus (value window) { + bool lime_vulkan_renderer_clear_overlay (value handle) { - Window* targetWindow = (Window*)val_data (window); - targetWindow->Focus (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - HL_PRIM void HL_NAME(hl_window_focus) (HL_CFFIPointer* window) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { - Window* targetWindow = (Window*)window->ptr; - targetWindow->Focus (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - double lime_window_get_context (value window) { + bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { - Window* targetWindow = (Window*)val_data (window); - return (uintptr_t)targetWindow->GetContext (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - HL_PRIM double HL_NAME(hl_window_get_context) (HL_CFFIPointer* window) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { - Window* targetWindow = (Window*)window->ptr; - return (uintptr_t)targetWindow->GetContext (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - value lime_window_get_context_type (value window) { + bool lime_vulkan_renderer_resize (value handle) { - Window* targetWindow = (Window*)val_data (window); - const char* type = targetWindow->GetContextType (); - return type ? alloc_string (type) : alloc_null (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } - HL_PRIM vbyte* HL_NAME(hl_window_get_context_type) (HL_CFFIPointer* window) { + HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { - Window* targetWindow = (Window*)window->ptr; - return (vbyte*)targetWindow->GetContextType (); + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; } +#endif int lime_window_get_display (value window) { @@ -4297,6 +13455,7 @@ namespace lime { DEFINE_PRIME1v (lime_window_focus); DEFINE_PRIME1 (lime_window_get_context); DEFINE_PRIME1 (lime_window_get_context_type); + DEFINE_PRIME3 (lime_window_create_vulkan_surface); DEFINE_PRIME1 (lime_window_get_display); DEFINE_PRIME1 (lime_window_get_display_mode); DEFINE_PRIME1 (lime_window_get_height); @@ -4304,6 +13463,114 @@ namespace lime { DEFINE_PRIME1 (lime_window_get_mouse_lock); DEFINE_PRIME1 (lime_window_get_scale); DEFINE_PRIME1 (lime_window_get_text_input_enabled); + DEFINE_PRIME1 (lime_window_get_vulkan_drawable_size); + DEFINE_PRIME1 (lime_window_get_vulkan_instance_extensions); + DEFINE_PRIME1 (lime_window_get_vulkan_instance_proc_addr); + DEFINE_PRIME2 (lime_vk_create_instance); + DEFINE_PRIME3v (lime_vk_destroy_instance); + DEFINE_PRIME5v (lime_vk_destroy_surface); + DEFINE_PRIME5 (lime_vk_get_physical_devices); + DEFINE_PRIME7 (lime_vk_create_device); + DEFINE_PRIME5v (lime_vk_destroy_device); + DEFINE_PRIME5 (lime_vk_device_wait_idle); + DEFINE_PRIME7 (lime_vk_queue_wait_idle); + DEFINE_PRIME7 (lime_vk_create_command_pool); + DEFINE_PRIME7v (lime_vk_destroy_command_pool); + DEFINE_PRIME8 (lime_vk_reset_command_pool); + DEFINE_PRIME8 (lime_vk_allocate_command_buffer); + DEFINE_PRIME9v (lime_vk_free_command_buffer); + DEFINE_PRIME8 (lime_vk_begin_command_buffer); + DEFINE_PRIME7 (lime_vk_end_command_buffer); + DEFINE_PRIME8 (lime_vk_reset_command_buffer); + DEFINE_PRIME5 (lime_vk_create_semaphore); + DEFINE_PRIME7v (lime_vk_destroy_semaphore); + DEFINE_PRIME6 (lime_vk_create_fence); + DEFINE_PRIME7v (lime_vk_destroy_fence); + DEFINE_PRIME9 (lime_vk_wait_for_fence); + DEFINE_PRIME7 (lime_vk_reset_fence); + DEFINE_PRIME11 (lime_vk_queue_submit); + DEFINE_PRIME11 (lime_vk_allocate_memory); + DEFINE_PRIME7v (lime_vk_free_memory); + DEFINE_PRIME12 (lime_vk_upload_memory); + DEFINE_PRIME12 (lime_vk_download_memory); + DEFINE_PRIME12 (lime_vk_map_memory); + DEFINE_PRIME7v (lime_vk_unmap_memory); + DEFINE_PRIME12 (lime_vk_write_mapped_memory); + DEFINE_PRIME11 (lime_vk_flush_mapped_memory); + DEFINE_PRIME11 (lime_vk_invalidate_mapped_memory); + DEFINE_PRIME8 (lime_vk_create_buffer); + DEFINE_PRIME7v (lime_vk_destroy_buffer); + DEFINE_PRIME7 (lime_vk_get_buffer_memory_requirements); + DEFINE_PRIME11 (lime_vk_bind_buffer_memory); + DEFINE_PRIME15 (lime_vk_create_image); + DEFINE_PRIME7v (lime_vk_destroy_image); + DEFINE_PRIME7 (lime_vk_get_image_memory_requirements); + DEFINE_PRIME11 (lime_vk_bind_image_memory); + DEFINE_PRIME15 (lime_vk_create_swapchain); + DEFINE_PRIME7v (lime_vk_destroy_swapchain); + DEFINE_PRIME7 (lime_vk_get_swapchain_images); + DEFINE_PRIME13 (lime_vk_acquire_next_image); + DEFINE_PRIME12 (lime_vk_queue_present); + DEFINE_PRIME10 (lime_vk_create_image_view); + DEFINE_PRIME7v (lime_vk_destroy_image_view); + DEFINE_PRIME14 (lime_vk_create_image_view_ex); + DEFINE_PRIME6 (lime_vk_create_render_pass); + DEFINE_PRIME7v (lime_vk_destroy_render_pass); + DEFINE_PRIME11 (lime_vk_create_framebuffer); + DEFINE_PRIME7v (lime_vk_destroy_framebuffer); + DEFINE_PRIME8 (lime_vk_create_shader_module); + DEFINE_PRIME7v (lime_vk_destroy_shader_module); + DEFINE_PRIME13 (lime_vk_create_sampler); + DEFINE_PRIME7v (lime_vk_destroy_sampler); + DEFINE_PRIME6 (lime_vk_create_descriptor_set_layout); + DEFINE_PRIME7v (lime_vk_destroy_descriptor_set_layout); + DEFINE_PRIME6 (lime_vk_create_descriptor_pool); + DEFINE_PRIME7v (lime_vk_destroy_descriptor_pool); + DEFINE_PRIME8 (lime_vk_reset_descriptor_pool); + DEFINE_PRIME9 (lime_vk_allocate_descriptor_set); + DEFINE_PRIME14 (lime_vk_update_descriptor_set_image); + DEFINE_PRIME13 (lime_vk_update_descriptor_set_buffer); + DEFINE_PRIME6 (lime_vk_update_descriptor_sets); + DEFINE_PRIME8 (lime_vk_create_pipeline_layout); + DEFINE_PRIME7v (lime_vk_destroy_pipeline_layout); + DEFINE_PRIME8 (lime_vk_create_pipeline_cache); + DEFINE_PRIME7v (lime_vk_destroy_pipeline_cache); + DEFINE_PRIME8 (lime_vk_get_pipeline_cache_data); + DEFINE_PRIME14 (lime_vk_create_graphics_pipeline); + DEFINE_PRIME7v (lime_vk_destroy_pipeline); + DEFINE_PRIME10 (lime_vk_queue_submit_synced); + DEFINE_PRIME13 (lime_vk_cmd_begin_render_pass); + DEFINE_PRIME7 (lime_vk_cmd_end_render_pass); + DEFINE_PRIME10 (lime_vk_cmd_bind_pipeline); + DEFINE_PRIME13 (lime_vk_cmd_bind_descriptor_set); + DEFINE_PRIME12 (lime_vk_cmd_bind_descriptor_set_ex); + DEFINE_PRIME14 (lime_vk_cmd_bind_descriptor_set_dynamic_offset); + DEFINE_PRIME12 (lime_vk_cmd_bind_vertex_buffer); + DEFINE_PRIME12 (lime_vk_cmd_bind_index_buffer); + DEFINE_PRIME13 (lime_vk_cmd_set_viewport); + DEFINE_PRIME11 (lime_vk_cmd_set_scissor); + DEFINE_PRIME11 (lime_vk_cmd_draw); + DEFINE_PRIME12 (lime_vk_cmd_draw_indexed); + DEFINE_PRIME13 (lime_vk_cmd_draw_indirect); + DEFINE_PRIME13 (lime_vk_cmd_draw_indexed_indirect); + DEFINE_PRIME12 (lime_vk_cmd_copy_buffer); + DEFINE_PRIME12 (lime_vk_cmd_copy_buffer_to_image_region); + DEFINE_PRIME12 (lime_vk_cmd_copy_image_to_buffer_region); + DEFINE_PRIME10 (lime_vk_cmd_pipeline_barrier_image); + DEFINE_PRIME12 (lime_vk_cmd_clear_color_image); + DEFINE_PRIME11 (lime_vk_cmd_clear_depth_stencil_image); + DEFINE_PRIME9 (lime_vk_cmd_clear_attachments); + DEFINE_PRIME12 (lime_vk_cmd_blit_image); + DEFINE_PRIME11 (lime_vk_cmd_push_constants); + DEFINE_PRIME0 (lime_vk_get_last_error); + DEFINE_PRIME2 (lime_vulkan_renderer_create); + DEFINE_PRIME1v (lime_vulkan_renderer_destroy); + DEFINE_PRIME1 (lime_vulkan_renderer_get_info); + DEFINE_PRIME0 (lime_vulkan_renderer_get_last_error); + DEFINE_PRIME6 (lime_vulkan_renderer_set_overlay); + DEFINE_PRIME1 (lime_vulkan_renderer_clear_overlay); + DEFINE_PRIME5 (lime_vulkan_renderer_render); + DEFINE_PRIME1 (lime_vulkan_renderer_resize); DEFINE_PRIME1 (lime_window_get_width); DEFINE_PRIME1 (lime_window_get_x); DEFINE_PRIME1 (lime_window_get_y); @@ -4341,9 +13608,9 @@ namespace lime { #define _TCLIPBOARD_EVENT _OBJ (_I32) #define _TDISPLAYMODE _OBJ (_I32 _I32 _I32 _I32) #define _TDROP_EVENT _OBJ (_BYTES _I32) - #define _TGAMEPAD_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64) + #define _TGAMEPAD_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64 _I32) #define _TJOYSTICK_EVENT _OBJ (_I32 _I32 _I32 _I32 _F64 _F64) - #define _TKEY_EVENT _OBJ (_F64 _I32 _I32 _I32) + #define _TKEY_EVENT _OBJ (_F64 _I32 _I32 _I32 _I32) #define _TMOUSE_EVENT _OBJ (_I32 _F64 _F64 _I32 _I32 _F64 _F64 _I32) #define _TORIENTATION_EVENT _OBJ (_I32 _I32 _I32) #define _TRECTANGLE _OBJ (_F64 _F64 _F64 _F64) @@ -4357,7 +13624,7 @@ namespace lime { #define _TARRAYBUFFER _TBYTES #define _TARRAYBUFFERVIEW _OBJ (_I32 _TARRAYBUFFER _I32 _I32 _I32 _I32) - #define _TAUDIOBUFFER _OBJ (_I32 _I32 _TARRAYBUFFERVIEW _I32 _DYN _DYN _DYN _DYN _BOOL _DYN _TBYTES _BOOL _I32 _STRING _TBYTES _STRING _TVORBISFILE) + #define _TAUDIOBUFFER _OBJ (_I32 _I32 _TARRAYBUFFERVIEW _I32 _DYN _DYN _I32 _DYN _DYN _BOOL _DYN _TBYTES _BOOL _I32 _STRING _TBYTES _STRING _TVORBISFILE) #define _TIMAGEBUFFER _OBJ (_I32 _TARRAYBUFFERVIEW _I32 _I32 _BOOL _BOOL _I32 _DYN _DYN _DYN _DYN _DYN _DYN) #define _TIMAGE _OBJ (_TIMAGEBUFFER _BOOL _I32 _I32 _I32 _TRECTANGLE _ENUM _I32 _I32 _F64 _F64) @@ -4496,6 +13763,7 @@ namespace lime { DEFINE_HL_PRIM (_VOID, hl_window_focus, _TCFFIPOINTER); DEFINE_HL_PRIM (_F64, hl_window_get_context, _TCFFIPOINTER); DEFINE_HL_PRIM (_BYTES, hl_window_get_context_type, _TCFFIPOINTER); + DEFINE_HL_PRIM (_DYN, hl_window_create_vulkan_surface, _TCFFIPOINTER _I32 _I32); DEFINE_HL_PRIM (_I32, hl_window_get_display, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_window_get_display_mode, _TCFFIPOINTER _TDISPLAYMODE); DEFINE_HL_PRIM (_I32, hl_window_get_height, _TCFFIPOINTER); @@ -4503,6 +13771,114 @@ namespace lime { DEFINE_HL_PRIM (_BOOL, hl_window_get_mouse_lock, _TCFFIPOINTER); DEFINE_HL_PRIM (_F64, hl_window_get_scale, _TCFFIPOINTER); DEFINE_HL_PRIM (_BOOL, hl_window_get_text_input_enabled, _TCFFIPOINTER); + DEFINE_HL_PRIM (_DYN, hl_window_get_vulkan_drawable_size, _TCFFIPOINTER); + DEFINE_HL_PRIM (_ARR, hl_window_get_vulkan_instance_extensions, _TCFFIPOINTER); + DEFINE_HL_PRIM (_DYN, hl_window_get_vulkan_instance_proc_addr, _TCFFIPOINTER); + DEFINE_HL_PRIM (_DYN, hl_vk_create_instance, _TCFFIPOINTER _STRING); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_instance, _TCFFIPOINTER _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_surface, _TCFFIPOINTER _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_ARR, hl_vk_get_physical_devices, _TCFFIPOINTER _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_device, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_device, _TCFFIPOINTER _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_device_wait_idle, _TCFFIPOINTER _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_queue_wait_idle, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_command_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_command_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_reset_command_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_allocate_command_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_free_command_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_begin_command_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_end_command_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_reset_command_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_semaphore, _TCFFIPOINTER _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_semaphore, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_fence, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_fence, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_wait_for_fence, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_reset_fence, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_queue_submit, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_allocate_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_free_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_upload_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_download_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_map_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_unmap_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_write_mapped_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_flush_mapped_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_invalidate_mapped_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_get_buffer_memory_requirements, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_bind_buffer_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_get_image_memory_requirements, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_bind_image_memory, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_swapchain, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_swapchain, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_ARR, hl_vk_get_swapchain_images, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_acquire_next_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_I32, hl_vk_queue_present, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_image_view, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_image_view, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_image_view_ex, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_render_pass, _TCFFIPOINTER _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_render_pass, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_framebuffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _ARR _I32 _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_framebuffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_shader_module, _TCFFIPOINTER _I32 _I32 _I32 _I32 _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_shader_module, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_sampler, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _BOOL _F64 _I32 _F64 _F64); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_sampler, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_descriptor_set_layout, _TCFFIPOINTER _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_descriptor_set_layout, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_descriptor_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_descriptor_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_reset_descriptor_pool, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_allocate_descriptor_set, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_update_descriptor_set_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_update_descriptor_set_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_update_descriptor_sets, _TCFFIPOINTER _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_DYN, hl_vk_create_pipeline_layout, _TCFFIPOINTER _I32 _I32 _I32 _I32 _ARR _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_pipeline_layout, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_DYN, hl_vk_create_pipeline_cache, _TCFFIPOINTER _I32 _I32 _I32 _I32 _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_pipeline_cache, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_get_pipeline_cache_data, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _TBYTES); + DEFINE_HL_PRIM (_DYN, hl_vk_create_graphics_pipeline, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_VOID, hl_vk_destroy_pipeline, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_queue_submit_synced, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_begin_render_pass, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_end_render_pass, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_pipeline, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_descriptor_set, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_descriptor_set_ex, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_descriptor_set_dynamic_offset, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_vertex_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_bind_index_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_set_viewport, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _F64 _F64 _F64 _F64 _F64 _F64); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_set_scissor, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_draw, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_draw_indexed, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_draw_indirect, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_draw_indexed_indirect, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_copy_buffer, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_copy_buffer_to_image_region, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_copy_image_to_buffer_region, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_pipeline_barrier_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_clear_color_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_clear_depth_stencil_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_clear_attachments, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _ARR _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_blit_image, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR); + DEFINE_HL_PRIM (_BOOL, hl_vk_cmd_push_constants, _TCFFIPOINTER _I32 _I32 _I32 _I32 _I32 _I32 _I32 _I32 _ARR _TBYTES); + DEFINE_HL_PRIM (_BYTES, hl_vk_get_last_error, _NO_ARG); + DEFINE_HL_PRIM (_TCFFIPOINTER, hl_vulkan_renderer_create, _TCFFIPOINTER _STRING); + DEFINE_HL_PRIM (_VOID, hl_vulkan_renderer_destroy, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BYTES, hl_vulkan_renderer_get_info, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BYTES, hl_vulkan_renderer_get_last_error, _NO_ARG); + DEFINE_HL_PRIM (_BOOL, hl_vulkan_renderer_set_overlay, _TCFFIPOINTER _TBYTES _I32 _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_vulkan_renderer_clear_overlay, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_vulkan_renderer_render, _TCFFIPOINTER _F64 _F64 _F64 _F64); + DEFINE_HL_PRIM (_BOOL, hl_vulkan_renderer_resize, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_window_get_width, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_window_get_x, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_window_get_y, _TCFFIPOINTER); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 821648774e..5b089f52b2 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -826,6 +826,7 @@ namespace lime gamepadEvent.type = GAMEPAD_AXIS_MOVE; gamepadEvent.axis = event->caxis.axis; gamepadEvent.id = event->caxis.which; + gamepadEvent.timestamp = event->common.timestamp; if (event->caxis.value > -analogAxisDeadZone && event->caxis.value < analogAxisDeadZone) { @@ -852,6 +853,7 @@ namespace lime gamepadEvent.type = GAMEPAD_BUTTON_DOWN; gamepadEvent.button = event->cbutton.button; gamepadEvent.id = event->cbutton.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch(&gamepadEvent); break; @@ -861,6 +863,7 @@ namespace lime gamepadEvent.type = GAMEPAD_BUTTON_UP; gamepadEvent.button = event->cbutton.button; gamepadEvent.id = event->cbutton.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch(&gamepadEvent); break; @@ -872,6 +875,7 @@ namespace lime gamepadEvent.type = GAMEPAD_CONNECT; gamepadEvent.id = SDLGamepad::GetInstanceID(event->cdevice.which); + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch(&gamepadEvent); } @@ -883,6 +887,7 @@ namespace lime gamepadEvent.type = GAMEPAD_DISCONNECT; gamepadEvent.id = event->cdevice.which; + gamepadEvent.timestamp = event->common.timestamp; GamepadEvent::Dispatch(&gamepadEvent); SDLGamepad::Disconnect(event->cdevice.which); @@ -1002,6 +1007,7 @@ namespace lime keyEvent.keyCode = event->key.keysym.sym; keyEvent.modifier = event->key.keysym.mod; + keyEvent.timestamp = event->common.timestamp; keyEvent.windowID = event->key.windowID; if (keyEvent.type == KEY_DOWN) diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index 07cd39693b..d38ce8ae4a 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -189,6 +189,43 @@ namespace lime { RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_TICK_PROP); } + + static bool EnableTransparentWindow (SDL_Window* sdlWindow) { + + if (!sdlWindow) return false; + + SDL_SysWMinfo wminfo; + SDL_VERSION (&wminfo.version); + if (SDL_GetWindowWMInfo (sdlWindow, &wminfo) != 1) return false; + + HWND hwnd = wminfo.info.win.window; + if (!hwnd) return false; + + typedef struct { + int leftWidth; + int rightWidth; + int topHeight; + int bottomHeight; + } DwmMargins; + typedef HRESULT (WINAPI *DwmExtendFrameIntoClientAreaFunc) (HWND hwnd, const DwmMargins* margins); + + HMODULE dwmapi = LoadLibraryW (L"dwmapi.dll"); + if (!dwmapi) return false; + + DwmExtendFrameIntoClientAreaFunc extendFrame = (DwmExtendFrameIntoClientAreaFunc)GetProcAddress (dwmapi, "DwmExtendFrameIntoClientArea"); + bool enabled = false; + + if (extendFrame) { + + DwmMargins margins = { -1, -1, -1, -1 }; + enabled = SUCCEEDED (extendFrame (hwnd, &margins)); + + } + + FreeLibrary (dwmapi); + return enabled; + + } #endif @@ -199,6 +236,7 @@ namespace lime { sdlTexture = 0; sdlRenderer = 0; context = 0; + useVulkan = (flags & WINDOW_FLAG_VULKAN) != 0; contextWidth = 0; contextHeight = 0; @@ -240,9 +278,25 @@ namespace lime { SDL_SetHint (SDL_HINT_TOUCH_MOUSE_EVENTS, "1"); #endif + if (flags & WINDOW_FLAG_TRANSPARENT) { + + #ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY + SDL_SetHint (SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1"); + #endif + + } + if (flags & WINDOW_FLAG_HARDWARE) { - sdlWindowFlags |= SDL_WINDOW_OPENGL; + if (useVulkan) { + + sdlWindowFlags |= SDL_WINDOW_VULKAN; + + } else { + + sdlWindowFlags |= SDL_WINDOW_OPENGL; + + } if (flags & WINDOW_FLAG_ALLOW_HIGHDPI) { @@ -250,61 +304,65 @@ namespace lime { } - #if defined (HX_WINDOWS) && defined (NATIVE_TOOLKIT_SDL_ANGLE) - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_SetHint (SDL_HINT_VIDEO_WIN_D3DCOMPILER, "d3dcompiler_47.dll"); - #endif + if (!useVulkan) { - #if defined (RASPBERRYPI) - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengles2"); - #endif + #if defined (HX_WINDOWS) && defined (NATIVE_TOOLKIT_SDL_ANGLE) + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_SetHint (SDL_HINT_VIDEO_WIN_D3DCOMPILER, "d3dcompiler_47.dll"); + #endif - #if defined (IPHONE) || defined (APPLETV) - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3); - #endif + #if defined (RASPBERRYPI) + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengles2"); + #endif - if (flags & WINDOW_FLAG_DEPTH_BUFFER) { + #if defined (IPHONE) || defined (APPLETV) + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3); + #endif - SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 32 - (flags & WINDOW_FLAG_STENCIL_BUFFER) ? 8 : 0); + if (flags & WINDOW_FLAG_DEPTH_BUFFER) { - } + SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 32 - (flags & WINDOW_FLAG_STENCIL_BUFFER) ? 8 : 0); - if (flags & WINDOW_FLAG_STENCIL_BUFFER) { + } - SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); + if (flags & WINDOW_FLAG_STENCIL_BUFFER) { - } + SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); - if (flags & WINDOW_FLAG_HW_AA_HIRES) { + } - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 4); + if (flags & WINDOW_FLAG_HW_AA_HIRES) { - } else if (flags & WINDOW_FLAG_HW_AA) { + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 4); - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 2); + } else if (flags & WINDOW_FLAG_HW_AA) { - } + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 2); - if (flags & WINDOW_FLAG_COLOR_DEPTH_32_BIT) { + } - SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8); + if (flags & (WINDOW_FLAG_COLOR_DEPTH_32_BIT | WINDOW_FLAG_TRANSPARENT)) { - } else { + SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8); + + } else { - SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 6); - SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 6); + SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5); + + } } @@ -313,7 +371,7 @@ namespace lime { sdlWindow = SDL_CreateWindow (title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, sdlWindowFlags); #if defined (IPHONE) || defined (APPLETV) - if (sdlWindow && !SDL_GL_CreateContext (sdlWindow)) { + if (!useVulkan && sdlWindow && !SDL_GL_CreateContext (sdlWindow)) { SDL_DestroyWindow (sdlWindow); SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2); @@ -332,6 +390,12 @@ namespace lime { #if defined (HX_WINDOWS) && !defined (HX_WINRT) InstallResizeEventHook (sdlWindow); + + if ((flags & WINDOW_FLAG_TRANSPARENT) && !useVulkan) { + + EnableTransparentWindow (sdlWindow); + + } #endif #if defined (HX_WINDOWS) && !defined (HX_WINRT) @@ -362,7 +426,7 @@ namespace lime { int sdlRendererFlags = 0; - if (flags & WINDOW_FLAG_HARDWARE) { + if ((flags & WINDOW_FLAG_HARDWARE) && !useVulkan) { sdlRendererFlags |= SDL_RENDERER_ACCELERATED; @@ -430,7 +494,7 @@ namespace lime { } - if (!context) { + if (!context && !useVulkan) { sdlRendererFlags &= ~SDL_RENDERER_ACCELERATED; sdlRendererFlags &= ~SDL_RENDERER_PRESENTVSYNC; @@ -441,7 +505,7 @@ namespace lime { } - if (context || sdlRenderer) { + if (context || sdlRenderer || useVulkan) { ((SDLApplication*)currentApplication)->RegisterWindow (this); @@ -462,6 +526,24 @@ namespace lime { } + if (sdlRenderer) { + + SDL_DestroyRenderer (sdlRenderer); + sdlRenderer = 0; + + } else if (context) { + + if (SDL_GL_GetCurrentContext () == context) { + + SDL_GL_MakeCurrent (sdlWindow, NULL); + + } + + SDL_GL_DeleteContext (context); + context = 0; + + } + if (sdlWindow) { #if defined (HX_WINDOWS) && !defined (HX_WINRT) @@ -473,16 +555,6 @@ namespace lime { } - if (sdlRenderer) { - - SDL_DestroyRenderer (sdlRenderer); - - } else if (context) { - - SDL_GL_DeleteContext (context); - - } - } @@ -531,6 +603,24 @@ namespace lime { RestoreResizeEventHook (sdlWindow); #endif + if (sdlRenderer) { + + SDL_DestroyRenderer (sdlRenderer); + sdlRenderer = 0; + + } else if (context) { + + if (SDL_GL_GetCurrentContext () == context) { + + SDL_GL_MakeCurrent (sdlWindow, NULL); + + } + + SDL_GL_DeleteContext (context); + context = 0; + + } + SDL_DestroyWindow (sdlWindow); sdlWindow = 0; @@ -558,6 +648,12 @@ namespace lime { void SDLWindow::ContextFlip () { + if (useVulkan) { + + return; + + } + if (context && !sdlRenderer) { SDL_GL_SwapWindow (sdlWindow); @@ -578,6 +674,13 @@ namespace lime { } + int SDLWindow::GetRequestedVSyncMode () const { + + return requestedVSyncMode; + + } + + double SDLWindow::GetRefreshRate () const { if (!sdlWindow) { @@ -605,6 +708,72 @@ namespace lime { } + uint64_t SDLWindow::CreateVulkanSurface (uintptr_t instance) { + + if (!useVulkan || !instance) { + + return 0; + + } + + SDL_vulkanSurface surface = 0; + if (SDL_Vulkan_CreateSurface (sdlWindow, (SDL_vulkanInstance)instance, &surface) != SDL_TRUE) { + + return 0; + + } + + #if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + return (uint64_t)(uintptr_t)surface; + #else + return (uint64_t)surface; + #endif + + } + + + void SDLWindow::GetVulkanDrawableSize (int* width, int* height) { + + if (!useVulkan) { + + if (width) *width = 0; + if (height) *height = 0; + return; + + } + + SDL_Vulkan_GetDrawableSize (sdlWindow, width, height); + + } + + + bool SDLWindow::GetVulkanInstanceExtensions (unsigned int* count, const char** names) { + + if (!useVulkan) { + + if (count) *count = 0; + return false; + + } + + return SDL_Vulkan_GetInstanceExtensions (sdlWindow, count, names) == SDL_TRUE; + + } + + + void* SDLWindow::GetVulkanInstanceProcAddr () { + + if (!useVulkan) { + + return 0; + + } + + return SDL_Vulkan_GetVkGetInstanceProcAddr (); + + } + + void* SDLWindow::ContextLock (bool useCFFIValue) { if (sdlRenderer) { @@ -692,6 +861,12 @@ namespace lime { void SDLWindow::ContextMakeCurrent () { + if (useVulkan) { + + return; + + } + if (sdlWindow && context) { SDL_GL_MakeCurrent (sdlWindow, context); @@ -723,6 +898,12 @@ namespace lime { void* SDLWindow::GetContext () { + if (useVulkan) { + + return sdlWindow; + + } + return context; } @@ -730,6 +911,12 @@ namespace lime { const char* SDLWindow::GetContextType () { + if (useVulkan) { + + return "vulkan"; + + } + if (context) { return "opengl"; @@ -1333,6 +1520,35 @@ namespace lime { requestedVSyncMode = vsyncMode; activeSwapInterval = 0; + if (useVulkan) { + + switch (vsyncMode) { + + case 1: + activeSwapInterval = 1; + flags |= WINDOW_FLAG_VSYNC; + break; + + case 2: + activeSwapInterval = -1; + flags |= WINDOW_FLAG_VSYNC; + break; + + case 3: + activeSwapInterval = 1; + flags |= WINDOW_FLAG_VSYNC; + break; + + default: + flags &= ~WINDOW_FLAG_VSYNC; + break; + + } + + return; + + } + if (!sdlWindow || !context || sdlRenderer) { flags &= ~WINDOW_FLAG_VSYNC; @@ -1439,7 +1655,16 @@ namespace lime { Window* CreateWindow (Application* application, int width, int height, int flags, const char* title) { - return new SDLWindow (application, width, height, flags, title); + SDLWindow* window = new SDLWindow (application, width, height, flags, title); + + if (!window->sdlWindow) { + + delete window; + return 0; + + } + + return window; } diff --git a/project/src/backend/sdl/SDLWindow.h b/project/src/backend/sdl/SDLWindow.h index 51cd02403a..9c3c20fddd 100644 --- a/project/src/backend/sdl/SDLWindow.h +++ b/project/src/backend/sdl/SDLWindow.h @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -62,7 +63,12 @@ namespace lime { virtual bool SetVisible (bool visible); virtual void WarpMouse (int x, int y); virtual int GetVSyncInterval () const; + virtual int GetRequestedVSyncMode () const; virtual double GetRefreshRate () const; + virtual uint64_t CreateVulkanSurface (uintptr_t instance); + virtual void GetVulkanDrawableSize (int* width, int* height); + virtual bool GetVulkanInstanceExtensions (unsigned int* count, const char** names); + virtual void* GetVulkanInstanceProcAddr (); SDL_Renderer* sdlRenderer; SDL_Texture* sdlTexture; SDL_Window* sdlWindow; @@ -74,6 +80,7 @@ namespace lime { int contextHeight; int contextWidth; int requestedVSyncMode; + bool useVulkan; }; diff --git a/project/src/graphics/opengl/OpenGLBindings.cpp b/project/src/graphics/opengl/OpenGLBindings.cpp index dbcc4f1aec..4bcd72a01c 100644 --- a/project/src/graphics/opengl/OpenGLBindings.cpp +++ b/project/src/graphics/opengl/OpenGLBindings.cpp @@ -228,10 +228,13 @@ namespace lime { if (glIsRenderbuffer (id)) glDeleteRenderbuffers (1, &id); break; - #ifdef LIME_GLES3_API + #if defined(LIME_GLES3_API) || !defined(LIME_GLES) case TYPE_SAMPLER: - if (glIsSampler (id)) glDeleteSamplers (1, &id); + if (glIsSampler && glIsSampler (id)) { + if (glDeleteSamplers) + glDeleteSamplers (1, &id); + } break; #endif @@ -245,10 +248,20 @@ namespace lime { if (glIsTexture (id)) glDeleteTextures (1, &id); break; - #ifdef LIME_GLES3_API + #if defined(LIME_GLES3_API) || !defined(LIME_GLES) case TYPE_VERTEX_ARRAY_OBJECT: - - if (glIsVertexArray (id)) glDeleteVertexArrays (1, &id); + + #if defined(HX_MACOS) + if (glIsVertexArrayAPPLE && glIsVertexArrayAPPLE (id)) { + if (glDeleteVertexArraysAPPLE) + glDeleteVertexArraysAPPLE (1, &id); + } + else + #endif + if (glIsVertexArray && glIsVertexArray (id)) { + if (glDeleteVertexArrays) + glDeleteVertexArrays (1, &id); + } break; #endif @@ -531,6 +544,12 @@ namespace lime { void lime_gl_bind_vertex_array (int vertexArray) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glBindVertexArrayAPPLE) { + glBindVertexArrayAPPLE (vertexArray); + } + else + #endif if (glBindVertexArray) { glBindVertexArray (vertexArray); } @@ -542,6 +561,12 @@ namespace lime { HL_PRIM void HL_NAME(hl_gl_bind_vertex_array) (int vertexArray) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glBindVertexArrayAPPLE) { + glBindVertexArrayAPPLE (vertexArray); + } + else + #endif if (glBindVertexArray) { glBindVertexArray (vertexArray); } @@ -1200,6 +1225,12 @@ namespace lime { GLuint id = 0; #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glGenVertexArraysAPPLE) { + glGenVertexArraysAPPLE (1, &id); + } + else + #endif if (glGenVertexArrays) { glGenVertexArrays (1, &id); } @@ -1213,6 +1244,12 @@ namespace lime { GLuint id = 0; #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glGenVertexArraysAPPLE) { + glGenVertexArraysAPPLE (1, &id); + } + else + #endif if (glGenVertexArrays) { glGenVertexArrays (1, &id); } @@ -1401,6 +1438,12 @@ namespace lime { void lime_gl_delete_vertex_array (int vertexArray) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glDeleteVertexArraysAPPLE) { + glDeleteVertexArraysAPPLE (1, (GLuint*)&vertexArray); + } + else + #endif if (glDeleteVertexArrays) { glDeleteVertexArrays (1, (GLuint*)&vertexArray); } @@ -1412,6 +1455,12 @@ namespace lime { HL_PRIM void HL_NAME(hl_gl_delete_vertex_array) (int vertexArray) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) + #if defined (HX_MACOS) + if (glDeleteVertexArraysAPPLE) { + glDeleteVertexArraysAPPLE (1, (GLuint*)&vertexArray); + } + else + #endif if (glDeleteVertexArrays) { glDeleteVertexArrays (1, (GLuint*)&vertexArray); } @@ -3880,7 +3929,17 @@ namespace lime { bool lime_gl_is_vertex_array (int handle) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) - return glIsVertexArray ? glIsVertexArray (handle) : false; + #if defined (HX_MACOS) + if (glIsVertexArrayAPPLE) { + return glIsVertexArrayAPPLE (handle); + } + else + #endif + if (glIsVertexArray) { + return glIsVertexArray (handle); + } + + return false; #else return false; #endif @@ -3891,7 +3950,17 @@ namespace lime { HL_PRIM bool HL_NAME(hl_gl_is_vertex_array) (int handle) { #if defined (LIME_GLES3_API) || !defined (LIME_GLES) - return glIsVertexArray ? glIsVertexArray (handle) : false; + #if defined (HX_MACOS) + if (glIsVertexArrayAPPLE) { + return glIsVertexArrayAPPLE (handle); + } + else + #endif + if (glIsVertexArray) { + return glIsVertexArray (handle); + } + + return false; #else return false; #endif diff --git a/project/src/graphics/vulkan/VKRenderer.cpp b/project/src/graphics/vulkan/VKRenderer.cpp new file mode 100644 index 0000000000..a8b9069a0d --- /dev/null +++ b/project/src/graphics/vulkan/VKRenderer.cpp @@ -0,0 +1,1750 @@ +#include + +#include +#include + +#include +#include +#include +#include + + +namespace lime { + + + static const char* VulkanResultToString (VkResult result) { + + switch (result) { + + case VK_SUCCESS: return "VK_SUCCESS"; + case VK_NOT_READY: return "VK_NOT_READY"; + case VK_TIMEOUT: return "VK_TIMEOUT"; + case VK_EVENT_SET: return "VK_EVENT_SET"; + case VK_EVENT_RESET: return "VK_EVENT_RESET"; + case VK_INCOMPLETE: return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; + default: return "VK_RESULT_UNKNOWN"; + + } + + } + + + static std::string FormatVulkanVersion (uint32_t version) { + + std::ostringstream result; + result << VK_API_VERSION_MAJOR (version) << "." << VK_API_VERSION_MINOR (version) << "." << VK_API_VERSION_PATCH (version); + return result.str (); + + } + + + static const char* VulkanPresentModeToString (VkPresentModeKHR mode) { + + switch (mode) { + + case VK_PRESENT_MODE_IMMEDIATE_KHR: return "immediate"; + case VK_PRESENT_MODE_MAILBOX_KHR: return "mailbox"; + case VK_PRESENT_MODE_FIFO_KHR: return "fifo"; + #ifdef VK_PRESENT_MODE_FIFO_RELAXED_KHR + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: return "fifo-relaxed"; + #endif + default: return "unknown"; + + } + + } + + + static VkPresentModeKHR ChoosePresentMode (const std::vector& presentModes, int requestedVSyncMode) { + + bool hasImmediate = false; + bool hasMailbox = false; + bool hasFifo = false; + bool hasFifoRelaxed = false; + + for (size_t i = 0; i < presentModes.size (); ++i) { + + switch (presentModes[i]) { + + case VK_PRESENT_MODE_IMMEDIATE_KHR: + hasImmediate = true; + break; + + case VK_PRESENT_MODE_MAILBOX_KHR: + hasMailbox = true; + break; + + case VK_PRESENT_MODE_FIFO_KHR: + hasFifo = true; + break; + + #ifdef VK_PRESENT_MODE_FIFO_RELAXED_KHR + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + hasFifoRelaxed = true; + break; + #endif + + default: + break; + + } + + } + + switch (requestedVSyncMode) { + + case 0: + if (hasImmediate) return VK_PRESENT_MODE_IMMEDIATE_KHR; + if (hasMailbox) return VK_PRESENT_MODE_MAILBOX_KHR; + break; + + case 2: + if (hasMailbox) return VK_PRESENT_MODE_MAILBOX_KHR; + #ifdef VK_PRESENT_MODE_FIFO_RELAXED_KHR + if (hasFifoRelaxed) return VK_PRESENT_MODE_FIFO_RELAXED_KHR; + #endif + break; + + case 3: + if (hasMailbox) return VK_PRESENT_MODE_MAILBOX_KHR; + if (hasFifo) return VK_PRESENT_MODE_FIFO_KHR; + if (hasImmediate) return VK_PRESENT_MODE_IMMEDIATE_KHR; + break; + + default: + if (hasFifo) return VK_PRESENT_MODE_FIFO_KHR; + break; + + } + + if (hasFifo) return VK_PRESENT_MODE_FIFO_KHR; + if (hasMailbox) return VK_PRESENT_MODE_MAILBOX_KHR; + if (hasImmediate) return VK_PRESENT_MODE_IMMEDIATE_KHR; + return VK_PRESENT_MODE_FIFO_KHR; + + } + + + VulkanRenderer::VulkanRenderer (Window* window) + : window (window), + vkGetInstanceProcAddr (0), + vkGetDeviceProcAddr (0), + vkAllocateMemory (0), + vkBindBufferMemory (0), + vkCmdCopyBufferToImage (0), + vkCmdPipelineBarrier (0), + vkCreateBuffer (0), + vkCreateDevice (0), + vkCreateFence (0), + vkCreateFramebuffer (0), + vkCreateImageView (0), + vkCreateInstance (0), + vkCreateRenderPass (0), + vkCreateSemaphore (0), + vkCreateSwapchainKHR (0), + vkCreateCommandPool (0), + vkAllocateCommandBuffers (0), + vkAcquireNextImageKHR (0), + vkBeginCommandBuffer (0), + vkCmdBeginRenderPass (0), + vkCmdEndRenderPass (0), + vkDestroyCommandPool (0), + vkDestroyBuffer (0), + vkDestroyDevice (0), + vkDestroyFence (0), + vkDestroyFramebuffer (0), + vkDestroyImageView (0), + vkDestroyInstance (0), + vkDestroyRenderPass (0), + vkDestroySemaphore (0), + vkDestroySurfaceKHR (0), + vkDestroySwapchainKHR (0), + vkDeviceWaitIdle (0), + vkEndCommandBuffer (0), + vkEnumerateDeviceExtensionProperties (0), + vkFreeMemory (0), + vkGetBufferMemoryRequirements (0), + vkEnumerateInstanceExtensionProperties (0), + vkEnumerateInstanceVersion (0), + vkEnumeratePhysicalDevices (0), + vkGetDeviceQueue (0), + vkGetPhysicalDeviceMemoryProperties (0), + vkGetPhysicalDeviceProperties (0), + vkGetPhysicalDeviceQueueFamilyProperties (0), + vkGetPhysicalDeviceSurfaceCapabilitiesKHR (0), + vkGetPhysicalDeviceSurfaceFormatsKHR (0), + vkGetPhysicalDeviceSurfacePresentModesKHR (0), + vkGetPhysicalDeviceSurfaceSupportKHR (0), + vkGetSwapchainImagesKHR (0), + vkMapMemory (0), + vkQueuePresentKHR (0), + vkQueueSubmit (0), + vkResetCommandPool (0), + vkResetFences (0), + vkUnmapMemory (0), + vkWaitForFences (0), + instance (VK_NULL_HANDLE), + surface (VK_NULL_HANDLE), + physicalDevice (VK_NULL_HANDLE), + device (VK_NULL_HANDLE), + queue (VK_NULL_HANDLE), + queueFamilyIndex (0), + swapchain (VK_NULL_HANDLE), + swapchainFormat (VK_FORMAT_UNDEFINED), + swapchainPresentMode (VK_PRESENT_MODE_FIFO_KHR), + requestedVSyncMode (0), + renderPass (VK_NULL_HANDLE), + commandPool (VK_NULL_HANDLE), + imageAvailableSemaphore (VK_NULL_HANDLE), + renderFinishedSemaphore (VK_NULL_HANDLE), + inFlightFence (VK_NULL_HANDLE), + overlayBuffer (VK_NULL_HANDLE), + overlayBufferMemory (VK_NULL_HANDLE), + portabilityEnumerationSupported (false), + portabilitySubsetSupported (false), + swapchainDirty (false), + overlayBufferCapacity (0), + overlayMappedData (0), + overlayWidth (0), + overlayHeight (0), + overlayX (0), + overlayY (0), + overlayEnabled (false) { + + memset (&physicalDeviceProperties, 0, sizeof (physicalDeviceProperties)); + memset (&swapchainExtent, 0, sizeof (swapchainExtent)); + + } + + + VulkanRenderer::~VulkanRenderer () { + + Destroy (); + + } + + + bool VulkanRenderer::Create (const char* applicationName) { + + Destroy (); + lastError.clear (); + info.clear (); + + if (!window) { + + SetError ("Vulkan renderer creation failed: missing window"); + return false; + + } + + if (SDL_Vulkan_LoadLibrary (NULL) != 0) { + + SetError (std::string ("SDL_Vulkan_LoadLibrary failed: ") + SDL_GetError ()); + return false; + + } + + if (!LoadGlobalProcs ()) { + + return false; + + } + + if (!CreateInstance (applicationName)) return false; + if (!LoadInstanceProcs ()) return false; + if (!CreateSurface ()) return false; + if (!PickPhysicalDevice ()) return false; + if (!CreateDevice ()) return false; + if (!LoadDeviceProcs ()) return false; + vkGetDeviceQueue (device, queueFamilyIndex, 0, &queue); + if (!CreateSwapchainResources ()) return false; + if (!CreateSyncObjects ()) return false; + + std::ostringstream result; + result << physicalDeviceProperties.deviceName << " | Vulkan " << FormatVulkanVersion (physicalDeviceProperties.apiVersion) + << " | present " << VulkanPresentModeToString (swapchainPresentMode); + info = result.str (); + return true; + + } + + + bool VulkanRenderer::ClearOverlay () { + + overlayEnabled = false; + overlayWidth = 0; + overlayHeight = 0; + overlayX = 0; + overlayY = 0; + lastError.clear (); + return true; + + } + + + void VulkanRenderer::Destroy () { + + if (device && vkDeviceWaitIdle) { + + vkDeviceWaitIdle (device); + + } + + if (device && vkDestroyFence && inFlightFence) { + + vkDestroyFence (device, inFlightFence, 0); + inFlightFence = VK_NULL_HANDLE; + + } + + if (device && vkDestroySemaphore && renderFinishedSemaphore) { + + vkDestroySemaphore (device, renderFinishedSemaphore, 0); + renderFinishedSemaphore = VK_NULL_HANDLE; + + } + + if (device && vkDestroySemaphore && imageAvailableSemaphore) { + + vkDestroySemaphore (device, imageAvailableSemaphore, 0); + imageAvailableSemaphore = VK_NULL_HANDLE; + + } + + DestroyOverlayResources (); + DestroySwapchainResources (); + + if (device && vkDestroyDevice) { + + vkDestroyDevice (device, 0); + device = VK_NULL_HANDLE; + + } + + queue = VK_NULL_HANDLE; + physicalDevice = VK_NULL_HANDLE; + memset (&physicalDeviceProperties, 0, sizeof (physicalDeviceProperties)); + + if (surface && vkDestroySurfaceKHR && instance) { + + vkDestroySurfaceKHR (instance, surface, 0); + surface = VK_NULL_HANDLE; + + } + + if (instance && vkDestroyInstance) { + + vkDestroyInstance (instance, 0); + instance = VK_NULL_HANDLE; + + } + + instanceExtensions.clear (); + deviceExtensions.clear (); + portabilityEnumerationSupported = false; + portabilitySubsetSupported = false; + swapchainDirty = false; + swapchainFormat = VK_FORMAT_UNDEFINED; + swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + requestedVSyncMode = 0; + memset (&swapchainExtent, 0, sizeof (swapchainExtent)); + + } + + + bool VulkanRenderer::Render (float red, float green, float blue, float alpha) { + + if (!device) { + + SetError ("Vulkan renderer is not initialized"); + return false; + + } + + int currentRequestedVSyncMode = window ? window->GetRequestedVSyncMode () : 0; + if (swapchainDirty || !swapchain || swapchainExtent.width == 0 || swapchainExtent.height == 0 || currentRequestedVSyncMode != requestedVSyncMode) { + + if (!RecreateSwapchain ()) { + + return false; + + } + + } + + if (!swapchain || swapchainExtent.width == 0 || swapchainExtent.height == 0) { + + return true; + + } + + VkResult result = vkWaitForFences (device, 1, &inFlightFence, VK_TRUE, UINT64_MAX); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkWaitForFences failed: ") + VulkanResultToString (result)); + return false; + + } + + uint32_t imageIndex = 0; + result = vkAcquireNextImageKHR (device, swapchain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + + return RecreateSwapchain (); + + } + + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + + SetError (std::string ("vkAcquireNextImageKHR failed: ") + VulkanResultToString (result)); + return false; + + } + + result = vkResetFences (device, 1, &inFlightFence); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkResetFences failed: ") + VulkanResultToString (result)); + return false; + + } + + result = vkResetCommandPool (device, commandPool, 0); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkResetCommandPool failed: ") + VulkanResultToString (result)); + return false; + + } + + if (!RecordCommandBuffer (imageIndex, red, green, blue, alpha)) { + + return false; + + } + + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + VkSubmitInfo submitInfo; + memset (&submitInfo, 0, sizeof (submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &imageAvailableSemaphore; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffers[imageIndex]; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &renderFinishedSemaphore; + + result = vkQueueSubmit (queue, 1, &submitInfo, inFlightFence); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkQueueSubmit failed: ") + VulkanResultToString (result)); + return false; + + } + + VkPresentInfoKHR presentInfo; + memset (&presentInfo, 0, sizeof (presentInfo)); + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &renderFinishedSemaphore; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + presentInfo.pImageIndices = &imageIndex; + + result = vkQueuePresentKHR (queue, &presentInfo); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + + return RecreateSwapchain (); + + } + + if (result != VK_SUCCESS) { + + SetError (std::string ("vkQueuePresentKHR failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::Resize () { + + return RecreateSwapchain (); + + } + + + bool VulkanRenderer::SetOverlay (const unsigned char* data, int width, int height, int x, int y) { + + if (!data || width <= 0 || height <= 0) { + + return ClearOverlay (); + + } + + size_t requiredSize = (size_t)width * (size_t)height * 4; + if (!CreateOverlayBuffer (requiredSize)) { + + return false; + + } + + memcpy (overlayMappedData, data, requiredSize); + + overlayWidth = (uint32_t)width; + overlayHeight = (uint32_t)height; + overlayX = x; + overlayY = y; + overlayEnabled = true; + lastError.clear (); + return true; + + } + + + bool VulkanRenderer::CreateCommandBuffers () { + + commandBuffers.clear (); + + if (swapchainImages.empty ()) { + + SetError ("Cannot allocate Vulkan command buffers without swapchain images"); + return false; + + } + + commandBuffers.resize (swapchainImages.size (), VK_NULL_HANDLE); + + VkCommandBufferAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = commandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.commandBufferCount = (uint32_t)commandBuffers.size (); + + VkResult result = vkAllocateCommandBuffers (device, &allocateInfo, commandBuffers.data ()); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkAllocateCommandBuffers failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateCommandPool () { + + VkCommandPoolCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + createInfo.queueFamilyIndex = queueFamilyIndex; + + VkResult result = vkCreateCommandPool (device, &createInfo, 0, &commandPool); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateCommandPool failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateDevice () { + + const float queuePriority = 1.0f; + + VkDeviceQueueCreateInfo queueCreateInfo; + memset (&queueCreateInfo, 0, sizeof (queueCreateInfo)); + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + + deviceExtensions.clear (); + deviceExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME); + if (portabilitySubsetSupported) { + + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + deviceExtensions.push_back (VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + #endif + + } + + VkDeviceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = 1; + createInfo.pQueueCreateInfos = &queueCreateInfo; + createInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size (); + createInfo.ppEnabledExtensionNames = deviceExtensions.data (); + + VkResult result = vkCreateDevice (physicalDevice, &createInfo, 0, &device); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateDevice failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateFramebuffers () { + + framebuffers.clear (); + framebuffers.resize (swapchainImageViews.size (), VK_NULL_HANDLE); + + for (size_t i = 0; i < swapchainImageViews.size (); ++i) { + + VkImageView attachments[] = { swapchainImageViews[i] }; + VkFramebufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + createInfo.renderPass = renderPass; + createInfo.attachmentCount = 1; + createInfo.pAttachments = attachments; + createInfo.width = swapchainExtent.width; + createInfo.height = swapchainExtent.height; + createInfo.layers = 1; + + VkResult result = vkCreateFramebuffer (device, &createInfo, 0, &framebuffers[i]); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateFramebuffer failed: ") + VulkanResultToString (result)); + return false; + + } + + } + + return true; + + } + + + bool VulkanRenderer::CreateImageViews () { + + swapchainImageViews.clear (); + swapchainImageViews.resize (swapchainImages.size (), VK_NULL_HANDLE); + + for (size_t i = 0; i < swapchainImages.size (); ++i) { + + VkImageViewCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapchainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = swapchainFormat; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + VkResult result = vkCreateImageView (device, &createInfo, 0, &swapchainImageViews[i]); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateImageView failed: ") + VulkanResultToString (result)); + return false; + + } + + } + + return true; + + } + + + bool VulkanRenderer::CreateInstance (const char* applicationName) { + + instanceExtensions.clear (); + + unsigned int requiredExtensionCount = 0; + if (!window->GetVulkanInstanceExtensions (&requiredExtensionCount, 0)) { + + SetError ("Failed to query required Vulkan window extensions"); + return false; + + } + + std::vector requiredExtensions (requiredExtensionCount); + if (requiredExtensionCount > 0 && !window->GetVulkanInstanceExtensions (&requiredExtensionCount, requiredExtensions.data ())) { + + SetError ("Failed to fetch required Vulkan window extensions"); + return false; + + } + + for (size_t i = 0; i < requiredExtensions.size (); ++i) { + + instanceExtensions.push_back (requiredExtensions[i]); + + } + + uint32_t availableCount = 0; + if (vkEnumerateInstanceExtensionProperties && + vkEnumerateInstanceExtensionProperties (0, &availableCount, 0) == VK_SUCCESS && availableCount > 0) { + + std::vector availableExtensions (availableCount); + if (vkEnumerateInstanceExtensionProperties (0, &availableCount, availableExtensions.data ()) == VK_SUCCESS) { + + for (size_t i = 0; i < availableExtensions.size (); ++i) { + + #ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + if (strcmp (availableExtensions[i].extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { + + portabilityEnumerationSupported = true; + + } + #endif + + } + + } + + } + + if (portabilityEnumerationSupported) { + + #ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + instanceExtensions.push_back (VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + #endif + + } + + uint32_t instanceVersion = VK_API_VERSION_1_0; + if (vkEnumerateInstanceVersion) { + + vkEnumerateInstanceVersion (&instanceVersion); + + } + + VkApplicationInfo applicationInfo; + memset (&applicationInfo, 0, sizeof (applicationInfo)); + applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + applicationInfo.pApplicationName = applicationName ? applicationName : "Lime Vulkan Sample"; + applicationInfo.pEngineName = "Lime"; + applicationInfo.applicationVersion = VK_MAKE_VERSION (1, 0, 0); + applicationInfo.engineVersion = VK_MAKE_VERSION (1, 0, 0); + applicationInfo.apiVersion = instanceVersion >= VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : instanceVersion; + + VkInstanceCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &applicationInfo; + createInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size (); + createInfo.ppEnabledExtensionNames = instanceExtensions.empty () ? 0 : instanceExtensions.data (); + + #ifdef VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR + if (portabilityEnumerationSupported) { + + createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + + } + #endif + + VkResult result = vkCreateInstance (&createInfo, 0, &instance); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateInstance failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateOverlayBuffer (size_t requiredSize) { + + if (!device) { + + SetError ("Cannot create Vulkan overlay buffer before device initialization"); + return false; + + } + + if (requiredSize == 0) { + + DestroyOverlayResources (); + return true; + + } + + if (overlayBuffer != VK_NULL_HANDLE && overlayMappedData && overlayBufferCapacity >= requiredSize) { + + return true; + + } + + DestroyOverlayResources (); + + VkBufferCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = requiredSize; + createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkResult result = vkCreateBuffer (device, &createInfo, 0, &overlayBuffer); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateBuffer failed for overlay upload: ") + VulkanResultToString (result)); + return false; + + } + + VkMemoryRequirements memoryRequirements; + memset (&memoryRequirements, 0, sizeof (memoryRequirements)); + vkGetBufferMemoryRequirements (device, overlayBuffer, &memoryRequirements); + + VkMemoryAllocateInfo allocateInfo; + memset (&allocateInfo, 0, sizeof (allocateInfo)); + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memoryRequirements.size; + allocateInfo.memoryTypeIndex = FindMemoryType ( + memoryRequirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + ); + if (allocateInfo.memoryTypeIndex == UINT32_MAX) { + + return false; + + } + + result = vkAllocateMemory (device, &allocateInfo, 0, &overlayBufferMemory); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkAllocateMemory failed for overlay upload: ") + VulkanResultToString (result)); + return false; + + } + + result = vkBindBufferMemory (device, overlayBuffer, overlayBufferMemory, 0); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkBindBufferMemory failed for overlay upload: ") + VulkanResultToString (result)); + return false; + + } + + void* mappedData = 0; + result = vkMapMemory (device, overlayBufferMemory, 0, allocateInfo.allocationSize, 0, &mappedData); + if (result != VK_SUCCESS || !mappedData) { + + SetError (std::string ("vkMapMemory failed for overlay upload: ") + VulkanResultToString (result)); + return false; + + } + + overlayMappedData = (unsigned char*)mappedData; + overlayBufferCapacity = requiredSize; + return true; + + } + + + bool VulkanRenderer::CreateRenderPass () { + + VkAttachmentDescription colorAttachment; + memset (&colorAttachment, 0, sizeof (colorAttachment)); + colorAttachment.format = swapchainFormat; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference colorAttachmentRef; + memset (&colorAttachmentRef, 0, sizeof (colorAttachmentRef)); + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass; + memset (&subpass, 0, sizeof (subpass)); + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkSubpassDependency dependency; + memset (&dependency, 0, sizeof (dependency)); + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = 1; + createInfo.pAttachments = &colorAttachment; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpass; + createInfo.dependencyCount = 1; + createInfo.pDependencies = &dependency; + + VkResult result = vkCreateRenderPass (device, &createInfo, 0, &renderPass); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateRenderPass failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateSurface () { + + uint64_t nativeSurface = window->CreateVulkanSurface ((uintptr_t)instance); + if (!nativeSurface) { + + SetError ("Failed to create Vulkan surface from Lime window"); + return false; + + } + + surface = (VkSurfaceKHR)(uintptr_t)nativeSurface; + return true; + + } + + + bool VulkanRenderer::CreateSwapchain () { + + VkSurfaceCapabilitiesKHR capabilities; + memset (&capabilities, 0, sizeof (capabilities)); + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physicalDevice, surface, &capabilities); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: ") + VulkanResultToString (result)); + return false; + + } + + uint32_t formatCount = 0; + result = vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, 0); + if (result != VK_SUCCESS || formatCount == 0) { + + SetError ("Failed to query Vulkan surface formats"); + return false; + + } + + std::vector formats (formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, formats.data ()); + + VkSurfaceFormatKHR surfaceFormat = formats[0]; + for (size_t i = 0; i < formats.size (); ++i) { + + if (formats[i].format == VK_FORMAT_B8G8R8A8_UNORM && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + + surfaceFormat = formats[i]; + break; + + } + + } + + uint32_t presentModeCount = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice, surface, &presentModeCount, 0); + std::vector presentModes (presentModeCount > 0 ? presentModeCount : 1, VK_PRESENT_MODE_FIFO_KHR); + if (presentModeCount > 0) { + + vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice, surface, &presentModeCount, presentModes.data ()); + + } + + int currentRequestedVSyncMode = window ? window->GetRequestedVSyncMode () : 0; + VkPresentModeKHR presentMode = ChoosePresentMode (presentModes, currentRequestedVSyncMode); + + int drawableWidth = 0; + int drawableHeight = 0; + window->GetVulkanDrawableSize (&drawableWidth, &drawableHeight); + if (drawableWidth <= 0 || drawableHeight <= 0) { + + swapchainExtent.width = 0; + swapchainExtent.height = 0; + swapchainDirty = true; + return true; + + } + + if (capabilities.currentExtent.width != UINT32_MAX) { + + swapchainExtent = capabilities.currentExtent; + + } else { + + swapchainExtent.width = (uint32_t)(std::max) ((int)capabilities.minImageExtent.width, + (std::min) (drawableWidth, (int)capabilities.maxImageExtent.width)); + swapchainExtent.height = (uint32_t)(std::max) ((int)capabilities.minImageExtent.height, + (std::min) (drawableHeight, (int)capabilities.maxImageExtent.height)); + + } + + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { + + imageCount = capabilities.maxImageCount; + + } + + VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + const bool transparentWindow = window && ((window->flags & WINDOW_FLAG_TRANSPARENT) != 0); + const VkCompositeAlphaFlagBitsKHR opaqueCompositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + }; + const VkCompositeAlphaFlagBitsKHR transparentCompositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR + }; + const VkCompositeAlphaFlagBitsKHR* compositeAlphaFlags = transparentWindow ? transparentCompositeAlphaFlags : opaqueCompositeAlphaFlags; + const size_t compositeAlphaFlagCount = transparentWindow + ? sizeof (transparentCompositeAlphaFlags) / sizeof (transparentCompositeAlphaFlags[0]) + : sizeof (opaqueCompositeAlphaFlags) / sizeof (opaqueCompositeAlphaFlags[0]); + + for (size_t i = 0; i < compositeAlphaFlagCount; ++i) { + + if (capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { + + compositeAlpha = compositeAlphaFlags[i]; + break; + + } + + } + + VkSwapchainCreateInfoKHR createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = swapchainExtent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = compositeAlpha; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + result = vkCreateSwapchainKHR (device, &createInfo, 0, &swapchain); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateSwapchainKHR failed: ") + VulkanResultToString (result)); + return false; + + } + + swapchainFormat = surfaceFormat.format; + swapchainPresentMode = presentMode; + requestedVSyncMode = currentRequestedVSyncMode; + swapchainDirty = false; + + uint32_t swapchainImageCount = 0; + result = vkGetSwapchainImagesKHR (device, swapchain, &swapchainImageCount, 0); + if (result != VK_SUCCESS || swapchainImageCount == 0) { + + SetError ("Failed to query Vulkan swapchain images"); + return false; + + } + + swapchainImages.resize (swapchainImageCount); + result = vkGetSwapchainImagesKHR (device, swapchain, &swapchainImageCount, swapchainImages.data ()); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkGetSwapchainImagesKHR failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::CreateSwapchainResources () { + + if (!CreateSwapchain ()) return false; + if (swapchainExtent.width == 0 || swapchainExtent.height == 0) return true; + if (!CreateImageViews ()) return false; + if (!CreateRenderPass ()) return false; + if (!CreateCommandPool ()) return false; + if (!CreateFramebuffers ()) return false; + if (!CreateCommandBuffers ()) return false; + return true; + + } + + + bool VulkanRenderer::CreateSyncObjects () { + + VkSemaphoreCreateInfo semaphoreInfo; + memset (&semaphoreInfo, 0, sizeof (semaphoreInfo)); + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fenceInfo; + memset (&fenceInfo, 0, sizeof (fenceInfo)); + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + VkResult result = vkCreateSemaphore (device, &semaphoreInfo, 0, &imageAvailableSemaphore); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateSemaphore failed: ") + VulkanResultToString (result)); + return false; + + } + + result = vkCreateSemaphore (device, &semaphoreInfo, 0, &renderFinishedSemaphore); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateSemaphore failed: ") + VulkanResultToString (result)); + return false; + + } + + result = vkCreateFence (device, &fenceInfo, 0, &inFlightFence); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkCreateFence failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + void VulkanRenderer::DestroyOverlayResources () { + + overlayEnabled = false; + overlayWidth = 0; + overlayHeight = 0; + overlayX = 0; + overlayY = 0; + + if (device && overlayBufferMemory && overlayMappedData && vkUnmapMemory) { + + vkUnmapMemory (device, overlayBufferMemory); + overlayMappedData = 0; + + } + + if (device && vkDestroyBuffer && overlayBuffer) { + + vkDestroyBuffer (device, overlayBuffer, 0); + overlayBuffer = VK_NULL_HANDLE; + + } + + if (device && vkFreeMemory && overlayBufferMemory) { + + vkFreeMemory (device, overlayBufferMemory, 0); + overlayBufferMemory = VK_NULL_HANDLE; + + } + + overlayMappedData = 0; + overlayBufferCapacity = 0; + + } + + + void VulkanRenderer::DestroySwapchainResources () { + + commandBuffers.clear (); + + if (device && vkDestroyCommandPool && commandPool) { + + vkDestroyCommandPool (device, commandPool, 0); + commandPool = VK_NULL_HANDLE; + + } + + for (size_t i = 0; i < framebuffers.size (); ++i) { + + if (framebuffers[i] && device && vkDestroyFramebuffer) { + + vkDestroyFramebuffer (device, framebuffers[i], 0); + + } + + } + + framebuffers.clear (); + + if (device && vkDestroyRenderPass && renderPass) { + + vkDestroyRenderPass (device, renderPass, 0); + renderPass = VK_NULL_HANDLE; + + } + + for (size_t i = 0; i < swapchainImageViews.size (); ++i) { + + if (swapchainImageViews[i] && device && vkDestroyImageView) { + + vkDestroyImageView (device, swapchainImageViews[i], 0); + + } + + } + + swapchainImageViews.clear (); + swapchainImages.clear (); + + if (device && vkDestroySwapchainKHR && swapchain) { + + vkDestroySwapchainKHR (device, swapchain, 0); + swapchain = VK_NULL_HANDLE; + + } + + } + + + uint32_t VulkanRenderer::FindMemoryType (uint32_t typeFilter, VkMemoryPropertyFlags properties) { + + VkPhysicalDeviceMemoryProperties memoryProperties; + memset (&memoryProperties, 0, sizeof (memoryProperties)); + vkGetPhysicalDeviceMemoryProperties (physicalDevice, &memoryProperties); + + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { + + if ((typeFilter & (1u << i)) && + (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { + + return i; + + } + + } + + SetError ("Failed to find a compatible Vulkan memory type"); + return UINT32_MAX; + + } + + + bool VulkanRenderer::LoadDeviceProcs () { + + if (!vkGetDeviceProcAddr) { + + SetError ("Missing vkGetDeviceProcAddr"); + return false; + + } + + #define LIME_LOAD_DEVICE_PROC(name) \ + name = (PFN_##name)vkGetDeviceProcAddr (device, #name); \ + if (!name) { SetError (std::string ("Missing Vulkan device proc: ") + #name); return false; } + + LIME_LOAD_DEVICE_PROC (vkAllocateMemory); + LIME_LOAD_DEVICE_PROC (vkAcquireNextImageKHR); + LIME_LOAD_DEVICE_PROC (vkAllocateCommandBuffers); + LIME_LOAD_DEVICE_PROC (vkBeginCommandBuffer); + LIME_LOAD_DEVICE_PROC (vkBindBufferMemory); + LIME_LOAD_DEVICE_PROC (vkCmdCopyBufferToImage); + LIME_LOAD_DEVICE_PROC (vkCmdBeginRenderPass); + LIME_LOAD_DEVICE_PROC (vkCmdEndRenderPass); + LIME_LOAD_DEVICE_PROC (vkCmdPipelineBarrier); + LIME_LOAD_DEVICE_PROC (vkCreateBuffer); + LIME_LOAD_DEVICE_PROC (vkCreateCommandPool); + LIME_LOAD_DEVICE_PROC (vkCreateFence); + LIME_LOAD_DEVICE_PROC (vkCreateFramebuffer); + LIME_LOAD_DEVICE_PROC (vkCreateImageView); + LIME_LOAD_DEVICE_PROC (vkCreateRenderPass); + LIME_LOAD_DEVICE_PROC (vkCreateSemaphore); + LIME_LOAD_DEVICE_PROC (vkCreateSwapchainKHR); + LIME_LOAD_DEVICE_PROC (vkDestroyCommandPool); + LIME_LOAD_DEVICE_PROC (vkDestroyBuffer); + LIME_LOAD_DEVICE_PROC (vkDestroyDevice); + LIME_LOAD_DEVICE_PROC (vkDestroyFence); + LIME_LOAD_DEVICE_PROC (vkDestroyFramebuffer); + LIME_LOAD_DEVICE_PROC (vkDestroyImageView); + LIME_LOAD_DEVICE_PROC (vkDestroyRenderPass); + LIME_LOAD_DEVICE_PROC (vkDestroySemaphore); + LIME_LOAD_DEVICE_PROC (vkDestroySwapchainKHR); + LIME_LOAD_DEVICE_PROC (vkDeviceWaitIdle); + LIME_LOAD_DEVICE_PROC (vkEndCommandBuffer); + LIME_LOAD_DEVICE_PROC (vkFreeMemory); + LIME_LOAD_DEVICE_PROC (vkGetBufferMemoryRequirements); + LIME_LOAD_DEVICE_PROC (vkGetSwapchainImagesKHR); + LIME_LOAD_DEVICE_PROC (vkMapMemory); + LIME_LOAD_DEVICE_PROC (vkQueuePresentKHR); + LIME_LOAD_DEVICE_PROC (vkQueueSubmit); + LIME_LOAD_DEVICE_PROC (vkResetCommandPool); + LIME_LOAD_DEVICE_PROC (vkResetFences); + LIME_LOAD_DEVICE_PROC (vkUnmapMemory); + LIME_LOAD_DEVICE_PROC (vkWaitForFences); + + #undef LIME_LOAD_DEVICE_PROC + + return true; + + } + + + bool VulkanRenderer::LoadGlobalProcs () { + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)window->GetVulkanInstanceProcAddr (); + + if (!vkGetInstanceProcAddr) { + + SetError ("SDL did not expose vkGetInstanceProcAddr"); + return false; + + } + + #define LIME_LOAD_GLOBAL_PROC(name) \ + name = (PFN_##name)vkGetInstanceProcAddr (VK_NULL_HANDLE, #name); \ + if (!name) { SetError (std::string ("Missing Vulkan global proc: ") + #name); return false; } + + LIME_LOAD_GLOBAL_PROC (vkCreateInstance); + LIME_LOAD_GLOBAL_PROC (vkEnumerateInstanceExtensionProperties); + vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr (VK_NULL_HANDLE, "vkEnumerateInstanceVersion"); + + #undef LIME_LOAD_GLOBAL_PROC + + return true; + + } + + + bool VulkanRenderer::LoadInstanceProcs () { + + #define LIME_LOAD_INSTANCE_PROC(name) \ + name = (PFN_##name)vkGetInstanceProcAddr (instance, #name); \ + if (!name) { SetError (std::string ("Missing Vulkan instance proc: ") + #name); return false; } + + LIME_LOAD_INSTANCE_PROC (vkCreateDevice); + LIME_LOAD_INSTANCE_PROC (vkDestroyInstance); + LIME_LOAD_INSTANCE_PROC (vkDestroySurfaceKHR); + LIME_LOAD_INSTANCE_PROC (vkEnumerateDeviceExtensionProperties); + LIME_LOAD_INSTANCE_PROC (vkEnumeratePhysicalDevices); + LIME_LOAD_INSTANCE_PROC (vkGetDeviceProcAddr); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceMemoryProperties); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceProperties); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceQueueFamilyProperties); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceSurfaceFormatsKHR); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceSurfacePresentModesKHR); + LIME_LOAD_INSTANCE_PROC (vkGetPhysicalDeviceSurfaceSupportKHR); + LIME_LOAD_INSTANCE_PROC (vkGetDeviceQueue); + + #undef LIME_LOAD_INSTANCE_PROC + + return true; + + } + + + bool VulkanRenderer::PickPhysicalDevice () { + + uint32_t deviceCount = 0; + VkResult result = vkEnumeratePhysicalDevices (instance, &deviceCount, 0); + if (result != VK_SUCCESS || deviceCount == 0) { + + SetError ("No Vulkan physical devices were found"); + return false; + + } + + std::vector physicalDevices (deviceCount); + vkEnumeratePhysicalDevices (instance, &deviceCount, physicalDevices.data ()); + + for (size_t deviceIndex = 0; deviceIndex < physicalDevices.size (); ++deviceIndex) { + + VkPhysicalDevice candidate = physicalDevices[deviceIndex]; + + uint32_t extensionCount = 0; + vkEnumerateDeviceExtensionProperties (candidate, 0, &extensionCount, 0); + std::vector extensions (extensionCount); + if (extensionCount > 0) { + + vkEnumerateDeviceExtensionProperties (candidate, 0, &extensionCount, extensions.data ()); + + } + + bool hasSwapchain = false; + bool hasPortabilitySubset = false; + + for (size_t i = 0; i < extensions.size (); ++i) { + + if (strcmp (extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { + + hasSwapchain = true; + + } + + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + if (strcmp (extensions[i].extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) { + + hasPortabilitySubset = true; + + } + #endif + + } + + if (!hasSwapchain) { + + continue; + + } + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties (candidate, &queueFamilyCount, 0); + if (queueFamilyCount == 0) { + + continue; + + } + + std::vector queueFamilies (queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties (candidate, &queueFamilyCount, queueFamilies.data ()); + + for (uint32_t queueIndex = 0; queueIndex < queueFamilyCount; ++queueIndex) { + + VkBool32 supportsPresent = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR (candidate, queueIndex, surface, &supportsPresent); + + if ((queueFamilies[queueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) && supportsPresent) { + + physicalDevice = candidate; + queueFamilyIndex = queueIndex; + portabilitySubsetSupported = hasPortabilitySubset; + vkGetPhysicalDeviceProperties (physicalDevice, &physicalDeviceProperties); + return true; + + } + + } + + } + + SetError ("Failed to find a Vulkan physical device with graphics and present support"); + return false; + + } + + + bool VulkanRenderer::RecordCommandBuffer (uint32_t imageIndex, float red, float green, float blue, float alpha) { + + if (imageIndex >= commandBuffers.size () || imageIndex >= framebuffers.size ()) { + + SetError ("Invalid Vulkan swapchain image index"); + return false; + + } + + VkCommandBuffer commandBuffer = commandBuffers[imageIndex]; + + VkCommandBufferBeginInfo beginInfo; + memset (&beginInfo, 0, sizeof (beginInfo)); + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkResult result = vkBeginCommandBuffer (commandBuffer, &beginInfo); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkBeginCommandBuffer failed: ") + VulkanResultToString (result)); + return false; + + } + + VkClearValue clearValue; + clearValue.color.float32[0] = red; + clearValue.color.float32[1] = green; + clearValue.color.float32[2] = blue; + clearValue.color.float32[3] = alpha; + + VkRenderPassBeginInfo renderPassInfo; + memset (&renderPassInfo, 0, sizeof (renderPassInfo)); + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + renderPassInfo.framebuffer = framebuffers[imageIndex]; + renderPassInfo.renderArea.offset.x = 0; + renderPassInfo.renderArea.offset.y = 0; + renderPassInfo.renderArea.extent = swapchainExtent; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearValue; + + vkCmdBeginRenderPass (commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass (commandBuffer); + + uint32_t copyWidth = overlayWidth; + uint32_t copyHeight = overlayHeight; + int copyX = overlayX; + int copyY = overlayY; + VkDeviceSize bufferOffset = 0; + bool hasOverlayCopy = overlayEnabled && overlayBuffer && overlayMappedData && overlayWidth > 0 && overlayHeight > 0; + + if (hasOverlayCopy) { + + if (copyX < 0) { + + uint32_t clipped = (uint32_t)(-copyX); + if (clipped >= copyWidth) { + + hasOverlayCopy = false; + + } else { + + bufferOffset += (VkDeviceSize)clipped * 4; + copyWidth -= clipped; + copyX = 0; + + } + + } + + if (hasOverlayCopy && copyY < 0) { + + uint32_t clipped = (uint32_t)(-copyY); + if (clipped >= copyHeight) { + + hasOverlayCopy = false; + + } else { + + bufferOffset += (VkDeviceSize)clipped * (VkDeviceSize)overlayWidth * 4; + copyHeight -= clipped; + copyY = 0; + + } + + } + + if (hasOverlayCopy && + (copyX >= (int)swapchainExtent.width || copyY >= (int)swapchainExtent.height)) { + + hasOverlayCopy = false; + + } + + if (hasOverlayCopy && (uint32_t)copyX + copyWidth > swapchainExtent.width) { + + copyWidth = swapchainExtent.width - (uint32_t)copyX; + + } + + if (hasOverlayCopy && (uint32_t)copyY + copyHeight > swapchainExtent.height) { + + copyHeight = swapchainExtent.height - (uint32_t)copyY; + + } + + hasOverlayCopy = hasOverlayCopy && copyWidth > 0 && copyHeight > 0; + + } + + VkImageMemoryBarrier imageBarrier; + memset (&imageBarrier, 0, sizeof (imageBarrier)); + imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageBarrier.image = swapchainImages[imageIndex]; + imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageBarrier.subresourceRange.baseMipLevel = 0; + imageBarrier.subresourceRange.levelCount = 1; + imageBarrier.subresourceRange.baseArrayLayer = 0; + imageBarrier.subresourceRange.layerCount = 1; + + if (hasOverlayCopy) { + + imageBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + vkCmdPipelineBarrier ( + commandBuffer, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, 0, + 0, 0, + 1, &imageBarrier + ); + + VkBufferImageCopy copyRegion; + memset (©Region, 0, sizeof (copyRegion)); + copyRegion.bufferOffset = bufferOffset; + copyRegion.bufferRowLength = overlayWidth; + copyRegion.bufferImageHeight = overlayHeight; + copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.imageSubresource.mipLevel = 0; + copyRegion.imageSubresource.baseArrayLayer = 0; + copyRegion.imageSubresource.layerCount = 1; + copyRegion.imageOffset.x = copyX; + copyRegion.imageOffset.y = copyY; + copyRegion.imageOffset.z = 0; + copyRegion.imageExtent.width = copyWidth; + copyRegion.imageExtent.height = copyHeight; + copyRegion.imageExtent.depth = 1; + + vkCmdCopyBufferToImage (commandBuffer, overlayBuffer, swapchainImages[imageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); + + imageBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageBarrier.dstAccessMask = 0; + imageBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + vkCmdPipelineBarrier ( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, 0, + 0, 0, + 1, &imageBarrier + ); + + } else { + + imageBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageBarrier.dstAccessMask = 0; + imageBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + vkCmdPipelineBarrier ( + commandBuffer, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, 0, + 0, 0, + 1, &imageBarrier + ); + + } + + result = vkEndCommandBuffer (commandBuffer); + if (result != VK_SUCCESS) { + + SetError (std::string ("vkEndCommandBuffer failed: ") + VulkanResultToString (result)); + return false; + + } + + return true; + + } + + + bool VulkanRenderer::RecreateSwapchain () { + + if (!device) { + + return false; + + } + + int drawableWidth = 0; + int drawableHeight = 0; + window->GetVulkanDrawableSize (&drawableWidth, &drawableHeight); + if (drawableWidth <= 0 || drawableHeight <= 0) { + + if (swapchain || !swapchainImages.empty () || !swapchainImageViews.empty () || !framebuffers.empty () || !commandBuffers.empty () || commandPool || renderPass) { + + if (vkDeviceWaitIdle (device) != VK_SUCCESS) { + + SetError ("vkDeviceWaitIdle failed while suspending the swapchain"); + return false; + + } + + DestroySwapchainResources (); + + } + + swapchainExtent.width = 0; + swapchainExtent.height = 0; + swapchainDirty = true; + lastError.clear (); + return true; + + } + + if (vkDeviceWaitIdle (device) != VK_SUCCESS) { + + SetError ("vkDeviceWaitIdle failed during swapchain recreation"); + return false; + + } + + DestroySwapchainResources (); + if (!CreateSwapchainResources ()) { + + swapchainDirty = true; + return false; + + } + + swapchainDirty = (swapchain == VK_NULL_HANDLE || swapchainExtent.width == 0 || swapchainExtent.height == 0); + lastError.clear (); + return true; + + } + + + void VulkanRenderer::SetError (const std::string& value) { + + lastError = value; + + } + + +} diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index a26c5c679a..cd682d444d 100644 --- a/project/src/media/openal/OpenALBindings.cpp +++ b/project/src/media/openal/OpenALBindings.cpp @@ -170,6 +170,7 @@ namespace lime { } */ + void lime_al_auxf (value aux, int param, float value) { #ifdef LIME_OPENALSOFT @@ -2317,6 +2318,30 @@ namespace lime { } + bool lime_alc_is_extension_present (value device, HxString extname) { + + #ifdef LIME_OPENALSOFT + ALCdevice* alcDevice = val_is_null (device) ? NULL : (ALCdevice*)val_data (device); + return extname.__s ? alcIsExtensionPresent (alcDevice, extname.__s) : false; + #else + return false; + #endif + + } + + + HL_PRIM bool HL_NAME(hl_alc_is_extension_present) (HL_CFFIPointer* device, hl_vstring* extname) { + + #ifdef LIME_OPENALSOFT + ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : NULL; + return extname ? alcIsExtensionPresent (alcDevice, hl_to_utf8 (extname->bytes)) : false; + #else + return false; + #endif + + } + + bool lime_al_is_filter (value filter) { #ifdef LIME_OPENALSOFT @@ -3379,7 +3404,7 @@ namespace lime { value lime_alc_get_string (value device, int param) { - ALCdevice* alcDevice = (ALCdevice*)val_data (device); + ALCdevice* alcDevice = val_is_null (device) ? NULL : (ALCdevice*)val_data (device); const char* result = alcGetString (alcDevice, param); return result ? alloc_string (result) : alloc_null (); @@ -3388,8 +3413,9 @@ namespace lime { HL_PRIM vbyte* HL_NAME(hl_alc_get_string) (HL_CFFIPointer* device, int param) { - ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : 0; + ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : NULL; const char* result = alcGetString (alcDevice, param); + if (!result) return 0; int length = strlen (result); char* _result = (char*)malloc (length + 1); strcpy (_result, result); @@ -3512,6 +3538,101 @@ namespace lime { } + value lime_alc_capture_open_device (HxString devicename, int frequency, int format, int buffersize) { + + ALCdevice* alcDevice = alcCaptureOpenDevice (devicename.__s, frequency, format, buffersize); + + value ptr = CFFIPointer (alcDevice, gc_alc_object); + alcObjects[alcDevice] = ptr; + return ptr; + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_alc_capture_open_device) (hl_vstring* devicename, int frequency, int format, int buffersize) { + + ALCdevice* alcDevice = alcCaptureOpenDevice (devicename ? (char*)hl_to_utf8 ((const uchar*)devicename->bytes) : 0, frequency, format, buffersize); + + HL_CFFIPointer* ptr = HLCFFIPointer (alcDevice, (hl_finalizer)hl_gc_alc_object); + alcObjects[alcDevice] = ptr; + return ptr; + + } + + + bool lime_alc_capture_close_device (value device) { + + al_gc_mutex.Lock (); + ALCdevice* alcDevice = (ALCdevice*)val_data (device); + alcObjects.erase (alcDevice); + al_gc_mutex.Unlock (); + + return alcCaptureCloseDevice (alcDevice); + + } + + + HL_PRIM bool HL_NAME(hl_alc_capture_close_device) (HL_CFFIPointer* device) { + + al_gc_mutex.Lock (); + ALCdevice* alcDevice = (ALCdevice*)device->ptr; + alcObjects.erase (alcDevice); + al_gc_mutex.Unlock (); + + return alcCaptureCloseDevice (alcDevice); + + } + + + void lime_alc_capture_start (value device) { + + ALCdevice* alcDevice = (ALCdevice*)val_data (device); + alcCaptureStart (alcDevice); + + } + + + HL_PRIM void HL_NAME(hl_alc_capture_start) (HL_CFFIPointer* device) { + + ALCdevice* alcDevice = (ALCdevice*)device->ptr; + alcCaptureStart (alcDevice); + + } + + + void lime_alc_capture_stop (value device) { + + ALCdevice* alcDevice = (ALCdevice*)val_data (device); + alcCaptureStop (alcDevice); + + } + + + HL_PRIM void HL_NAME(hl_alc_capture_stop) (HL_CFFIPointer* device) { + + ALCdevice* alcDevice = (ALCdevice*)device->ptr; + alcCaptureStop (alcDevice); + + } + + + void lime_alc_capture_samples (value device, value buffer, int samples) { + + ALCdevice* alcDevice = (ALCdevice*)val_data (device); + Bytes bytes (buffer); + alcCaptureSamples (alcDevice, bytes.b, samples); + + } + + + HL_PRIM void HL_NAME(hl_alc_capture_samples) (HL_CFFIPointer* device, Bytes* buffer, int samples) { + + ALCdevice* alcDevice = (ALCdevice*)device->ptr; + alcCaptureSamples (alcDevice, buffer->b, samples); + + } + + DEFINE_PRIME3v (lime_al_auxf); @@ -3587,6 +3708,7 @@ namespace lime { DEFINE_PRIME1 (lime_al_is_effect); DEFINE_PRIME1 (lime_al_is_enabled); DEFINE_PRIME1 (lime_al_is_extension_present); + DEFINE_PRIME2 (lime_alc_is_extension_present); DEFINE_PRIME1 (lime_al_is_filter); DEFINE_PRIME1 (lime_al_is_source); DEFINE_PRIME4v (lime_al_listener3f); @@ -3628,6 +3750,11 @@ namespace lime { DEFINE_PRIME1v (lime_alc_process_context); DEFINE_PRIME1v (lime_alc_resume_device); DEFINE_PRIME1v (lime_alc_suspend_context); + DEFINE_PRIME4 (lime_alc_capture_open_device); + DEFINE_PRIME1 (lime_alc_capture_close_device); + DEFINE_PRIME1v (lime_alc_capture_start); + DEFINE_PRIME1v (lime_alc_capture_stop); + DEFINE_PRIME3v (lime_alc_capture_samples); #define _TBYTES _OBJ (_I32 _BYTES) @@ -3711,6 +3838,7 @@ namespace lime { DEFINE_HL_PRIM (_BOOL, hl_al_is_effect, _TCFFIPOINTER); DEFINE_HL_PRIM (_BOOL, hl_al_is_enabled, _I32); DEFINE_HL_PRIM (_BOOL, hl_al_is_extension_present, _STRING); + DEFINE_HL_PRIM (_BOOL, hl_alc_is_extension_present, _TCFFIPOINTER _STRING); DEFINE_HL_PRIM (_BOOL, hl_al_is_filter, _TCFFIPOINTER); DEFINE_HL_PRIM (_BOOL, hl_al_is_source, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_al_listener3f, _I32 _F32 _F32 _F32); @@ -3752,6 +3880,11 @@ namespace lime { DEFINE_HL_PRIM (_VOID, hl_alc_process_context, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_alc_resume_device, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_alc_suspend_context, _TCFFIPOINTER); + DEFINE_HL_PRIM (_TCFFIPOINTER, hl_alc_capture_open_device, _STRING _I32 _I32 _I32); + DEFINE_HL_PRIM (_BOOL, hl_alc_capture_close_device, _TCFFIPOINTER); + DEFINE_HL_PRIM (_VOID, hl_alc_capture_start, _TCFFIPOINTER); + DEFINE_HL_PRIM (_VOID, hl_alc_capture_stop, _TCFFIPOINTER); + DEFINE_HL_PRIM (_VOID, hl_alc_capture_samples, _TCFFIPOINTER _TBYTES _I32); } diff --git a/project/src/ui/FileDialog.cpp b/project/src/ui/FileDialog.cpp index b4ce57fdd1..b740102696 100644 --- a/project/src/ui/FileDialog.cpp +++ b/project/src/ui/FileDialog.cpp @@ -6,298 +6,144 @@ #include +#ifdef HX_WINDOWS +#define tinyfd_selectFolderDialog tinyfd_selectFolderDialogW +#define tinyfd_openFileDialog tinyfd_openFileDialogW +#define tinyfd_saveFileDialog tinyfd_saveFileDialogW -namespace lime { - - - std::string* wstring_to_string (std::wstring* source) { +#define FD_STR(str) L##str +#else +#define FD_STR(str) str +#endif - if (!source) return NULL; +using char_t = lime::FileDialog::char_t; +using string_t = std::basic_string; - int size = std::wcslen (source->c_str ()); - char* temp = (char*)malloc (size + 1); - std::wcstombs (temp, source->c_str (), size); - temp[size] = '\0'; - - std::string* data = new std::string (temp); - free (temp); - return data; +namespace lime { + static bool is_null_or_empty (const char_t* str) { + return str == nullptr || str[0] == 0; } - - std::wstring* FileDialog::OpenDirectory (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { + const char_t* FileDialog::OpenDirectory (const char_t* title, const char_t* filter, const char_t* defaultPath) { // TODO: Filter? - #ifdef HX_WINDOWS - - const wchar_t* path = tinyfd_selectFolderDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0); - - if (path && std::wcslen(path) > 0) { - - std::wstring* _path = new std::wstring (path); - return _path; - - } - - #else - - std::string* _title = wstring_to_string (title); - //std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - const char* path = tinyfd_selectFolderDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL); - - if (_title) delete _title; - //if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const char_t* path = tinyfd_selectFolderDialog(title, defaultPath); - if (path && std::strlen(path) > 0) { + if (!is_null_or_empty(path)) { - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; + return path; } - #endif - return 0; } - std::wstring* FileDialog::OpenFile (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - #ifdef HX_WINDOWS + const char_t* FileDialog::OpenFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - std::vector filters_vec; + std::vector filters_vec; if (filter) { - std::wstring temp (L"*."); - std::wstring line; - std::wstringstream ss(*filter); - while(std::getline(ss, line, L',')) { + string_t temp(FD_STR("*.")); + string_t line; + std::basic_stringstream ss(filter); + while(std::getline(ss, line, FD_STR(','))) { filters_vec.push_back(temp + line); } } const int numFilters = filter ? filters_vec.size() : 1; - const wchar_t **filters = new const wchar_t*[numFilters]; + const char_t **filters = new const char_t*[numFilters]; if (filter && numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = const_cast(filters_vec[index].c_str()); } } else { filters[0] = NULL; } - const wchar_t* path = tinyfd_openFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? numFilters : 0, filter ? filters : NULL, NULL, 0); + const char_t* path = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 0); delete[] filters; - if (path && std::wcslen(path) > 0) { + if (!is_null_or_empty(path)) { - std::wstring* _path = new std::wstring (path); - return _path; + return path; } - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - std::vector filters_vec; - if (_filter) { - std::string line; - std::stringstream ss(*_filter); - while(std::getline(ss, line, ',')) { - line.insert (0, "*."); - filters_vec.push_back(line); - } - } - - const int numFilters = _filter ? filters_vec.size() : 1; - const char **filters = new const char*[numFilters]; - if (_filter && numFilters > 0) { - for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); - } - } else { - filters[0] = NULL; - } - - const char* path = tinyfd_openFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? numFilters : 0, _filter ? filters : NULL, NULL, 0); - - delete[] filters; - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (path && std::strlen(path) > 0) { - - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; - - } - - #endif - return 0; } - void FileDialog::OpenFiles (std::vector* files, std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - std::wstring* __paths = 0; - - #ifdef HX_WINDOWS + std::vector FileDialog::OpenFiles (const char_t* title, const char_t* filter, const char_t* defaultPath) { + std::vector files; - std::vector filters_vec; + std::vector filters_vec; if (filter) { - std::wstring temp (L"*."); - std::wstring line; - std::wstringstream ss(*filter); - while(std::getline(ss, line, L',')) { + string_t temp(FD_STR("*.")); + string_t line; + std::basic_stringstream ss(filter); + while(std::getline(ss, line, FD_STR(','))) { filters_vec.push_back(temp + line); } } const int numFilters = filter ? filters_vec.size() : 1; - const wchar_t **filters = new const wchar_t*[numFilters]; + const char_t **filters = new const char_t*[numFilters]; if (filter && numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = const_cast(filters_vec[index].c_str()); } } else { filters[0] = NULL; } - const wchar_t* paths = tinyfd_openFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? numFilters : 0, filter ? filters : NULL, NULL, 1); + const char_t* paths = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 1); delete[] filters; - if (paths) { + if (!is_null_or_empty(paths)) { - __paths = new std::wstring (paths); + char_t sep = FD_STR('|'); - } - - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); + const char_t* start = paths, + * cur = paths; - std::vector filters_vec; - if (_filter) { - std::string line; - std::stringstream ss(*_filter); - while(std::getline(ss, line, ',')) { - line.insert (0, "*."); - filters_vec.push_back(line); - } - } + while (*cur) { + if (*cur == sep) { + files.emplace_back(start, cur - start); + start = cur + 1; + } - const int numFilters = _filter ? filters_vec.size() : 1; - const char **filters = new const char*[numFilters]; - if (_filter && numFilters > 0) { - for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + cur++; } - } else { - filters[0] = NULL; - } - - const char* paths = tinyfd_openFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? numFilters : 0, _filter ? filters : NULL, NULL, 1); - delete[] filters; - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (paths) { - - std::string _paths = std::string (paths); - __paths = new std::wstring (_paths.begin (), _paths.end ()); + files.emplace_back(start, cur - start); } - #endif - - if (__paths) { - - std::wstring sep = L"|"; - - std::size_t start = 0, end = 0; - - while ((end = __paths->find (sep, start)) != std::wstring::npos) { - - files->push_back (new std::wstring (__paths->substr (start, end - start).c_str ())); - start = end + 1; - - } - - files->push_back (new std::wstring (__paths->substr (start).c_str ())); - - } + return files; } - std::wstring* FileDialog::SaveFile (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - #ifdef HX_WINDOWS + const char_t* FileDialog::SaveFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - std::wstring temp (L"*."); - const wchar_t* filters[] = { filter ? (temp + *filter).c_str () : NULL }; + string_t temp(FD_STR("*.")); + const char_t* filters[] = { filter ? (temp + *filter).c_str () : NULL }; - const wchar_t* path = tinyfd_saveFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? 1 : 0, filter ? filters : NULL, NULL); + const char_t* path = tinyfd_saveFileDialog (title, defaultPath, filter ? 1 : 0, filter ? filters : NULL, NULL); - if (path && std::wcslen(path) > 0) { + if (!is_null_or_empty(path)) { - std::wstring* _path = new std::wstring (path); - return _path; + return path; } - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - const char* filters[] = { NULL }; - - if (_filter) { - - _filter->insert (0, "*."); - filters[0] = _filter->c_str (); - - } - - const char* path = tinyfd_saveFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? 1 : 0, _filter ? filters : NULL, NULL); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (path && std::strlen(path) > 0) { - - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; - - } - - #endif - return 0; } diff --git a/project/src/ui/GamepadEvent.cpp b/project/src/ui/GamepadEvent.cpp index 64fa1c5384..6c4b3fd74b 100644 --- a/project/src/ui/GamepadEvent.cpp +++ b/project/src/ui/GamepadEvent.cpp @@ -11,6 +11,7 @@ namespace lime { static double id_axis; static int id_button; static int id_id; + static int id_timestamp; static int id_type; static int id_value; static bool init = false; @@ -22,6 +23,7 @@ namespace lime { axisValue = 0; button = 0; id = 0; + timestamp = 0; type = GAMEPAD_AXIS_MOVE; } @@ -38,6 +40,7 @@ namespace lime { id_axis = val_id ("axis"); id_button = val_id ("button"); id_id = val_id ("id"); + id_timestamp = val_id ("timestamp"); id_type = val_id ("type"); id_value = val_id ("axisValue"); init = true; @@ -49,6 +52,7 @@ namespace lime { alloc_field (object, id_axis, alloc_int (event->axis)); alloc_field (object, id_button, alloc_int (event->button)); alloc_field (object, id_id, alloc_int (event->id)); + alloc_field (object, id_timestamp, alloc_int (event->timestamp)); alloc_field (object, id_type, alloc_int (event->type)); alloc_field (object, id_value, alloc_float (event->axisValue)); @@ -59,6 +63,7 @@ namespace lime { eventObject->axis = event->axis; eventObject->button = event->button; eventObject->id = event->id; + eventObject->timestamp = event->timestamp; eventObject->type = event->type; eventObject->axisValue = event->axisValue; @@ -71,4 +76,4 @@ namespace lime { } -} \ No newline at end of file +} diff --git a/project/src/ui/KeyEvent.cpp b/project/src/ui/KeyEvent.cpp index 42acd15560..871d8d1146 100644 --- a/project/src/ui/KeyEvent.cpp +++ b/project/src/ui/KeyEvent.cpp @@ -10,6 +10,7 @@ namespace lime { static double id_keyCode; static int id_modifier; + static int id_timestamp; static int id_type; static int id_windowID; static bool init = false; @@ -19,6 +20,7 @@ namespace lime { keyCode = 0; modifier = 0; + timestamp = 0; type = KEY_DOWN; windowID = 0; @@ -35,6 +37,7 @@ namespace lime { id_keyCode = val_id ("keyCode"); id_modifier = val_id ("modifier"); + id_timestamp = val_id ("timestamp"); id_type = val_id ("type"); id_windowID = val_id ("windowID"); init = true; @@ -45,6 +48,7 @@ namespace lime { alloc_field (object, id_keyCode, alloc_float (event->keyCode)); alloc_field (object, id_modifier, alloc_int (event->modifier)); + alloc_field (object, id_timestamp, alloc_int (event->timestamp)); alloc_field (object, id_type, alloc_int (event->type)); alloc_field (object, id_windowID, alloc_int (event->windowID)); @@ -54,6 +58,7 @@ namespace lime { eventObject->keyCode = event->keyCode; eventObject->modifier = event->modifier; + eventObject->timestamp = event->timestamp; eventObject->type = event->type; eventObject->windowID = event->windowID; @@ -66,4 +71,4 @@ namespace lime { } -} \ No newline at end of file +} diff --git a/run.n b/run.n index deae46fd3a..1436727e31 100644 Binary files a/run.n and b/run.n differ diff --git a/src/lime/_internal/backend/flash/FlashAudioInput.hx b/src/lime/_internal/backend/flash/FlashAudioInput.hx new file mode 100644 index 0000000000..59f0012252 --- /dev/null +++ b/src/lime/_internal/backend/flash/FlashAudioInput.hx @@ -0,0 +1,288 @@ +package lime._internal.backend.flash; + +import flash.events.SampleDataEvent; +import flash.media.Microphone; +import haxe.io.Bytes; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; + +private typedef AudioInputData = +{ + var bytes:Bytes; + var offset:Int; +} + +@:access(lime.media.AudioInput) +class FlashAudioInput +{ + private static inline var MAX_QUEUED_MS = 10000; + + private var buffers:Array; + private var frameSize:Int; + private var microphone:Microphone; + private var parent:AudioInput; + private var queuedBytes:Int; + + public static function getDefaultDevice():AudioInputDevice + { + if (!isSupported()) + { + return null; + } + + var microphone = Microphone.getMicrophone(); + + if (microphone != null) + { + return new AudioInputDevice(microphone.name, Std.string(microphone.index), true); + } + + var devices = getDevices(); + return devices.length > 0 ? devices[0] : null; + } + + public static function getDevices():Array + { + var devices:Array = []; + + if (!isSupported() || Microphone.names == null) + { + return devices; + } + + for (i in 0...Microphone.names.length) + { + var name = Std.string(Microphone.names[i]); + devices.push(new AudioInputDevice(name, Std.string(i), i == 0)); + } + + return devices; + } + + public static function isSupported():Bool + { + return Microphone.isSupported; + } + + public function new(parent:AudioInput) + { + this.parent = parent; + + buffers = []; + frameSize = getFrameSize(); + queuedBytes = 0; + } + + public function dispose():Void + { + stop(); + buffers.resize(0); + queuedBytes = 0; + } + + public function getSamplesAvailable():Int + { + if (frameSize <= 0) + { + return 0; + } + + return Std.int(queuedBytes / frameSize); + } + + public function read(buffer:Bytes, samples:Int):Int + { + if (buffer == null || samples <= 0 || frameSize <= 0) + { + return 0; + } + + var samplesToRead = samples; + var available = getSamplesAvailable(); + var maxSamples = Std.int(buffer.length / frameSize); + + if (samplesToRead > available) + { + samplesToRead = available; + } + + if (samplesToRead > maxSamples) + { + samplesToRead = maxSamples; + } + + if (samplesToRead <= 0) + { + return 0; + } + + var bytesToRead = samplesToRead * frameSize; + var remaining = bytesToRead; + var writePosition = 0; + + while (remaining > 0 && buffers.length > 0) + { + var data = buffers[0]; + var availableBytes = data.bytes.length - data.offset; + var copyBytes = availableBytes < remaining ? availableBytes : remaining; + + buffer.blit(writePosition, data.bytes, data.offset, copyBytes); + + data.offset += copyBytes; + writePosition += copyBytes; + remaining -= copyBytes; + queuedBytes -= copyBytes; + + if (data.offset >= data.bytes.length) + { + buffers.shift(); + } + } + + return Std.int((bytesToRead - remaining) / frameSize); + } + + public function start():Bool + { + if (parent.running || !isSupported() || !isFormatSupported()) + { + return parent.running; + } + + var index = -1; + + if (parent.device != null && !parent.device.isDefault && parent.device.id != null) + { + var parsedIndex = Std.parseInt(parent.device.id); + + if (parsedIndex != null) + { + index = parsedIndex; + } + } + + microphone = Microphone.getMicrophone(index); + + if (microphone == null) + { + return false; + } + + microphone.rate = getMicrophoneRate(parent.sampleRate); + parent.sampleRate = microphone.rate * 1000; + + microphone.setLoopBack(false); + microphone.setSilenceLevel(0, -1); + microphone.setUseEchoSuppression(false); + microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, microphone_onSampleData); + + return true; + } + + public function stop():Void + { + parent.running = false; + + if (microphone != null) + { + microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, microphone_onSampleData); + microphone = null; + } + } + + private function appendSample(bytes:Bytes, position:Int, sample:Float):Int + { + if (sample > 1) + { + sample = 1; + } + else if (sample < -1) + { + sample = -1; + } + + if (parent.bitsPerSample == 8) + { + bytes.set(position++, Std.int((sample * 0.5 + 0.5) * 255) & 0xFF); + } + else + { + var value = sample < 0 ? Std.int(sample * 32768) : Std.int(sample * 32767); + bytes.set(position++, value & 0xFF); + bytes.set(position++, (value >> 8) & 0xFF); + } + + return position; + } + + private function getFrameSize():Int + { + return Std.int((parent.channels * parent.bitsPerSample) / 8); + } + + private function getMicrophoneRate(sampleRate:Int):Int + { + if (sampleRate >= 44100) + { + return 44; + } + else if (sampleRate >= 22050) + { + return 22; + } + else if (sampleRate >= 11025) + { + return 11; + } + else if (sampleRate >= 8000) + { + return 8; + } + + return 5; + } + + private function isFormatSupported():Bool + { + return (parent.channels == 1 || parent.channels == 2) && (parent.bitsPerSample == 8 || parent.bitsPerSample == 16); + } + + private function microphone_onSampleData(event:SampleDataEvent):Void + { + if (!parent.running || frameSize <= 0) + { + return; + } + + event.data.position = 0; + + var samples = Std.int(event.data.bytesAvailable / 4); + var bytes = Bytes.alloc(samples * frameSize); + var position = 0; + + for (i in 0...samples) + { + var sample = event.data.readFloat(); + + for (channel in 0...parent.channels) + { + position = appendSample(bytes, position, sample); + } + } + + buffers.push({bytes: bytes, offset: 0}); + queuedBytes += bytes.length; + trimQueue(); + } + + private function trimQueue():Void + { + var maxQueuedBytes = Std.int((parent.sampleRate * MAX_QUEUED_MS / 1000) * frameSize); + + while (queuedBytes > maxQueuedBytes && buffers.length > 0) + { + var data = buffers.shift(); + queuedBytes -= data.bytes.length - data.offset; + } + } +} diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index e451eb3545..356683065c 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -11,6 +11,7 @@ import lime.media.AudioManager; import lime.system.Orientation; import lime.system.Sensor; import lime.system.SensorType; +import lime.system.System; import lime.ui.GamepadAxis; import lime.ui.KeyCode; import lime.ui.KeyModifier; @@ -444,10 +445,11 @@ class HTML5Application var keyCode = cast convertKeyCode(event.keyCode != null ? event.keyCode : event.which); var modifier = (event.shiftKey ? (KeyModifier.SHIFT) : 0) | (event.ctrlKey ? (KeyModifier.CTRL) : 0) | (event.altKey ? (KeyModifier.ALT) : 0) | (event.metaKey ? (KeyModifier.META) : 0); + var timestamp = Std.int(event.timeStamp); if (event.type == "keydown") { - parent.window.onKeyDown.dispatch(keyCode, modifier); + @:privateAccess parent.window.onKeyDown.__dispatchWithTimestamp(timestamp, keyCode, modifier); if (parent.window.onKeyDown.canceled && event.cancelable) { @@ -456,7 +458,7 @@ class HTML5Application } else { - parent.window.onKeyUp.dispatch(keyCode, modifier); + @:privateAccess parent.window.onKeyUp.__dispatchWithTimestamp(timestamp, keyCode, modifier); if (parent.window.onKeyUp.canceled && event.cancelable) { @@ -601,18 +603,19 @@ class HTML5Application for (i in 0...data.buttons.length) { value = data.buttons[i].value; + var timestamp = System.getTimer(); if (value != cache.buttons[i]) { if (i == 6) { joystick.onAxisMove.dispatch(data.axes.length, value); - if (gamepad != null) gamepad.onAxisMove.dispatch(GamepadAxis.TRIGGER_LEFT, value); + if (gamepad != null) @:privateAccess gamepad.onAxisMove.__dispatchWithTimestamp(timestamp, GamepadAxis.TRIGGER_LEFT, value); } else if (i == 7) { joystick.onAxisMove.dispatch(data.axes.length + 1, value); - if (gamepad != null) gamepad.onAxisMove.dispatch(GamepadAxis.TRIGGER_RIGHT, value); + if (gamepad != null) @:privateAccess gamepad.onAxisMove.__dispatchWithTimestamp(timestamp, GamepadAxis.TRIGGER_RIGHT, value); } else { @@ -649,11 +652,11 @@ class HTML5Application if (value > 0) { - gamepad.onButtonDown.dispatch(button); + @:privateAccess gamepad.onButtonDown.__dispatchWithTimestamp(timestamp, button); } else { - gamepad.onButtonUp.dispatch(button); + @:privateAccess gamepad.onButtonUp.__dispatchWithTimestamp(timestamp, button); } } } @@ -667,7 +670,7 @@ class HTML5Application if (data.axes[i] != cache.axes[i]) { joystick.onAxisMove.dispatch(i, data.axes[i]); - if (gamepad != null) gamepad.onAxisMove.dispatch(i, data.axes[i]); + if (gamepad != null) @:privateAccess gamepad.onAxisMove.__dispatchWithTimestamp(System.getTimer(), i, data.axes[i]); cache.axes[i] = data.axes[i]; } } diff --git a/src/lime/_internal/backend/html5/HTML5AudioInput.hx b/src/lime/_internal/backend/html5/HTML5AudioInput.hx new file mode 100644 index 0000000000..856ddd8aad --- /dev/null +++ b/src/lime/_internal/backend/html5/HTML5AudioInput.hx @@ -0,0 +1,444 @@ +package lime._internal.backend.html5; + +import haxe.io.Bytes; +import js.Browser; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; + +private typedef AudioInputData = +{ + var bytes:Bytes; + var offset:Int; +} + +@:access(lime.media.AudioInput) +class HTML5AudioInput +{ + private static inline var MAX_QUEUED_MS = 10000; + + private static var cachedDevices:Array; + private static var enumeratingDevices:Bool; + + private var audioContext:Dynamic; + private var buffers:Array; + private var disposed:Bool; + private var frameSize:Int; + private var mediaStream:Dynamic; + private var parent:AudioInput; + private var processorNode:Dynamic; + private var queuedBytes:Int; + private var sourceNode:Dynamic; + private var starting:Bool; + + public static function getDefaultDevice():AudioInputDevice + { + if (!isSupported()) + { + return null; + } + + return new AudioInputDevice("Default Audio Input", null, true); + } + + public static function getDevices():Array + { + refreshDevices(); + + if (cachedDevices != null) + { + return cachedDevices.copy(); + } + + var defaultDevice = getDefaultDevice(); + return defaultDevice != null ? [defaultDevice] : []; + } + + public static function isSupported():Bool + { + var navigator:Dynamic = Browser.navigator; + return navigator != null && navigator.mediaDevices != null && navigator.mediaDevices.getUserMedia != null; + } + + public function new(parent:AudioInput) + { + this.parent = parent; + + buffers = []; + frameSize = getFrameSize(); + queuedBytes = 0; + } + + public function dispose():Void + { + disposed = true; + stop(); + buffers.resize(0); + queuedBytes = 0; + } + + public function getSamplesAvailable():Int + { + if (frameSize <= 0) + { + return 0; + } + + return Std.int(queuedBytes / frameSize); + } + + public function read(buffer:Bytes, samples:Int):Int + { + if (buffer == null || samples <= 0 || frameSize <= 0) + { + return 0; + } + + var samplesToRead = samples; + var available = getSamplesAvailable(); + var maxSamples = Std.int(buffer.length / frameSize); + + if (samplesToRead > available) + { + samplesToRead = available; + } + + if (samplesToRead > maxSamples) + { + samplesToRead = maxSamples; + } + + if (samplesToRead <= 0) + { + return 0; + } + + var bytesToRead = samplesToRead * frameSize; + var remaining = bytesToRead; + var writePosition = 0; + + while (remaining > 0 && buffers.length > 0) + { + var data = buffers[0]; + var availableBytes = data.bytes.length - data.offset; + var copyBytes = availableBytes < remaining ? availableBytes : remaining; + + buffer.blit(writePosition, data.bytes, data.offset, copyBytes); + + data.offset += copyBytes; + writePosition += copyBytes; + remaining -= copyBytes; + queuedBytes -= copyBytes; + + if (data.offset >= data.bytes.length) + { + buffers.shift(); + } + } + + return Std.int((bytesToRead - remaining) / frameSize); + } + + public function start():Bool + { + if (disposed || starting || parent.running || !isSupported() || !isFormatSupported()) + { + return parent.running; + } + + starting = true; + audioContext = createAudioContext(); + + if (audioContext == null) + { + starting = false; + return false; + } + + if (audioContext.resume != null) + { + audioContext.resume(); + } + + var constraints:Dynamic = + { + audio: + { + channelCount: parent.channels, + echoCancellation: false, + noiseSuppression: false, + autoGainControl: false + } + }; + + if (parent.sampleRate > 0) + { + constraints.audio.sampleRate = parent.sampleRate; + } + + if (parent.device != null && !parent.device.isDefault && parent.device.id != null && parent.device.id != "") + { + constraints.audio.deviceId = {exact: parent.device.id}; + } + + var navigator:Dynamic = Browser.navigator; + var promise:Dynamic = navigator.mediaDevices.getUserMedia(constraints); + + promise.then(function(stream) + { + if (disposed || !starting) + { + stopMediaStream(stream); + return; + } + + open(stream); + }, function(error) + { + starting = false; + parent.running = false; + }); + + return false; + } + + public function stop():Void + { + starting = false; + parent.running = false; + + if (sourceNode != null) + { + sourceNode.disconnect(); + sourceNode = null; + } + + if (processorNode != null) + { + processorNode.disconnect(); + processorNode.onaudioprocess = null; + processorNode = null; + } + + if (audioContext != null && audioContext.close != null) + { + audioContext.close(); + audioContext = null; + } + + if (mediaStream != null) + { + stopMediaStream(mediaStream); + mediaStream = null; + } + } + + private function appendSamples(event:Dynamic):Void + { + var outputBuffer:Dynamic = event.outputBuffer; + + if (outputBuffer != null) + { + for (channel in 0...outputBuffer.numberOfChannels) + { + var output = outputBuffer.getChannelData(channel); + + for (frame in 0...outputBuffer.length) + { + output[frame] = 0; + } + } + } + + if (!parent.running || disposed || frameSize <= 0) + { + return; + } + + var inputBuffer:Dynamic = event.inputBuffer; + var frames:Int = inputBuffer.length; + var inputChannels:Int = inputBuffer.numberOfChannels; + var channelData:Array = []; + + for (channel in 0...parent.channels) + { + var sourceChannel = channel < inputChannels ? channel : 0; + channelData.push(inputBuffer.getChannelData(sourceChannel)); + } + + var bytes = Bytes.alloc(frames * frameSize); + var position = 0; + + for (frame in 0...frames) + { + for (channel in 0...parent.channels) + { + var sample:Float = channelData[channel][frame]; + + if (sample > 1) + { + sample = 1; + } + else if (sample < -1) + { + sample = -1; + } + + if (parent.bitsPerSample == 8) + { + bytes.set(position++, Std.int((sample * 0.5 + 0.5) * 255) & 0xFF); + } + else + { + var value = sample < 0 ? Std.int(sample * 32768) : Std.int(sample * 32767); + bytes.set(position++, value & 0xFF); + bytes.set(position++, (value >> 8) & 0xFF); + } + } + } + + buffers.push({bytes: bytes, offset: 0}); + queuedBytes += bytes.length; + trimQueue(); + } + + private function createAudioContext():Dynamic + { + var window:Dynamic = Browser.window; + var audioContextClass:Dynamic = window.AudioContext != null ? window.AudioContext : window.webkitAudioContext; + + if (audioContextClass == null) + { + return null; + } + + try + { + return untyped #if haxe4 js.Syntax.code #else __js__ #end ("new audioContextClass({ sampleRate: {0} })", parent.sampleRate); + } + catch (e:Dynamic) + { + return untyped #if haxe4 js.Syntax.code #else __js__ #end ("new audioContextClass()"); + } + } + + private function getFrameSize():Int + { + return Std.int((parent.channels * parent.bitsPerSample) / 8); + } + + private function getProcessorBufferSize():Int + { + var size = 256; + + while (size < parent.bufferSize && size < 16384) + { + size *= 2; + } + + return size; + } + + private function isFormatSupported():Bool + { + return (parent.channels == 1 || parent.channels == 2) && (parent.bitsPerSample == 8 || parent.bitsPerSample == 16); + } + + private function open(stream:Dynamic):Void + { + if (audioContext == null) + { + starting = false; + stopMediaStream(stream); + return; + } + + if (audioContext.sampleRate != null) + { + parent.sampleRate = Std.int(audioContext.sampleRate); + } + + mediaStream = stream; + sourceNode = audioContext.createMediaStreamSource(stream); + processorNode = audioContext.createScriptProcessor(getProcessorBufferSize(), parent.channels, parent.channels); + + processorNode.onaudioprocess = appendSamples; + sourceNode.connect(processorNode); + processorNode.connect(audioContext.destination); + + if (audioContext.resume != null) + { + audioContext.resume(); + } + + starting = false; + parent.running = true; + refreshDevices(); + } + + private static function refreshDevices():Void + { + if (enumeratingDevices || !isSupported()) + { + return; + } + + enumeratingDevices = true; + + var navigator:Dynamic = Browser.navigator; + var promise:Dynamic = navigator.mediaDevices.enumerateDevices(); + + promise.then(function(devices) + { + var result:Array = []; + var length:Int = devices.length; + + for (i in 0...length) + { + var device:Dynamic = devices[i]; + + if (device.kind == "audioinput") + { + var label:String = device.label != null && device.label != "" ? device.label : "Audio Input"; + result.push(new AudioInputDevice(label, device.deviceId, result.length == 0)); + } + } + + if (result.length > 0) + { + cachedDevices = result; + } + + enumeratingDevices = false; + }, function(error) + { + enumeratingDevices = false; + }); + } + + private function stopMediaStream(stream:Dynamic):Void + { + if (stream == null || stream.getTracks == null) + { + return; + } + + var tracks:Dynamic = stream.getTracks(); + var length:Int = tracks.length; + + for (i in 0...length) + { + tracks[i].stop(); + } + } + + private function trimQueue():Void + { + var maxQueuedBytes = Std.int((parent.sampleRate * MAX_QUEUED_MS / 1000) * frameSize); + + while (queuedBytes > maxQueuedBytes && buffers.length > 0) + { + var data = buffers.shift(); + queuedBytes -= data.bytes.length - data.offset; + } + } +} diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index 8e7b662b08..e36aa53e34 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -320,7 +320,8 @@ class HTML5Window if (forceWebGL || (!forceCanvas && (!Reflect.hasField(contextAttributes, "hardware") || contextAttributes.hardware))) { - var transparentBackground = Reflect.hasField(contextAttributes, "background") && contextAttributes.background == null; + var transparentBackground = (Reflect.hasField(contextAttributes, "background") && contextAttributes.background == null) + || parent.transparent; var colorDepth = Reflect.hasField(contextAttributes, "colorDepth") ? contextAttributes.colorDepth : 16; var options = diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 1be8e8df77..ad45bbaba0 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -292,13 +292,14 @@ class NativeApplication { case AXIS_MOVE: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onAxisMove.dispatch(gamepadEventInfo.axis, gamepadEventInfo.axisValue); + if (gamepad != null) @:privateAccess gamepad.onAxisMove.__dispatchWithTimestamp(gamepadEventInfo.timestamp, gamepadEventInfo.axis, + gamepadEventInfo.axisValue); case BUTTON_DOWN: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onButtonDown.dispatch(gamepadEventInfo.button); + if (gamepad != null) @:privateAccess gamepad.onButtonDown.__dispatchWithTimestamp(gamepadEventInfo.timestamp, gamepadEventInfo.button); case BUTTON_UP: var gamepad = Gamepad.devices.get(gamepadEventInfo.id); - if (gamepad != null) gamepad.onButtonUp.dispatch(gamepadEventInfo.button); + if (gamepad != null) @:privateAccess gamepad.onButtonUp.__dispatchWithTimestamp(gamepadEventInfo.timestamp, gamepadEventInfo.button); case CONNECT: Gamepad.__connect(gamepadEventInfo.id); @@ -345,9 +346,9 @@ class NativeApplication switch (type) { case KEY_DOWN: - window.onKeyDown.dispatch(keyCode, modifier); + @:privateAccess window.onKeyDown.__dispatchWithTimestamp(keyEventInfo.timestamp, keyCode, modifier); case KEY_UP: - window.onKeyUp.dispatch(keyCode, modifier); + @:privateAccess window.onKeyUp.__dispatchWithTimestamp(keyEventInfo.timestamp, keyCode, modifier); } #if (windows || linux) @@ -466,6 +467,9 @@ class NativeApplication switch (renderEventInfo.type) { case RENDER: + #if lime_skip_invisible_windows + if (!window.visible) continue; + #end if (window.context != null) { window.__backend.render(); @@ -776,19 +780,21 @@ class NativeApplication public var id:Int; public var type:GamepadEventType; public var axisValue:Float; + public var timestamp:Int; - public function new(type:GamepadEventType = null, id:Int = 0, button:Int = 0, axis:Int = 0, value:Float = 0) + public function new(type:GamepadEventType = null, id:Int = 0, button:Int = 0, axis:Int = 0, value:Float = 0, timestamp:Int = 0) { this.type = type; this.id = id; this.button = button; this.axis = axis; this.axisValue = value; + this.timestamp = timestamp; } public function clone():GamepadEventInfo { - return new GamepadEventInfo(type, id, button, axis, axisValue); + return new GamepadEventInfo(type, id, button, axis, axisValue, timestamp); } } @@ -843,18 +849,20 @@ class NativeApplication public var modifier:Int; public var type:KeyEventType; public var windowID:Int; + public var timestamp:Int; - public function new(type:KeyEventType = null, windowID:Int = 0, keyCode:Float = 0, modifier:Int = 0) + public function new(type:KeyEventType = null, windowID:Int = 0, keyCode:Float = 0, modifier:Int = 0, timestamp:Int = 0) { this.type = type; this.windowID = windowID; this.keyCode = keyCode; this.modifier = modifier; + this.timestamp = timestamp; } public function clone():KeyEventInfo { - return new KeyEventInfo(type, windowID, keyCode, modifier); + return new KeyEventInfo(type, windowID, keyCode, modifier, timestamp); } } diff --git a/src/lime/_internal/backend/native/NativeAudioInput.hx b/src/lime/_internal/backend/native/NativeAudioInput.hx new file mode 100644 index 0000000000..813a146684 --- /dev/null +++ b/src/lime/_internal/backend/native/NativeAudioInput.hx @@ -0,0 +1,275 @@ +package lime._internal.backend.native; + +import haxe.io.Bytes; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; +#if (!lime_doc_gen || lime_openal) +import lime.media.openal.AL; +import lime.media.openal.ALC; +import lime.media.openal.ALDevice; +#end + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime.media.AudioInput) +class NativeAudioInput +{ + private var disposed:Bool; + private var handle:#if (!lime_doc_gen || lime_openal) ALDevice #else Dynamic #end; + private var parent:AudioInput; + private var started:Bool; + + public static function getDefaultDevice():AudioInputDevice + { + #if (!lime_doc_gen || lime_openal) + var name = ALC.getString(null, ALC.CAPTURE_DEFAULT_DEVICE_SPECIFIER); + + if (name == null || name == "") + { + return null; + } + + return new AudioInputDevice(name, name, true); + #else + return null; + #end + } + + public static function getDevices():Array + { + #if (!lime_doc_gen || lime_openal) + var defaultDevice = getDefaultDevice(); + var defaultName = defaultDevice != null ? defaultDevice.name : null; + var devices = parseDeviceList(ALC.getString(null, ALC.CAPTURE_DEVICE_SPECIFIER), defaultName); + + if (devices.length == 0 && defaultDevice != null) + { + devices.push(defaultDevice); + } + + return devices; + #else + return []; + #end + } + + public static function isSupported():Bool + { + return getDefaultDevice() != null || getDevices().length > 0; + } + + public function new(parent:AudioInput) + { + this.parent = parent; + + open(); + } + + public function dispose():Void + { + if (disposed) + { + return; + } + + stop(); + + #if (!lime_doc_gen || lime_openal) + if (handle != null) + { + ALC.captureCloseDevice(handle); + handle = null; + } + #end + + disposed = true; + } + + public function getSamplesAvailable():Int + { + #if (!lime_doc_gen || lime_openal) + if (handle == null) + { + return 0; + } + + var values = ALC.getIntegerv(handle, ALC.CAPTURE_SAMPLES, 1); + + if (values != null && values.length > 0) + { + return values[0]; + } + #end + + return 0; + } + + public function read(buffer:Bytes, samples:Int):Int + { + #if (!lime_doc_gen || lime_openal) + if (!started || handle == null || buffer == null || samples <= 0) + { + return 0; + } + + var available = getSamplesAvailable(); + + if (available <= 0) + { + return 0; + } + + var samplesToRead = samples < available ? samples : available; + var frameSize = getFrameSize(); + + if (frameSize <= 0) + { + return 0; + } + + var maxSamples = Std.int(buffer.length / frameSize); + + if (samplesToRead > maxSamples) + { + samplesToRead = maxSamples; + } + + if (samplesToRead <= 0) + { + return 0; + } + + ALC.captureSamples(handle, buffer, samplesToRead); + return samplesToRead; + #end + + return 0; + } + + public function start():Bool + { + #if (!lime_doc_gen || lime_openal) + if (disposed) + { + return false; + } + + if (handle == null) + { + open(); + } + + if (handle == null) + { + return false; + } + + ALC.captureStart(handle); + started = true; + return true; + #else + return false; + #end + } + + public function stop():Void + { + #if (!lime_doc_gen || lime_openal) + if (started && handle != null) + { + ALC.captureStop(handle); + } + #end + + started = false; + } + + private function getFormat():Int + { + #if (!lime_doc_gen || lime_openal) + if (parent.channels == 1) + { + if (parent.bitsPerSample == 8) + { + return AL.FORMAT_MONO8; + } + else if (parent.bitsPerSample == 16) + { + return AL.FORMAT_MONO16; + } + } + else if (parent.channels == 2) + { + if (parent.bitsPerSample == 8) + { + return AL.FORMAT_STEREO8; + } + else if (parent.bitsPerSample == 16) + { + return AL.FORMAT_STEREO16; + } + } + #end + + return 0; + } + + private function getFrameSize():Int + { + return Std.int((parent.channels * parent.bitsPerSample) / 8); + } + + private function open():Void + { + #if (!lime_doc_gen || lime_openal) + if (handle != null) + { + return; + } + + var format = getFormat(); + + if (format == 0) + { + return; + } + + var deviceName = parent.device != null && !parent.device.isDefault ? parent.device.id : null; + handle = ALC.captureOpenDevice(deviceName, parent.sampleRate, format, parent.bufferSize); + #end + } + + private static function parseDeviceList(value:String, defaultName:String):Array + { + var devices = []; + + if (value == null || value == "") + { + return devices; + } + + var hasDefault = false; + var names = value.split(String.fromCharCode(0)); + + for (name in names) + { + if (name == null || name == "") + { + continue; + } + + var isDefault = name == defaultName; + hasDefault = hasDefault || isDefault; + devices.push(new AudioInputDevice(name, name, isDefault)); + } + + if (!hasDefault && defaultName != null && defaultName != "") + { + devices.unshift(new AudioInputDevice(defaultName, defaultName, true)); + } + + return devices; + } +} diff --git a/src/lime/_internal/backend/native/NativeAudioSource.hx b/src/lime/_internal/backend/native/NativeAudioSource.hx index 363aa63117..e881c5166e 100644 --- a/src/lime/_internal/backend/native/NativeAudioSource.hx +++ b/src/lime/_internal/backend/native/NativeAudioSource.hx @@ -32,6 +32,7 @@ class NativeAudioSource #if lime_openalsoft private static var hasDirectChannelsExt:Null; #end + private static var activeSources:Array = []; private var buffers:Array; private var bufferTimeBlocks:Array; @@ -46,8 +47,19 @@ class NativeAudioSource private var playing:Bool; private var position:Vector4; private var queuedBufferCount:Int; + private var queuedBufferLoopCounts:Array; + private var queuedStreamLoopCount:Int; private var readArray:UInt8Array; private var readBuffer:Bytes; + private var recoveryCompleted:Bool; + private var recoveryGain:Float; + private var recoveryLength:Null; + private var recoveryLoops:Int; + private var recoveryPending:Bool; + private var recoveryPitch:Float; + private var recoveryPlaying:Bool; + private var recoveryPosition:Vector4; + private var recoveryTime:Int; private var sdlSoundStream:CFFIPointer; private var samples:Int; private var stream:Bool; @@ -64,10 +76,31 @@ class NativeAudioSource this.parent = parent; position = new Vector4(); + activeSources.push(this); + } + + @:allow(lime.media.AudioManager) + private static function prepareAudioContextRecovery():Void + { + for (source in activeSources.copy()) + { + source.prepareAudioContextRecoverySource(); + } + } + + @:allow(lime.media.AudioManager) + private static function restoreAudioContextRecovery():Void + { + for (source in activeSources.copy()) + { + source.restoreAudioContextRecoverySource(); + } } public function dispose():Void { + activeSources.remove(this); + if (handle != null) { stop(); @@ -100,6 +133,8 @@ class NativeAudioSource streamExhausted = false; streamPosition = 0; queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; ownsVorbisStream = false; clearVorbisStream(); clearSDLSoundStream(); @@ -195,8 +230,15 @@ class NativeAudioSource if (parent.buffer.__srcBuffer != null) { AL.bufferData(parent.buffer.__srcBuffer, format, parent.buffer.data, parent.buffer.data.length, parent.buffer.sampleRate); + parent.buffer.__srcBufferContext = AudioManager.__contextGeneration; } } + else if (parent.buffer.__srcBufferContext != AudioManager.__contextGeneration) + { + parent.buffer.__srcBuffer = null; + init(); + return; + } dataLength = parent.buffer.data.length; @@ -487,6 +529,79 @@ class NativeAudioSource return length - (length % frameSize); } + private function getStreamBytePosition(useSDLSound:Bool, vorbisFile:VorbisFile):Int + { + if (useSDLSound) + { + return Std.int(streamPosition * streamByteRate); + } + + #if lime_vorbis + return (vorbisFile != null) ? Int64.toInt(vorbisFile.pcmTell()) : 0; + #else + return 0; + #end + } + + private function shouldLoopStreamInline():Bool + { + return stream && loops > 0 && length == null; + } + + private function resetStreamForLoop(useSDLSound:Bool):Bool + { + if (!shouldLoopStreamInline() || loops <= queuedStreamLoopCount) + { + return false; + } + + var streamTime = parent.offset; + var reset = useSDLSound ? resetSDLSoundStream(streamTime) : resetVorbisStream(streamTime); + + if (!reset) + { + return false; + } + + queuedStreamLoopCount++; + streamExhausted = false; + return true; + } + + private function consumeProcessedStreamLoopCounts(processed:Int):Void + { + if (queuedBufferLoopCounts == null || processed <= 0) + { + return; + } + + var completedLoops = 0; + for (i in 0...processed) + { + if (queuedBufferLoopCounts.length == 0) + { + break; + } + + completedLoops += queuedBufferLoopCounts.shift(); + } + + if (completedLoops > 0) + { + loops -= completedLoops; + if (loops < 0) + { + loops = 0; + } + + queuedStreamLoopCount -= completedLoops; + if (queuedStreamLoopCount < 0) + { + queuedStreamLoopCount = 0; + } + } + } + private function clearQueuedBuffers():Void { if (handle == null) @@ -503,6 +618,88 @@ class NativeAudioSource } queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; + } + + private function prepareAudioContextRecoverySource():Void + { + if (parent.buffer == null) + { + recoveryPending = false; + return; + } + + recoveryPending = true; + recoveryCompleted = completed; + recoveryGain = getGain(); + recoveryLength = length; + recoveryLoops = loops; + recoveryPitch = getPitch(); + recoveryPlaying = playing; + recoveryPosition = getPosition().clone(); + recoveryTime = getCurrentTime(); + + if (streamTimer != null) + { + streamTimer.stop(); + streamTimer = null; + } + + if (timer != null) + { + timer.stop(); + timer = null; + } + + playing = false; + handle = null; + buffers = null; + bufferTimeBlocks = null; + queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; + + if (parent.buffer != null) + { + parent.buffer.__srcBuffer = null; + parent.buffer.__srcBufferContext = 0; + } + + clearSDLSoundStream(); + clearVorbisStream(); + } + + private function restoreAudioContextRecoverySource():Void + { + if (!recoveryPending || parent.buffer == null) + { + return; + } + + recoveryPending = false; + completed = recoveryCompleted; + length = recoveryLength; + loops = recoveryLoops; + playing = false; + + init(); + + if (handle == null) + { + return; + } + + setGain(recoveryGain); + setPitch(recoveryPitch); + setPosition(recoveryPosition); + setCurrentTime(recoveryTime); + completed = recoveryCompleted; + + if (recoveryPlaying) + { + play(); + } } private function ensureReadBuffer(length:Int):Bool @@ -622,10 +819,12 @@ class NativeAudioSource if (buffers != null) { queuedBufferCount -= buffers.length; + consumeProcessedStreamLoopCounts(buffers.length); } else { queuedBufferCount -= buffersProcessed; + consumeProcessedStreamLoopCounts(buffersProcessed); } if (queuedBufferCount < 0) @@ -654,13 +853,30 @@ class NativeAudioSource var numBuffers = 0; var bytesRead = 0; + var newBufferLoopCounts = []; for (buffer in buffers) { + var bufferLoopCount = 0; + if (hasKnownStreamLength && position >= dataLength) { - streamExhausted = true; - break; + if (resetStreamForLoop(useSDLSound)) + { + if (!useSDLSound) + { + #if lime_vorbis + vorbisFile = vorbisStream; + #end + } + + position = getStreamBytePosition(useSDLSound, vorbisFile); + } + else + { + streamExhausted = true; + break; + } } var requestLength = hasKnownStreamLength ? (dataLength - position) : STREAM_BUFFER_SIZE; @@ -687,17 +903,57 @@ class NativeAudioSource if (bytesRead <= 0 || readArray == null) { - streamExhausted = true; - break; + if (resetStreamForLoop(useSDLSound)) + { + if (!useSDLSound) + { + #if lime_vorbis + vorbisFile = vorbisStream; + #end + } + + position = getStreamBytePosition(useSDLSound, vorbisFile); + continue; + } + else + { + streamExhausted = true; + break; + } } AL.bufferData(buffer, format, readArray, bytesRead, parent.buffer.sampleRate); position += bytesRead; numBuffers++; + var stopAfterBuffer = false; + if (bytesRead < requestLength || (hasKnownStreamLength && position >= dataLength)) { - streamExhausted = true; + if (resetStreamForLoop(useSDLSound)) + { + bufferLoopCount++; + + if (!useSDLSound) + { + #if lime_vorbis + vorbisFile = vorbisStream; + #end + } + + position = getStreamBytePosition(useSDLSound, vorbisFile); + } + else + { + streamExhausted = true; + stopAfterBuffer = true; + } + } + + newBufferLoopCounts.push(bufferLoopCount); + + if (stopAfterBuffer) + { break; } } @@ -707,6 +963,11 @@ class NativeAudioSource var buffersToQueue = (numBuffers == buffers.length) ? buffers : buffers.slice(0, numBuffers); AL.sourceQueueBuffers(handle, numBuffers, buffersToQueue); queuedBufferCount += numBuffers; + + for (i in 0...numBuffers) + { + queuedBufferLoopCounts.push(newBufferLoopCounts[i]); + } } // OpenAL can unexpectedly stop playback if the buffers run out @@ -898,13 +1159,13 @@ class NativeAudioSource var totalLength = getLength(); var timeRemaining = Std.int((totalLength - value) / getPitch()); - if (timeRemaining > 0) + if (timeRemaining > 0 && !shouldLoopStreamInline()) { completed = false; timer = new Timer(timeRemaining); timer.run = timer_onRun; } - else if (stream && totalLength <= 0) + else if (stream && (totalLength <= 0 || shouldLoopStreamInline())) { completed = false; timer = null; diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index fe8bb2cb41..bbb081e3d8 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -328,6 +328,8 @@ class NativeCFFI @:cffi private static function lime_window_get_context_type(handle:Dynamic):Dynamic; + @:cffi private static function lime_window_create_vulkan_surface(handle:Dynamic, instanceHigh:Int, instanceLow:Int):Dynamic; + @:cffi private static function lime_window_get_display(handle:Dynamic):Int; @:cffi private static function lime_window_get_display_mode(handle:Dynamic):Dynamic; @@ -344,6 +346,323 @@ class NativeCFFI @:cffi private static function lime_window_get_text_input_enabled(handle:Dynamic):Bool; + @:cffi private static function lime_window_get_vulkan_drawable_size(handle:Dynamic):Dynamic; + + @:cffi private static function lime_window_get_vulkan_instance_extensions(handle:Dynamic):Array; + + @:cffi private static function lime_window_get_vulkan_instance_proc_addr(handle:Dynamic):Dynamic; + + @:cffi private static function lime_vk_create_instance(handle:Dynamic, applicationName:String):Dynamic; + + @:cffi private static function lime_vk_destroy_instance(handle:Dynamic, instanceHigh:Int, instanceLow:Int):Void; + + @:cffi private static function lime_vk_destroy_surface(handle:Dynamic, instanceHigh:Int, instanceLow:Int, surfaceHigh:Int, surfaceLow:Int):Void; + + @:cffi private static function lime_vk_get_physical_devices(handle:Dynamic, instanceHigh:Int, instanceLow:Int, surfaceHigh:Int, surfaceLow:Int):Dynamic; + + #if lime_vulkan + @:cffi private static function lime_vk_create_device(handle:Dynamic, instanceHigh:Int, instanceLow:Int, physicalDeviceHigh:Int, physicalDeviceLow:Int, + queueFamilyIndex:Int, extensions:Array):Dynamic; + + @:cffi private static function lime_vk_destroy_device(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int):Void; + + @:cffi private static function lime_vk_device_wait_idle(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int):Bool; + + @:cffi private static function lime_vk_queue_wait_idle(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, + queueLow:Int):Bool; + + @:cffi private static function lime_vk_create_command_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + queueFamilyIndex:Int, flags:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_command_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandPoolHigh:Int, commandPoolLow:Int):Void; + + @:cffi private static function lime_vk_reset_command_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandPoolHigh:Int, commandPoolLow:Int, flags:Int):Bool; + + @:cffi private static function lime_vk_allocate_command_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandPoolHigh:Int, commandPoolLow:Int, level:Int):Dynamic; + + @:cffi private static function lime_vk_free_command_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandPoolHigh:Int, commandPoolLow:Int, commandBufferHigh:Int, commandBufferLow:Int):Void; + + @:cffi private static function lime_vk_begin_command_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, flags:Int):Bool; + + @:cffi private static function lime_vk_end_command_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int):Bool; + + @:cffi private static function lime_vk_reset_command_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, flags:Int):Bool; + + @:cffi private static function lime_vk_create_semaphore(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_semaphore(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + semaphoreHigh:Int, semaphoreLow:Int):Void; + + @:cffi private static function lime_vk_create_fence(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + flags:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_fence(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, fenceHigh:Int, + fenceLow:Int):Void; + + @:cffi private static function lime_vk_wait_for_fence(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + fenceHigh:Int, fenceLow:Int, timeoutHigh:Int, timeoutLow:Int):Bool; + + @:cffi private static function lime_vk_reset_fence(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, fenceHigh:Int, + fenceLow:Int):Bool; + + @:cffi private static function lime_vk_queue_submit(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, + queueLow:Int, commandBufferHigh:Int, commandBufferLow:Int, fenceHigh:Int, fenceLow:Int):Bool; + + @:cffi private static function lime_vk_allocate_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, physicalDeviceHigh:Int, + physicalDeviceLow:Int, deviceHigh:Int, deviceLow:Int, sizeHigh:Int, sizeLow:Int, memoryTypeBits:Int, properties:Int):Dynamic; + + @:cffi private static function lime_vk_free_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int):Void; + + @:cffi private static function lime_vk_upload_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, bytes:Dynamic, byteOffset:Int, byteLength:Int):Bool; + + @:cffi private static function lime_vk_download_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, bytes:Dynamic, byteOffset:Int, byteLength:Int):Bool; + + @:cffi private static function lime_vk_map_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, sizeHigh:Int, sizeLow:Int, flags:Int):Bool; + + @:cffi private static function lime_vk_unmap_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int):Void; + + @:cffi private static function lime_vk_write_mapped_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, bytes:Dynamic, byteOffset:Int, byteLength:Int):Bool; + + @:cffi private static function lime_vk_flush_mapped_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, sizeHigh:Int, sizeLow:Int):Bool; + + @:cffi private static function lime_vk_invalidate_mapped_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, sizeHigh:Int, sizeLow:Int):Bool; + + @:cffi private static function lime_vk_create_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + sizeHigh:Int, sizeLow:Int, usage:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + bufferHigh:Int, bufferLow:Int):Void; + + @:cffi private static function lime_vk_get_buffer_memory_requirements(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, bufferHigh:Int, bufferLow:Int):Dynamic; + + @:cffi private static function lime_vk_bind_buffer_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + bufferHigh:Int, bufferLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int):Bool; + + @:cffi private static function lime_vk_create_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + width:Int, height:Int, depth:Int, mipLevels:Int, arrayLayers:Int, format:Int, imageType:Int, tiling:Int, usage:Int, samples:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + imageHigh:Int, imageLow:Int):Void; + + @:cffi private static function lime_vk_get_image_memory_requirements(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, imageHigh:Int, imageLow:Int):Dynamic; + + @:cffi private static function lime_vk_bind_image_memory(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + imageHigh:Int, imageLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int):Bool; + + @:cffi private static function lime_vk_create_swapchain(handle:Dynamic, instanceHigh:Int, instanceLow:Int, physicalDeviceHigh:Int, + physicalDeviceLow:Int, deviceHigh:Int, deviceLow:Int, surfaceHigh:Int, surfaceLow:Int, queueFamilyIndex:Int, width:Int, height:Int, + presentMode:Int, oldSwapchainHigh:Int, oldSwapchainLow:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_swapchain(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + swapchainHigh:Int, swapchainLow:Int):Void; + + @:cffi private static function lime_vk_get_swapchain_images(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + swapchainHigh:Int, swapchainLow:Int):Dynamic; + + @:cffi private static function lime_vk_acquire_next_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + swapchainHigh:Int, swapchainLow:Int, timeoutHigh:Int, timeoutLow:Int, semaphoreHigh:Int, semaphoreLow:Int, fenceHigh:Int, fenceLow:Int):Dynamic; + + @:cffi private static function lime_vk_queue_present(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, + queueLow:Int, swapchainHigh:Int, swapchainLow:Int, imageIndex:Int, waitSemaphoreHigh:Int, waitSemaphoreLow:Int):Int; + + @:cffi private static function lime_vk_create_image_view(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + imageHigh:Int, imageLow:Int, format:Int, aspectMask:Int, viewType:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_image_view(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + imageViewHigh:Int, imageViewLow:Int):Void; + + @:cffi private static function lime_vk_create_image_view_ex(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + imageHigh:Int, imageLow:Int, format:Int, aspectMask:Int, viewType:Int, baseMipLevel:Int, levelCount:Int, baseArrayLayer:Int, + layerCount:Int):Dynamic; + + @:cffi private static function lime_vk_create_render_pass(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + state:Array):Dynamic; + + @:cffi private static function lime_vk_destroy_render_pass(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + renderPassHigh:Int, renderPassLow:Int):Void; + + @:cffi private static function lime_vk_create_framebuffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + renderPassHigh:Int, renderPassLow:Int, attachments:Array, width:Int, height:Int, layers:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_framebuffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + framebufferHigh:Int, framebufferLow:Int):Void; + + @:cffi private static function lime_vk_create_shader_module(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + bytes:Dynamic, byteOffset:Int, byteLength:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_shader_module(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + shaderModuleHigh:Int, shaderModuleLow:Int):Void; + + @:cffi private static function lime_vk_create_sampler(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + filter:Int, addressMode:Int, mipmapMode:Int, anisotropyEnable:Bool, maxAnisotropy:Float, compareOp:Int, minLod:Float, maxLod:Float):Dynamic; + + @:cffi private static function lime_vk_destroy_sampler(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + samplerHigh:Int, samplerLow:Int):Void; + + @:cffi private static function lime_vk_create_descriptor_set_layout(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, bindings:Array):Dynamic; + + @:cffi private static function lime_vk_destroy_descriptor_set_layout(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, layoutHigh:Int, layoutLow:Int):Void; + + @:cffi private static function lime_vk_create_descriptor_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, poolSizes:Array):Dynamic; + + @:cffi private static function lime_vk_destroy_descriptor_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, poolHigh:Int, poolLow:Int):Void; + + @:cffi private static function lime_vk_reset_descriptor_pool(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, poolHigh:Int, poolLow:Int, flags:Int):Bool; + + @:cffi private static function lime_vk_allocate_descriptor_set(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, poolHigh:Int, poolLow:Int, layoutHigh:Int, layoutLow:Int):Dynamic; + + @:cffi private static function lime_vk_update_descriptor_set_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, setHigh:Int, setLow:Int, binding:Int, descriptorType:Int, imageViewHigh:Int, imageViewLow:Int, samplerHigh:Int, + samplerLow:Int, imageLayout:Int):Bool; + + @:cffi private static function lime_vk_update_descriptor_set_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, setHigh:Int, setLow:Int, binding:Int, descriptorType:Int, bufferHigh:Int, bufferLow:Int, offset:Int, range:Int):Bool; + + @:cffi private static function lime_vk_update_descriptor_sets(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + writes:Array):Bool; + + @:cffi private static function lime_vk_create_pipeline_layout(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, setLayouts:Array, pushConstantStages:Int, pushConstantSize:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_pipeline_layout(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, layoutHigh:Int, layoutLow:Int):Void; + + @:cffi private static function lime_vk_create_pipeline_cache(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, bytes:Dynamic, byteOffset:Int, byteLength:Int):Dynamic; + + @:cffi private static function lime_vk_destroy_pipeline_cache(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, cacheHigh:Int, cacheLow:Int):Void; + + @:cffi private static function lime_vk_get_pipeline_cache_data(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, cacheHigh:Int, cacheLow:Int, bytes:Dynamic):Bool; + + @:cffi private static function lime_vk_create_graphics_pipeline(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, renderPassHigh:Int, renderPassLow:Int, layoutHigh:Int, layoutLow:Int, vertexShaderHigh:Int, vertexShaderLow:Int, + fragmentShaderHigh:Int, fragmentShaderLow:Int, state:Array):Dynamic; + + @:cffi private static function lime_vk_destroy_pipeline(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + pipelineHigh:Int, pipelineLow:Int):Void; + + @:cffi private static function lime_vk_queue_submit_synced(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + queueHigh:Int, queueLow:Int, commandBufferHigh:Int, commandBufferLow:Int, state:Array):Bool; + + @:cffi private static function lime_vk_cmd_begin_render_pass(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, renderPassHigh:Int, renderPassLow:Int, framebufferHigh:Int, framebufferLow:Int, + state:Array, clear:Array):Bool; + + @:cffi private static function lime_vk_cmd_end_render_pass(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int):Bool; + + @:cffi private static function lime_vk_cmd_bind_pipeline(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, pipelineHigh:Int, pipelineLow:Int, bindPoint:Int):Bool; + + @:cffi private static function lime_vk_cmd_bind_descriptor_set(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, layoutLow:Int, setHigh:Int, setLow:Int, bindPoint:Int, + firstSet:Int):Bool; + + @:cffi private static function lime_vk_cmd_bind_descriptor_set_ex(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, layoutLow:Int, setHigh:Int, setLow:Int, state:Array):Bool; + + @:cffi private static function lime_vk_cmd_bind_descriptor_set_dynamic_offset(handle:Dynamic, instanceHigh:Int, instanceLow:Int, + deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, layoutLow:Int, setHigh:Int, setLow:Int, + dynamicOffset:Int, firstSet:Int, bindPoint:Int):Bool; + + @:cffi private static function lime_vk_cmd_bind_vertex_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, binding:Int, offsetHigh:Int, offsetLow:Int):Bool; + + @:cffi private static function lime_vk_cmd_bind_index_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, offsetHigh:Int, offsetLow:Int, indexType:Int):Bool; + + @:cffi private static function lime_vk_cmd_set_viewport(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, x:Float, y:Float, width:Float, height:Float, minDepth:Float, maxDepth:Float):Bool; + + @:cffi private static function lime_vk_cmd_set_scissor(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, x:Int, y:Int, width:Int, height:Int):Bool; + + @:cffi private static function lime_vk_cmd_draw(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, vertexCount:Int, instanceCount:Int, firstVertex:Int, firstInstance:Int):Bool; + + @:cffi private static function lime_vk_cmd_draw_indexed(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, indexCount:Int, instanceCount:Int, firstIndex:Int, vertexOffset:Int, firstInstance:Int):Bool; + + @:cffi private static function lime_vk_cmd_draw_indirect(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, offsetHigh:Int, offsetLow:Int, drawCount:Int, stride:Int):Bool; + + @:cffi private static function lime_vk_cmd_draw_indexed_indirect(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, offsetHigh:Int, offsetLow:Int, drawCount:Int, + stride:Int):Bool; + + @:cffi private static function lime_vk_cmd_copy_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, sourceHigh:Int, sourceLow:Int, destinationHigh:Int, destinationLow:Int, state:Array):Bool; + + @:cffi private static function lime_vk_cmd_copy_buffer_to_image_region(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, imageHigh:Int, imageLow:Int, + state:Array):Bool; + + @:cffi private static function lime_vk_cmd_copy_image_to_buffer_region(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, imageLow:Int, bufferHigh:Int, bufferLow:Int, + state:Array):Bool; + + @:cffi private static function lime_vk_cmd_pipeline_barrier_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, imageLow:Int, state:Array):Bool; + + @:cffi private static function lime_vk_cmd_clear_color_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, imageLow:Int, layout:Int, aspectMask:Int, clear:Array):Bool; + + @:cffi private static function lime_vk_cmd_clear_depth_stencil_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, imageLow:Int, state:Array, clear:Array):Bool; + + @:cffi private static function lime_vk_cmd_clear_attachments(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, state:Array, clear:Array):Bool; + + @:cffi private static function lime_vk_cmd_blit_image(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, sourceHigh:Int, sourceLow:Int, destinationHigh:Int, destinationLow:Int, state:Array):Bool; + + @:cffi private static function lime_vk_cmd_push_constants(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, + commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, layoutLow:Int, state:Array, bytes:Dynamic):Bool; + #end + + @:cffi private static function lime_vk_get_last_error():Dynamic; + + @:cffi private static function lime_vulkan_renderer_create(handle:Dynamic, applicationName:String):CFFIPointer; + + @:cffi private static function lime_vulkan_renderer_destroy(handle:Dynamic):Void; + + @:cffi private static function lime_vulkan_renderer_get_info(handle:Dynamic):Dynamic; + + @:cffi private static function lime_vulkan_renderer_get_last_error():Dynamic; + + @:cffi private static function lime_vulkan_renderer_set_overlay(handle:Dynamic, bytes:Dynamic, width:Int, height:Int, x:Int, y:Int):Bool; + + @:cffi private static function lime_vulkan_renderer_clear_overlay(handle:Dynamic):Bool; + + @:cffi private static function lime_vulkan_renderer_render(handle:Dynamic, red:Float, green:Float, blue:Float, alpha:Float):Bool; + + @:cffi private static function lime_vulkan_renderer_resize(handle:Dynamic):Bool; + @:cffi private static function lime_window_get_width(handle:Dynamic):Int; @:cffi private static function lime_window_get_x(handle:Dynamic):Int; @@ -633,6 +952,8 @@ class NativeCFFI private static var lime_window_get_context = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", "lime_window_get_context", "od", false)); private static var lime_window_get_context_type = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_get_context_type", "oo", false)); + private static var lime_window_create_vulkan_surface = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_window_create_vulkan_surface", "oiio", false)); private static var lime_window_get_display = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_display", "oi", false)); private static var lime_window_get_display_mode = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_get_display_mode", "oo", false)); @@ -644,6 +965,224 @@ class NativeCFFI private static var lime_window_get_scale = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", "lime_window_get_scale", "od", false)); private static var lime_window_get_text_input_enabled = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_window_get_text_input_enabled", "ob", false)); + private static var lime_window_get_vulkan_drawable_size = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_window_get_vulkan_drawable_size", "oo", false)); + private static var lime_window_get_vulkan_instance_extensions = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_window_get_vulkan_instance_extensions", "oo", false)); + private static var lime_window_get_vulkan_instance_proc_addr = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_window_get_vulkan_instance_proc_addr", "oo", false)); + private static var lime_vk_create_instance = new cpp.CallableString->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_instance", "oso", false)); + private static var lime_vk_destroy_instance = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_instance", "oiiv", false)); + private static var lime_vk_destroy_surface = new cpp.CallableInt->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_surface", "oiiiiv", false)); + private static var lime_vk_get_physical_devices = new cpp.CallableInt->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_get_physical_devices", "oiiiio", false)); + #if lime_vulkan + private static var lime_vk_create_device = new cpp.CallableInt->Int->Int->Int->Int->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_device", "oiiiiioo", false)); + private static var lime_vk_destroy_device = new cpp.CallableInt->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_device", "oiiiiv", false)); + private static var lime_vk_device_wait_idle = new cpp.CallableInt->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_device_wait_idle", "oiiiib", false)); + private static var lime_vk_queue_wait_idle = new cpp.CallableInt->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_queue_wait_idle", "oiiiiiib", false)); + private static var lime_vk_create_command_pool = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_command_pool", "oiiiiiio", false)); + private static var lime_vk_destroy_command_pool = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_command_pool", "oiiiiiiv", false)); + private static var lime_vk_reset_command_pool = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_reset_command_pool", "oiiiiiiib", false)); + private static var lime_vk_allocate_command_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_allocate_command_buffer", "oiiiiiiio", false)); + private static var lime_vk_free_command_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_free_command_buffer", "oiiiiiiiiv", false)); + private static var lime_vk_begin_command_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_begin_command_buffer", "oiiiiiiib", false)); + private static var lime_vk_end_command_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_end_command_buffer", "oiiiiiib", false)); + private static var lime_vk_reset_command_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_reset_command_buffer", "oiiiiiiib", false)); + private static var lime_vk_create_semaphore = new cpp.CallableInt->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_semaphore", "oiiiio", false)); + private static var lime_vk_destroy_semaphore = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_semaphore", "oiiiiiiv", false)); + private static var lime_vk_create_fence = new cpp.CallableInt->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_fence", "oiiiiio", false)); + private static var lime_vk_destroy_fence = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_fence", "oiiiiiiv", false)); + private static var lime_vk_wait_for_fence = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_wait_for_fence", "oiiiiiiiib", false)); + private static var lime_vk_reset_fence = new cpp.CallableInt->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_reset_fence", "oiiiiiib", false)); + private static var lime_vk_queue_submit = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_queue_submit", "oiiiiiiiiiib", false)); + private static var lime_vk_allocate_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime( + "lime", "lime_vk_allocate_memory", "oiiiiiiiiiio", false)); + private static var lime_vk_free_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_free_memory", "oiiiiiiv", false)); + private static var lime_vk_upload_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_upload_memory", "oiiiiiiiioiib", false)); + private static var lime_vk_download_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_download_memory", "oiiiiiiiioiib", false)); + private static var lime_vk_map_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_map_memory", "oiiiiiiiiiiib", false)); + private static var lime_vk_unmap_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_unmap_memory", "oiiiiiiv", false)); + private static var lime_vk_write_mapped_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_write_mapped_memory", "oiiiiiiiioiib", false)); + private static var lime_vk_flush_mapped_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_flush_mapped_memory", "oiiiiiiiiiib", false)); + private static var lime_vk_invalidate_mapped_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_invalidate_mapped_memory", "oiiiiiiiiiib", false)); + private static var lime_vk_create_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_buffer", "oiiiiiiio", false)); + private static var lime_vk_destroy_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_buffer", "oiiiiiiv", false)); + private static var lime_vk_get_buffer_memory_requirements = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_get_buffer_memory_requirements", "oiiiiiio", false)); + private static var lime_vk_bind_buffer_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_bind_buffer_memory", "oiiiiiiiiiib", false)); + private static var lime_vk_create_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_image", "oiiiiiiiiiiiiiio", false)); + private static var lime_vk_destroy_image = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_image", "oiiiiiiv", false)); + private static var lime_vk_get_image_memory_requirements = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_get_image_memory_requirements", "oiiiiiio", false)); + private static var lime_vk_bind_image_memory = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_bind_image_memory", "oiiiiiiiiiib", false)); + private static var lime_vk_create_swapchain = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int-> + cpp.Object>(cpp.Prime._loadPrime("lime", "lime_vk_create_swapchain", "oiiiiiiiiiiiiiio", false)); + private static var lime_vk_destroy_swapchain = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_swapchain", "oiiiiiiv", false)); + private static var lime_vk_get_swapchain_images = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_get_swapchain_images", "oiiiiiio", false)); + private static var lime_vk_acquire_next_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int-> + cpp.Object>(cpp.Prime._loadPrime("lime", "lime_vk_acquire_next_image", "oiiiiiiiiiiiio", false)); + private static var lime_vk_queue_present = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int>(cpp.Prime._loadPrime("lime", + "lime_vk_queue_present", "oiiiiiiiiiiii", false)); + private static var lime_vk_create_image_view = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_image_view", "oiiiiiiiiio", false)); + private static var lime_vk_destroy_image_view = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_image_view", "oiiiiiiv", false)); + private static var lime_vk_create_image_view_ex = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_image_view_ex", "oiiiiiiiiiiiiio", false)); + private static var lime_vk_create_render_pass = new cpp.CallableInt->Int->Int->Int->cpp.Object->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_render_pass", "oiiiioo", false)); + private static var lime_vk_destroy_render_pass = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_render_pass", "oiiiiiiv", false)); + private static var lime_vk_create_framebuffer = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object->Int->Int->Int->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_framebuffer", "oiiiiiioiiio", false)); + private static var lime_vk_destroy_framebuffer = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_framebuffer", "oiiiiiiv", false)); + private static var lime_vk_create_shader_module = new cpp.CallableInt->Int->Int->Int->cpp.Object->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_shader_module", "oiiiioiio", false)); + private static var lime_vk_destroy_shader_module = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_shader_module", "oiiiiiiv", false)); + private static var lime_vk_create_sampler = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Bool->Float->Int->Float->Float->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_sampler", "oiiiiiiibdiddo", false)); + private static var lime_vk_destroy_sampler = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_sampler", "oiiiiiiv", false)); + private static var lime_vk_create_descriptor_set_layout = new cpp.CallableInt->Int->Int->Int->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_descriptor_set_layout", "oiiiioo", false)); + private static var lime_vk_destroy_descriptor_set_layout = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_descriptor_set_layout", "oiiiiiiv", false)); + private static var lime_vk_create_descriptor_pool = new cpp.CallableInt->Int->Int->Int->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_descriptor_pool", "oiiiioo", false)); + private static var lime_vk_destroy_descriptor_pool = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_descriptor_pool", "oiiiiiiv", false)); + private static var lime_vk_reset_descriptor_pool = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_reset_descriptor_pool", "oiiiiiiib", false)); + private static var lime_vk_allocate_descriptor_set = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_allocate_descriptor_set", "oiiiiiiiio", false)); + private static var lime_vk_update_descriptor_set_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_update_descriptor_set_image", "oiiiiiiiiiiiiib", false)); + private static var lime_vk_update_descriptor_set_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_update_descriptor_set_buffer", "oiiiiiiiiiiiib", false)); + private static var lime_vk_update_descriptor_sets = new cpp.CallableInt->Int->Int->Int->cpp.Object->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_update_descriptor_sets", "oiiiiob", false)); + private static var lime_vk_create_pipeline_layout = new cpp.CallableInt->Int->Int->Int->cpp.Object->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_pipeline_layout", "oiiiioiio", false)); + private static var lime_vk_destroy_pipeline_layout = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_pipeline_layout", "oiiiiiiv", false)); + private static var lime_vk_create_pipeline_cache = new cpp.CallableInt->Int->Int->Int->cpp.Object->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_create_pipeline_cache", "oiiiioiio", false)); + private static var lime_vk_destroy_pipeline_cache = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_pipeline_cache", "oiiiiiiv", false)); + private static var lime_vk_get_pipeline_cache_data = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_get_pipeline_cache_data", "oiiiiiiob", false)); + private static var lime_vk_create_graphics_pipeline = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object-> + cpp.Object>(cpp.Prime._loadPrime("lime", "lime_vk_create_graphics_pipeline", "oiiiiiiiiiiiioo", false)); + private static var lime_vk_destroy_pipeline = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vk_destroy_pipeline", "oiiiiiiv", false)); + private static var lime_vk_queue_submit_synced = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_queue_submit_synced", "oiiiiiiiiob", false)); + private static var lime_vk_cmd_begin_render_pass = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_begin_render_pass", "oiiiiiiiiiioob", false)); + private static var lime_vk_cmd_end_render_pass = new cpp.CallableInt->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_end_render_pass", "oiiiiiib", false)); + private static var lime_vk_cmd_bind_pipeline = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_bind_pipeline", "oiiiiiiiiib", false)); + private static var lime_vk_cmd_bind_descriptor_set = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_bind_descriptor_set", "oiiiiiiiiiiiib", false)); + private static var lime_vk_cmd_bind_descriptor_set_ex = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_bind_descriptor_set_ex", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_bind_descriptor_set_dynamic_offset = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_bind_descriptor_set_dynamic_offset", "oiiiiiiiiiiiiib", false)); + private static var lime_vk_cmd_bind_vertex_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_bind_vertex_buffer", "oiiiiiiiiiiib", false)); + private static var lime_vk_cmd_bind_index_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_bind_index_buffer", "oiiiiiiiiiiib", false)); + private static var lime_vk_cmd_set_viewport = new cpp.CallableInt->Int->Int->Int->Int->Int->Float->Float->Float->Float->Float->Float->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_set_viewport", "oiiiiiiddddddb", false)); + private static var lime_vk_cmd_set_scissor = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_set_scissor", "oiiiiiiiiiib", false)); + private static var lime_vk_cmd_draw = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_draw", "oiiiiiiiiiib", false)); + private static var lime_vk_cmd_draw_indexed = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_draw_indexed", "oiiiiiiiiiiib", false)); + private static var lime_vk_cmd_draw_indirect = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vk_cmd_draw_indirect", "oiiiiiiiiiiiib", false)); + private static var lime_vk_cmd_draw_indexed_indirect = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime( + "lime", "lime_vk_cmd_draw_indexed_indirect", "oiiiiiiiiiiiib", false)); + private static var lime_vk_cmd_copy_buffer = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_copy_buffer_to_image_region = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer_to_image_region", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_copy_image_to_buffer_region = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_image_to_buffer_region", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_pipeline_barrier_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_pipeline_barrier_image", "oiiiiiiiiob", false)); + private static var lime_vk_cmd_clear_color_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_clear_color_image", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_clear_depth_stencil_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_clear_depth_stencil_image", "oiiiiiiiioob", false)); + private static var lime_vk_cmd_clear_attachments = new cpp.CallableInt->Int->Int->Int->Int->Int->cpp.Object->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_clear_attachments", "oiiiiiioob", false)); + private static var lime_vk_cmd_blit_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_blit_image", "oiiiiiiiiiiob", false)); + private static var lime_vk_cmd_push_constants = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->cpp.Object->cpp.Object->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_push_constants", "oiiiiiiiioob", false)); + #end + private static var lime_vk_get_last_error = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vk_get_last_error", "o", false)); + private static var lime_vulkan_renderer_create = new cpp.CallableString->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_create", "oso", false)); + private static var lime_vulkan_renderer_destroy = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_destroy", "ov", false)); + private static var lime_vulkan_renderer_get_info = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_get_info", "oo", false)); + private static var lime_vulkan_renderer_get_last_error = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_get_last_error", "o", false)); + private static var lime_vulkan_renderer_set_overlay = new cpp.Callablecpp.Object->Int->Int->Int->Int->Bool>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_set_overlay", "ooiiiib", false)); + private static var lime_vulkan_renderer_clear_overlay = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_clear_overlay", "ob", false)); + private static var lime_vulkan_renderer_render = new cpp.CallableFloat->Float->Float->Float->Bool>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_render", "oddddb", false)); + private static var lime_vulkan_renderer_resize = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", + "lime_vulkan_renderer_resize", "ob", false)); private static var lime_window_get_width = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_width", "oi", false)); private static var lime_window_get_x = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_x", "oi", false)); private static var lime_window_get_y = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_y", "oi", false)); @@ -831,6 +1370,7 @@ class NativeCFFI private static var lime_window_focus = CFFI.load("lime", "lime_window_focus", 1); private static var lime_window_get_context = CFFI.load("lime", "lime_window_get_context", 1); private static var lime_window_get_context_type = CFFI.load("lime", "lime_window_get_context_type", 1); + private static var lime_window_create_vulkan_surface = CFFI.load("lime", "lime_window_create_vulkan_surface", 3); private static var lime_window_get_display = CFFI.load("lime", "lime_window_get_display", 1); private static var lime_window_get_display_mode = CFFI.load("lime", "lime_window_get_display_mode", 1); private static var lime_window_get_height = CFFI.load("lime", "lime_window_get_height", 1); @@ -839,6 +1379,116 @@ class NativeCFFI private static var lime_window_get_opacity = CFFI.load("lime", "lime_window_get_opacity", 1); private static var lime_window_get_scale = CFFI.load("lime", "lime_window_get_scale", 1); private static var lime_window_get_text_input_enabled = CFFI.load("lime", "lime_window_get_text_input_enabled", 1); + private static var lime_window_get_vulkan_drawable_size = CFFI.load("lime", "lime_window_get_vulkan_drawable_size", 1); + private static var lime_window_get_vulkan_instance_extensions = CFFI.load("lime", "lime_window_get_vulkan_instance_extensions", 1); + private static var lime_window_get_vulkan_instance_proc_addr = CFFI.load("lime", "lime_window_get_vulkan_instance_proc_addr", 1); + private static var lime_vk_create_instance = CFFI.load("lime", "lime_vk_create_instance", 2); + private static var lime_vk_destroy_instance = CFFI.load("lime", "lime_vk_destroy_instance", 3); + private static var lime_vk_destroy_surface = CFFI.load("lime", "lime_vk_destroy_surface", 5); + private static var lime_vk_get_physical_devices = CFFI.load("lime", "lime_vk_get_physical_devices", 5); + #if lime_vulkan + private static var lime_vk_create_device = CFFI.load("lime", "lime_vk_create_device", -1); + private static var lime_vk_destroy_device = CFFI.load("lime", "lime_vk_destroy_device", 5); + private static var lime_vk_device_wait_idle = CFFI.load("lime", "lime_vk_device_wait_idle", 5); + private static var lime_vk_queue_wait_idle = CFFI.load("lime", "lime_vk_queue_wait_idle", -1); + private static var lime_vk_create_command_pool = CFFI.load("lime", "lime_vk_create_command_pool", -1); + private static var lime_vk_destroy_command_pool = CFFI.load("lime", "lime_vk_destroy_command_pool", -1); + private static var lime_vk_reset_command_pool = CFFI.load("lime", "lime_vk_reset_command_pool", -1); + private static var lime_vk_allocate_command_buffer = CFFI.load("lime", "lime_vk_allocate_command_buffer", -1); + private static var lime_vk_free_command_buffer = CFFI.load("lime", "lime_vk_free_command_buffer", -1); + private static var lime_vk_begin_command_buffer = CFFI.load("lime", "lime_vk_begin_command_buffer", -1); + private static var lime_vk_end_command_buffer = CFFI.load("lime", "lime_vk_end_command_buffer", -1); + private static var lime_vk_reset_command_buffer = CFFI.load("lime", "lime_vk_reset_command_buffer", -1); + private static var lime_vk_create_semaphore = CFFI.load("lime", "lime_vk_create_semaphore", 5); + private static var lime_vk_destroy_semaphore = CFFI.load("lime", "lime_vk_destroy_semaphore", -1); + private static var lime_vk_create_fence = CFFI.load("lime", "lime_vk_create_fence", -1); + private static var lime_vk_destroy_fence = CFFI.load("lime", "lime_vk_destroy_fence", -1); + private static var lime_vk_wait_for_fence = CFFI.load("lime", "lime_vk_wait_for_fence", -1); + private static var lime_vk_reset_fence = CFFI.load("lime", "lime_vk_reset_fence", -1); + private static var lime_vk_queue_submit = CFFI.load("lime", "lime_vk_queue_submit", -1); + private static var lime_vk_allocate_memory = CFFI.load("lime", "lime_vk_allocate_memory", -1); + private static var lime_vk_free_memory = CFFI.load("lime", "lime_vk_free_memory", -1); + private static var lime_vk_upload_memory = CFFI.load("lime", "lime_vk_upload_memory", -1); + private static var lime_vk_download_memory = CFFI.load("lime", "lime_vk_download_memory", -1); + private static var lime_vk_map_memory = CFFI.load("lime", "lime_vk_map_memory", -1); + private static var lime_vk_unmap_memory = CFFI.load("lime", "lime_vk_unmap_memory", -1); + private static var lime_vk_write_mapped_memory = CFFI.load("lime", "lime_vk_write_mapped_memory", -1); + private static var lime_vk_flush_mapped_memory = CFFI.load("lime", "lime_vk_flush_mapped_memory", -1); + private static var lime_vk_invalidate_mapped_memory = CFFI.load("lime", "lime_vk_invalidate_mapped_memory", -1); + private static var lime_vk_create_buffer = CFFI.load("lime", "lime_vk_create_buffer", -1); + private static var lime_vk_destroy_buffer = CFFI.load("lime", "lime_vk_destroy_buffer", -1); + private static var lime_vk_get_buffer_memory_requirements = CFFI.load("lime", "lime_vk_get_buffer_memory_requirements", -1); + private static var lime_vk_bind_buffer_memory = CFFI.load("lime", "lime_vk_bind_buffer_memory", -1); + private static var lime_vk_create_image = CFFI.load("lime", "lime_vk_create_image", -1); + private static var lime_vk_destroy_image = CFFI.load("lime", "lime_vk_destroy_image", -1); + private static var lime_vk_get_image_memory_requirements = CFFI.load("lime", "lime_vk_get_image_memory_requirements", -1); + private static var lime_vk_bind_image_memory = CFFI.load("lime", "lime_vk_bind_image_memory", -1); + private static var lime_vk_create_swapchain = CFFI.load("lime", "lime_vk_create_swapchain", -1); + private static var lime_vk_destroy_swapchain = CFFI.load("lime", "lime_vk_destroy_swapchain", -1); + private static var lime_vk_get_swapchain_images = CFFI.load("lime", "lime_vk_get_swapchain_images", -1); + private static var lime_vk_acquire_next_image = CFFI.load("lime", "lime_vk_acquire_next_image", -1); + private static var lime_vk_queue_present = CFFI.load("lime", "lime_vk_queue_present", -1); + private static var lime_vk_create_image_view = CFFI.load("lime", "lime_vk_create_image_view", -1); + private static var lime_vk_destroy_image_view = CFFI.load("lime", "lime_vk_destroy_image_view", -1); + private static var lime_vk_create_image_view_ex = CFFI.load("lime", "lime_vk_create_image_view_ex", -1); + private static var lime_vk_create_render_pass = CFFI.load("lime", "lime_vk_create_render_pass", -1); + private static var lime_vk_destroy_render_pass = CFFI.load("lime", "lime_vk_destroy_render_pass", -1); + private static var lime_vk_create_framebuffer = CFFI.load("lime", "lime_vk_create_framebuffer", -1); + private static var lime_vk_destroy_framebuffer = CFFI.load("lime", "lime_vk_destroy_framebuffer", -1); + private static var lime_vk_create_shader_module = CFFI.load("lime", "lime_vk_create_shader_module", -1); + private static var lime_vk_destroy_shader_module = CFFI.load("lime", "lime_vk_destroy_shader_module", -1); + private static var lime_vk_create_sampler = CFFI.load("lime", "lime_vk_create_sampler", -1); + private static var lime_vk_destroy_sampler = CFFI.load("lime", "lime_vk_destroy_sampler", -1); + private static var lime_vk_create_descriptor_set_layout = CFFI.load("lime", "lime_vk_create_descriptor_set_layout", -1); + private static var lime_vk_destroy_descriptor_set_layout = CFFI.load("lime", "lime_vk_destroy_descriptor_set_layout", -1); + private static var lime_vk_create_descriptor_pool = CFFI.load("lime", "lime_vk_create_descriptor_pool", -1); + private static var lime_vk_destroy_descriptor_pool = CFFI.load("lime", "lime_vk_destroy_descriptor_pool", -1); + private static var lime_vk_reset_descriptor_pool = CFFI.load("lime", "lime_vk_reset_descriptor_pool", -1); + private static var lime_vk_allocate_descriptor_set = CFFI.load("lime", "lime_vk_allocate_descriptor_set", -1); + private static var lime_vk_update_descriptor_set_image = CFFI.load("lime", "lime_vk_update_descriptor_set_image", -1); + private static var lime_vk_update_descriptor_set_buffer = CFFI.load("lime", "lime_vk_update_descriptor_set_buffer", -1); + private static var lime_vk_update_descriptor_sets = CFFI.load("lime", "lime_vk_update_descriptor_sets", -1); + private static var lime_vk_create_pipeline_layout = CFFI.load("lime", "lime_vk_create_pipeline_layout", -1); + private static var lime_vk_destroy_pipeline_layout = CFFI.load("lime", "lime_vk_destroy_pipeline_layout", -1); + private static var lime_vk_create_pipeline_cache = CFFI.load("lime", "lime_vk_create_pipeline_cache", -1); + private static var lime_vk_destroy_pipeline_cache = CFFI.load("lime", "lime_vk_destroy_pipeline_cache", -1); + private static var lime_vk_get_pipeline_cache_data = CFFI.load("lime", "lime_vk_get_pipeline_cache_data", -1); + private static var lime_vk_create_graphics_pipeline = CFFI.load("lime", "lime_vk_create_graphics_pipeline", -1); + private static var lime_vk_destroy_pipeline = CFFI.load("lime", "lime_vk_destroy_pipeline", -1); + private static var lime_vk_queue_submit_synced = CFFI.load("lime", "lime_vk_queue_submit_synced", -1); + private static var lime_vk_cmd_begin_render_pass = CFFI.load("lime", "lime_vk_cmd_begin_render_pass", -1); + private static var lime_vk_cmd_end_render_pass = CFFI.load("lime", "lime_vk_cmd_end_render_pass", -1); + private static var lime_vk_cmd_bind_pipeline = CFFI.load("lime", "lime_vk_cmd_bind_pipeline", -1); + private static var lime_vk_cmd_bind_descriptor_set = CFFI.load("lime", "lime_vk_cmd_bind_descriptor_set", -1); + private static var lime_vk_cmd_bind_descriptor_set_ex = CFFI.load("lime", "lime_vk_cmd_bind_descriptor_set_ex", -1); + private static var lime_vk_cmd_bind_descriptor_set_dynamic_offset = CFFI.load("lime", "lime_vk_cmd_bind_descriptor_set_dynamic_offset", -1); + private static var lime_vk_cmd_bind_vertex_buffer = CFFI.load("lime", "lime_vk_cmd_bind_vertex_buffer", -1); + private static var lime_vk_cmd_bind_index_buffer = CFFI.load("lime", "lime_vk_cmd_bind_index_buffer", -1); + private static var lime_vk_cmd_set_viewport = CFFI.load("lime", "lime_vk_cmd_set_viewport", -1); + private static var lime_vk_cmd_set_scissor = CFFI.load("lime", "lime_vk_cmd_set_scissor", -1); + private static var lime_vk_cmd_draw = CFFI.load("lime", "lime_vk_cmd_draw", -1); + private static var lime_vk_cmd_draw_indexed = CFFI.load("lime", "lime_vk_cmd_draw_indexed", -1); + private static var lime_vk_cmd_draw_indirect = CFFI.load("lime", "lime_vk_cmd_draw_indirect", -1); + private static var lime_vk_cmd_draw_indexed_indirect = CFFI.load("lime", "lime_vk_cmd_draw_indexed_indirect", -1); + private static var lime_vk_cmd_copy_buffer = CFFI.load("lime", "lime_vk_cmd_copy_buffer", -1); + private static var lime_vk_cmd_copy_buffer_to_image_region = CFFI.load("lime", "lime_vk_cmd_copy_buffer_to_image_region", -1); + private static var lime_vk_cmd_copy_image_to_buffer_region = CFFI.load("lime", "lime_vk_cmd_copy_image_to_buffer_region", -1); + private static var lime_vk_cmd_pipeline_barrier_image = CFFI.load("lime", "lime_vk_cmd_pipeline_barrier_image", -1); + private static var lime_vk_cmd_clear_color_image = CFFI.load("lime", "lime_vk_cmd_clear_color_image", -1); + private static var lime_vk_cmd_clear_depth_stencil_image = CFFI.load("lime", "lime_vk_cmd_clear_depth_stencil_image", -1); + private static var lime_vk_cmd_clear_attachments = CFFI.load("lime", "lime_vk_cmd_clear_attachments", -1); + private static var lime_vk_cmd_blit_image = CFFI.load("lime", "lime_vk_cmd_blit_image", -1); + private static var lime_vk_cmd_push_constants = CFFI.load("lime", "lime_vk_cmd_push_constants", -1); + #end + private static var lime_vk_get_last_error = CFFI.load("lime", "lime_vk_get_last_error", 0); + private static var lime_vulkan_renderer_create = CFFI.load("lime", "lime_vulkan_renderer_create", 2); + private static var lime_vulkan_renderer_destroy = CFFI.load("lime", "lime_vulkan_renderer_destroy", 1); + private static var lime_vulkan_renderer_get_info = CFFI.load("lime", "lime_vulkan_renderer_get_info", 1); + private static var lime_vulkan_renderer_get_last_error = CFFI.load("lime", "lime_vulkan_renderer_get_last_error", 0); + private static var lime_vulkan_renderer_set_overlay = CFFI.load("lime", "lime_vulkan_renderer_set_overlay", -1); + private static var lime_vulkan_renderer_clear_overlay = CFFI.load("lime", "lime_vulkan_renderer_clear_overlay", 1); + private static var lime_vulkan_renderer_render = CFFI.load("lime", "lime_vulkan_renderer_render", 5); + private static var lime_vulkan_renderer_resize = CFFI.load("lime", "lime_vulkan_renderer_resize", 1); private static var lime_window_get_width = CFFI.load("lime", "lime_window_get_width", 1); private static var lime_window_get_x = CFFI.load("lime", "lime_window_get_x", 1); private static var lime_window_get_y = CFFI.load("lime", "lime_window_get_y", 1); @@ -1431,6 +2081,12 @@ class NativeCFFI return null; } + @:hlNative("lime", "hl_window_create_vulkan_surface") private static function lime_window_create_vulkan_surface(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int):Dynamic + { + return null; + } + @:hlNative("lime", "hl_window_get_display") private static function lime_window_get_display(handle:CFFIPointer):Int { return 0; @@ -1463,6 +2119,623 @@ class NativeCFFI return false; } + @:hlNative("lime", "hl_window_get_vulkan_drawable_size") private static function lime_window_get_vulkan_drawable_size(handle:CFFIPointer):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_window_get_vulkan_instance_extensions") private static function lime_window_get_vulkan_instance_extensions( + handle:CFFIPointer):hl.NativeArray + { + return null; + } + + @:hlNative("lime", "hl_window_get_vulkan_instance_proc_addr") private static function lime_window_get_vulkan_instance_proc_addr(handle:CFFIPointer):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_create_instance") private static function lime_vk_create_instance(handle:CFFIPointer, applicationName:String):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_instance") private static function lime_vk_destroy_instance(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int):Void {} + + @:hlNative("lime", "hl_vk_destroy_surface") private static function lime_vk_destroy_surface(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, surfaceHigh:Int, surfaceLow:Int):Void {} + + @:hlNative("lime", "hl_vk_get_physical_devices") private static function lime_vk_get_physical_devices(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, surfaceHigh:Int, surfaceLow:Int):hl.NativeArray + { + return null; + } + + #if lime_vulkan + @:hlNative("lime", "hl_vk_create_device") private static function lime_vk_create_device(handle:CFFIPointer, instanceHigh:Int, instanceLow:Int, + physicalDeviceHigh:Int, physicalDeviceLow:Int, queueFamilyIndex:Int, extensions:hl.NativeArray):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_device") private static function lime_vk_destroy_device(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int):Void {} + + @:hlNative("lime", "hl_vk_device_wait_idle") private static function lime_vk_device_wait_idle(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_queue_wait_idle") private static function lime_vk_queue_wait_idle(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, queueLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_command_pool") private static function lime_vk_create_command_pool(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueFamilyIndex:Int, flags:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_command_pool") private static function lime_vk_destroy_command_pool(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandPoolHigh:Int, commandPoolLow:Int):Void {} + + @:hlNative("lime", "hl_vk_reset_command_pool") private static function lime_vk_reset_command_pool(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandPoolHigh:Int, commandPoolLow:Int, flags:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_allocate_command_buffer") private static function lime_vk_allocate_command_buffer(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandPoolHigh:Int, commandPoolLow:Int, level:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_free_command_buffer") private static function lime_vk_free_command_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandPoolHigh:Int, commandPoolLow:Int, commandBufferHigh:Int, commandBufferLow:Int):Void {} + + @:hlNative("lime", "hl_vk_begin_command_buffer") private static function lime_vk_begin_command_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, flags:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_end_command_buffer") private static function lime_vk_end_command_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_reset_command_buffer") private static function lime_vk_reset_command_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, flags:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_semaphore") private static function lime_vk_create_semaphore(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_semaphore") private static function lime_vk_destroy_semaphore(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, semaphoreHigh:Int, semaphoreLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_fence") private static function lime_vk_create_fence(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, flags:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_fence") private static function lime_vk_destroy_fence(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, fenceHigh:Int, fenceLow:Int):Void {} + + @:hlNative("lime", "hl_vk_wait_for_fence") private static function lime_vk_wait_for_fence(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, fenceHigh:Int, fenceLow:Int, timeoutHigh:Int, timeoutLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_reset_fence") private static function lime_vk_reset_fence(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, fenceHigh:Int, fenceLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_queue_submit") private static function lime_vk_queue_submit(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, queueLow:Int, commandBufferHigh:Int, commandBufferLow:Int, fenceHigh:Int, + fenceLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_allocate_memory") private static function lime_vk_allocate_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, physicalDeviceHigh:Int, physicalDeviceLow:Int, deviceHigh:Int, deviceLow:Int, sizeHigh:Int, sizeLow:Int, + memoryTypeBits:Int, properties:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_free_memory") private static function lime_vk_free_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int):Void {} + + @:hlNative("lime", "hl_vk_upload_memory") private static function lime_vk_upload_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, bytes:Bytes, + byteOffset:Int, byteLength:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_download_memory") private static function lime_vk_download_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, bytes:Bytes, + byteOffset:Int, byteLength:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_map_memory") private static function lime_vk_map_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, sizeHigh:Int, + sizeLow:Int, flags:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_unmap_memory") private static function lime_vk_unmap_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int):Void {} + + @:hlNative("lime", "hl_vk_write_mapped_memory") private static function lime_vk_write_mapped_memory(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, + bytes:Bytes, byteOffset:Int, byteLength:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_flush_mapped_memory") private static function lime_vk_flush_mapped_memory(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, + sizeHigh:Int, sizeLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_invalidate_mapped_memory") private static function lime_vk_invalidate_mapped_memory(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, offsetLow:Int, + sizeHigh:Int, sizeLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_buffer") private static function lime_vk_create_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, sizeHigh:Int, sizeLow:Int, usage:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_buffer") private static function lime_vk_destroy_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, bufferHigh:Int, bufferLow:Int):Void {} + + @:hlNative("lime", "hl_vk_get_buffer_memory_requirements") private static function lime_vk_get_buffer_memory_requirements(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, bufferHigh:Int, bufferLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_bind_buffer_memory") private static function lime_vk_bind_buffer_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, bufferHigh:Int, bufferLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, + offsetLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_image") private static function lime_vk_create_image(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, width:Int, height:Int, depth:Int, mipLevels:Int, arrayLayers:Int, format:Int, + imageType:Int, tiling:Int, usage:Int, samples:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_image") private static function lime_vk_destroy_image(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageHigh:Int, imageLow:Int):Void {} + + @:hlNative("lime", "hl_vk_get_image_memory_requirements") private static function lime_vk_get_image_memory_requirements(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageHigh:Int, imageLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_bind_image_memory") private static function lime_vk_bind_image_memory(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageHigh:Int, imageLow:Int, memoryHigh:Int, memoryLow:Int, offsetHigh:Int, + offsetLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_swapchain") private static function lime_vk_create_swapchain(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, physicalDeviceHigh:Int, physicalDeviceLow:Int, deviceHigh:Int, deviceLow:Int, surfaceHigh:Int, surfaceLow:Int, + queueFamilyIndex:Int, width:Int, height:Int, presentMode:Int, oldSwapchainHigh:Int, oldSwapchainLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_swapchain") private static function lime_vk_destroy_swapchain(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, swapchainHigh:Int, swapchainLow:Int):Void {} + + @:hlNative("lime", "hl_vk_get_swapchain_images") private static function lime_vk_get_swapchain_images(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, swapchainHigh:Int, swapchainLow:Int):hl.NativeArray + { + return null; + } + + @:hlNative("lime", "hl_vk_acquire_next_image") private static function lime_vk_acquire_next_image(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, swapchainHigh:Int, swapchainLow:Int, timeoutHigh:Int, timeoutLow:Int, semaphoreHigh:Int, + semaphoreLow:Int, fenceHigh:Int, fenceLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_queue_present") private static function lime_vk_queue_present(handle:CFFIPointer, instanceHigh:Int, instanceLow:Int, + deviceHigh:Int, deviceLow:Int, queueHigh:Int, queueLow:Int, swapchainHigh:Int, swapchainLow:Int, imageIndex:Int, waitSemaphoreHigh:Int, + waitSemaphoreLow:Int):Int + { + return -3; + } + + @:hlNative("lime", "hl_vk_create_image_view") private static function lime_vk_create_image_view(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageHigh:Int, imageLow:Int, format:Int, aspectMask:Int, viewType:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_image_view") private static function lime_vk_destroy_image_view(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageViewHigh:Int, imageViewLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_image_view_ex") private static function lime_vk_create_image_view_ex(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, imageHigh:Int, imageLow:Int, format:Int, aspectMask:Int, + viewType:Int, baseMipLevel:Int, levelCount:Int, baseArrayLayer:Int, layerCount:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_create_render_pass") private static function lime_vk_create_render_pass(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, state:hl.NativeArray):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_render_pass") private static function lime_vk_destroy_render_pass(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, renderPassHigh:Int, renderPassLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_framebuffer") private static function lime_vk_create_framebuffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, renderPassHigh:Int, renderPassLow:Int, attachments:hl.NativeArray, + width:Int, height:Int, layers:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_framebuffer") private static function lime_vk_destroy_framebuffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, framebufferHigh:Int, framebufferLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_shader_module") private static function lime_vk_create_shader_module(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, bytes:Bytes, byteOffset:Int, byteLength:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_shader_module") private static function lime_vk_destroy_shader_module(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, shaderModuleHigh:Int, shaderModuleLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_sampler") private static function lime_vk_create_sampler(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, filter:Int, addressMode:Int, mipmapMode:Int, anisotropyEnable:Bool, + maxAnisotropy:Float, compareOp:Int, minLod:Float, maxLod:Float):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_sampler") private static function lime_vk_destroy_sampler(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, samplerHigh:Int, samplerLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_descriptor_set_layout") private static function lime_vk_create_descriptor_set_layout(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, bindings:hl.NativeArray):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_descriptor_set_layout") private static function lime_vk_destroy_descriptor_set_layout(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, layoutHigh:Int, layoutLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_descriptor_pool") private static function lime_vk_create_descriptor_pool(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, poolSizes:hl.NativeArray):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_descriptor_pool") private static function lime_vk_destroy_descriptor_pool(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, poolHigh:Int, poolLow:Int):Void {} + + @:hlNative("lime", "hl_vk_reset_descriptor_pool") private static function lime_vk_reset_descriptor_pool(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, poolHigh:Int, poolLow:Int, flags:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_allocate_descriptor_set") private static function lime_vk_allocate_descriptor_set(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, poolHigh:Int, poolLow:Int, layoutHigh:Int, layoutLow:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_update_descriptor_set_image") private static function lime_vk_update_descriptor_set_image(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, setHigh:Int, setLow:Int, binding:Int, descriptorType:Int, + imageViewHigh:Int, imageViewLow:Int, samplerHigh:Int, samplerLow:Int, imageLayout:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_update_descriptor_set_buffer") private static function lime_vk_update_descriptor_set_buffer(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, setHigh:Int, setLow:Int, binding:Int, descriptorType:Int, + bufferHigh:Int, bufferLow:Int, offset:Int, range:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_update_descriptor_sets") private static function lime_vk_update_descriptor_sets(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, writes:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_pipeline_layout") private static function lime_vk_create_pipeline_layout(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, setLayouts:hl.NativeArray, pushConstantStages:Int, + pushConstantSize:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_pipeline_layout") private static function lime_vk_destroy_pipeline_layout(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, layoutHigh:Int, layoutLow:Int):Void {} + + @:hlNative("lime", "hl_vk_create_pipeline_cache") private static function lime_vk_create_pipeline_cache(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, bytes:Bytes, byteOffset:Int, byteLength:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_pipeline_cache") private static function lime_vk_destroy_pipeline_cache(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, cacheHigh:Int, cacheLow:Int):Void {} + + @:hlNative("lime", "hl_vk_get_pipeline_cache_data") private static function lime_vk_get_pipeline_cache_data(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, cacheHigh:Int, cacheLow:Int, bytes:Bytes):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_create_graphics_pipeline") private static function lime_vk_create_graphics_pipeline(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, renderPassHigh:Int, renderPassLow:Int, layoutHigh:Int, + layoutLow:Int, vertexShaderHigh:Int, vertexShaderLow:Int, fragmentShaderHigh:Int, fragmentShaderLow:Int, + state:hl.NativeArray):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_vk_destroy_pipeline") private static function lime_vk_destroy_pipeline(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, pipelineHigh:Int, pipelineLow:Int):Void {} + + @:hlNative("lime", "hl_vk_queue_submit_synced") private static function lime_vk_queue_submit_synced(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, queueHigh:Int, queueLow:Int, commandBufferHigh:Int, + commandBufferLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_begin_render_pass") private static function lime_vk_cmd_begin_render_pass(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, renderPassHigh:Int, + renderPassLow:Int, framebufferHigh:Int, framebufferLow:Int, state:hl.NativeArray, clear:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_end_render_pass") private static function lime_vk_cmd_end_render_pass(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_pipeline") private static function lime_vk_cmd_bind_pipeline(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, pipelineHigh:Int, pipelineLow:Int, + bindPoint:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_descriptor_set") private static function lime_vk_cmd_bind_descriptor_set(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, + layoutLow:Int, setHigh:Int, setLow:Int, bindPoint:Int, firstSet:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_descriptor_set_ex") private static function lime_vk_cmd_bind_descriptor_set_ex(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, + layoutLow:Int, setHigh:Int, setLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_descriptor_set_dynamic_offset") private static function lime_vk_cmd_bind_descriptor_set_dynamic_offset( + handle:CFFIPointer, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, + layoutHigh:Int, layoutLow:Int, setHigh:Int, setLow:Int, dynamicOffset:Int, firstSet:Int, bindPoint:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_vertex_buffer") private static function lime_vk_cmd_bind_vertex_buffer(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, + bufferLow:Int, binding:Int, offsetHigh:Int, offsetLow:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_bind_index_buffer") private static function lime_vk_cmd_bind_index_buffer(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, + bufferLow:Int, offsetHigh:Int, offsetLow:Int, indexType:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_set_viewport") private static function lime_vk_cmd_set_viewport(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, x:Float, y:Float, width:Float, + height:Float, minDepth:Float, maxDepth:Float):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_set_scissor") private static function lime_vk_cmd_set_scissor(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, x:Int, y:Int, width:Int, + height:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_draw") private static function lime_vk_cmd_draw(handle:CFFIPointer, instanceHigh:Int, instanceLow:Int, + deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, vertexCount:Int, instanceCount:Int, firstVertex:Int, + firstInstance:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_draw_indexed") private static function lime_vk_cmd_draw_indexed(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, indexCount:Int, instanceCount:Int, + firstIndex:Int, vertexOffset:Int, firstInstance:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_draw_indirect") private static function lime_vk_cmd_draw_indirect(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, + offsetHigh:Int, offsetLow:Int, drawCount:Int, stride:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_draw_indexed_indirect") private static function lime_vk_cmd_draw_indexed_indirect(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, + bufferLow:Int, offsetHigh:Int, offsetLow:Int, drawCount:Int, stride:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_copy_buffer") private static function lime_vk_cmd_copy_buffer(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, sourceHigh:Int, sourceLow:Int, + destinationHigh:Int, destinationLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_copy_buffer_to_image_region") private static function lime_vk_cmd_copy_buffer_to_image_region(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, + bufferLow:Int, imageHigh:Int, imageLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_copy_image_to_buffer_region") private static function lime_vk_cmd_copy_image_to_buffer_region(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, + imageLow:Int, bufferHigh:Int, bufferLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_pipeline_barrier_image") private static function lime_vk_cmd_pipeline_barrier_image(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, + imageLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_clear_color_image") private static function lime_vk_cmd_clear_color_image(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, + imageLow:Int, layout:Int, aspectMask:Int, clear:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_clear_depth_stencil_image") private static function lime_vk_cmd_clear_depth_stencil_image(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, imageHigh:Int, + imageLow:Int, state:hl.NativeArray, clear:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_clear_attachments") private static function lime_vk_cmd_clear_attachments(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, + state:hl.NativeArray, clear:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_blit_image") private static function lime_vk_cmd_blit_image(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, sourceHigh:Int, sourceLow:Int, + destinationHigh:Int, destinationLow:Int, state:hl.NativeArray):Bool + { + return false; + } + + @:hlNative("lime", "hl_vk_cmd_push_constants") private static function lime_vk_cmd_push_constants(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, layoutHigh:Int, layoutLow:Int, + state:hl.NativeArray, bytes:Bytes):Bool + { + return false; + } + #end + + @:hlNative("lime", "hl_vk_get_last_error") private static function lime_vk_get_last_error():hl.Bytes + { + return null; + } + + @:hlNative("lime", "hl_vulkan_renderer_create") private static function lime_vulkan_renderer_create(handle:CFFIPointer, + applicationName:String):CFFIPointer + { + return null; + } + + @:hlNative("lime", "hl_vulkan_renderer_destroy") private static function lime_vulkan_renderer_destroy(handle:CFFIPointer):Void {} + + @:hlNative("lime", "hl_vulkan_renderer_get_info") private static function lime_vulkan_renderer_get_info(handle:CFFIPointer):hl.Bytes + { + return null; + } + + @:hlNative("lime", "hl_vulkan_renderer_get_last_error") private static function lime_vulkan_renderer_get_last_error():hl.Bytes + { + return null; + } + + @:hlNative("lime", "hl_vulkan_renderer_set_overlay") private static function lime_vulkan_renderer_set_overlay(handle:CFFIPointer, + bytes:Bytes, width:Int, height:Int, x:Int, y:Int):Bool + { + return false; + } + + @:hlNative("lime", "hl_vulkan_renderer_clear_overlay") private static function lime_vulkan_renderer_clear_overlay(handle:CFFIPointer):Bool + { + return false; + } + + @:hlNative("lime", "hl_vulkan_renderer_render") private static function lime_vulkan_renderer_render(handle:CFFIPointer, red:Float, green:Float, + blue:Float, alpha:Float):Bool + { + return false; + } + + @:hlNative("lime", "hl_vulkan_renderer_resize") private static function lime_vulkan_renderer_resize(handle:CFFIPointer):Bool + { + return false; + } + @:hlNative("lime", "hl_window_get_width") private static function lime_window_get_width(handle:CFFIPointer):Int { return 0; @@ -1743,6 +3016,8 @@ class NativeCFFI @:cffi private static function lime_al_is_extension_present(extname:String):Bool; + @:cffi private static function lime_alc_is_extension_present(device:CFFIPointer, extname:String):Bool; + @:cffi private static function lime_al_is_source(source:CFFIPointer):Bool; @:cffi private static function lime_al_listener3f(param:Int, value1:Float32, value2:Float32, value3:Float32):Void; @@ -1819,6 +3094,16 @@ class NativeCFFI @:cffi private static function lime_alc_suspend_context(context:CFFIPointer):Void; + @:cffi private static function lime_alc_capture_open_device(devicename:String, frequency:Int, format:Int, buffersize:Int):CFFIPointer; + + @:cffi private static function lime_alc_capture_close_device(device:CFFIPointer):Bool; + + @:cffi private static function lime_alc_capture_start(device:CFFIPointer):Void; + + @:cffi private static function lime_alc_capture_stop(device:CFFIPointer):Void; + + @:cffi private static function lime_alc_capture_samples(device:CFFIPointer, buffer:Dynamic, samples:Int):Void; + @:cffi private static function lime_al_gen_filter():CFFIPointer; @:cffi private static function lime_al_filteri(filter:CFFIPointer, param:Int, value:Dynamic):Void; @@ -1929,6 +3214,8 @@ class NativeCFFI private static var lime_al_is_enabled = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_al_is_enabled", "ib", false)); private static var lime_al_is_extension_present = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_al_is_extension_present", "sb", false)); + private static var lime_alc_is_extension_present = new cpp.CallableString->Bool>(cpp.Prime._loadPrime("lime", "lime_alc_is_extension_present", + "osb", false)); private static var lime_al_is_source = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_al_is_source", "ob", false)); private static var lime_al_listener3f = new cpp.Callablecpp.Float32->cpp.Float32->cpp.Float32->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_listener3f", "ifffv", false)); @@ -1986,6 +3273,16 @@ class NativeCFFI private static var lime_alc_resume_device = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_resume_device", "ov", false)); private static var lime_alc_suspend_context = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_suspend_context", "ov", false)); + private static var lime_alc_capture_open_device = new cpp.CallableInt->Int->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_capture_open_device", + "siiio", false)); + private static var lime_alc_capture_close_device = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_alc_capture_close_device", "ob", + false)); + private static var lime_alc_capture_start = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_capture_start", "ov", + false)); + private static var lime_alc_capture_stop = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_capture_stop", "ov", + false)); + private static var lime_alc_capture_samples = new cpp.Callablecpp.Object->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_capture_samples", + "ooiv", false)); private static var lime_al_gen_filter = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_gen_filter", "o", false)); private static var lime_al_filteri = new cpp.CallableInt->cpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_filteri", "oiov", false)); @@ -2068,6 +3365,7 @@ class NativeCFFI private static var lime_al_is_buffer = CFFI.load("lime", "lime_al_is_buffer", 1); private static var lime_al_is_enabled = CFFI.load("lime", "lime_al_is_enabled", 1); private static var lime_al_is_extension_present = CFFI.load("lime", "lime_al_is_extension_present", 1); + private static var lime_alc_is_extension_present = CFFI.load("lime", "lime_alc_is_extension_present", 2); private static var lime_al_is_source = CFFI.load("lime", "lime_al_is_source", 1); private static var lime_al_listener3f = CFFI.load("lime", "lime_al_listener3f", 4); private static var lime_al_listener3i = CFFI.load("lime", "lime_al_listener3i", 4); @@ -2106,6 +3404,11 @@ class NativeCFFI private static var lime_alc_process_context = CFFI.load("lime", "lime_alc_process_context", 1); private static var lime_alc_resume_device = CFFI.load("lime", "lime_alc_resume_device", 1); private static var lime_alc_suspend_context = CFFI.load("lime", "lime_alc_suspend_context", 1); + private static var lime_alc_capture_open_device = CFFI.load("lime", "lime_alc_capture_open_device", 4); + private static var lime_alc_capture_close_device = CFFI.load("lime", "lime_alc_capture_close_device", 1); + private static var lime_alc_capture_start = CFFI.load("lime", "lime_alc_capture_start", 1); + private static var lime_alc_capture_stop = CFFI.load("lime", "lime_alc_capture_stop", 1); + private static var lime_alc_capture_samples = CFFI.load("lime", "lime_alc_capture_samples", 3); private static var lime_al_gen_filter = CFFI.load("lime", "lime_al_gen_filter", 0); private static var lime_al_filteri = CFFI.load("lime", "lime_al_filteri", 3); private static var lime_al_filterf = CFFI.load("lime", "lime_al_filterf", 3); @@ -2349,6 +3652,11 @@ class NativeCFFI return false; } + @:hlNative("lime", "hl_alc_is_extension_present") private static function lime_alc_is_extension_present(device:CFFIPointer, extname:String):Bool + { + return false; + } + @:hlNative("lime", "hl_al_is_source") private static function lime_al_is_source(source:CFFIPointer):Bool { return false; @@ -2462,6 +3770,22 @@ class NativeCFFI @:hlNative("lime", "hl_alc_suspend_context") private static function lime_alc_suspend_context(context:ALContext):Void {} + @:hlNative("lime", "hl_alc_capture_open_device") private static function lime_alc_capture_open_device(devicename:String, frequency:Int, format:Int, buffersize:Int):CFFIPointer + { + return null; + } + + @:hlNative("lime", "hl_alc_capture_close_device") private static function lime_alc_capture_close_device(device:ALDevice):Bool + { + return false; + } + + @:hlNative("lime", "hl_alc_capture_start") private static function lime_alc_capture_start(device:ALDevice):Void {} + + @:hlNative("lime", "hl_alc_capture_stop") private static function lime_alc_capture_stop(device:ALDevice):Void {} + + @:hlNative("lime", "hl_alc_capture_samples") private static function lime_alc_capture_samples(device:ALDevice, buffer:Bytes, samples:Int):Void {} + @:hlNative("lime", "hl_al_gen_filter") private static function lime_al_gen_filter():CFFIPointer { return null; diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index 0f6028a296..f548ae1c5f 100644 --- a/src/lime/_internal/backend/native/NativeWindow.hx +++ b/src/lime/_internal/backend/native/NativeWindow.hx @@ -14,6 +14,7 @@ import lime.graphics.Image; import lime.graphics.ImageBuffer; import lime.graphics.OpenGLRenderContext; import lime.graphics.RenderContext; +import lime.graphics.VulkanRenderContext; import lime.math.Rectangle; import lime.math.Vector2; import lime.system.CFFI; @@ -67,9 +68,12 @@ class NativeWindow var resolvedVSyncMode = parent.application.__resolveVSyncMode(attributes); var title = Reflect.hasField(attributes, "title") ? attributes.title : "Lime Application"; var flags = 0; + var transparent = Reflect.hasField(attributes, "transparent") && attributes.transparent; if (!Reflect.hasField(contextAttributes, "antialiasing")) contextAttributes.antialiasing = 0; - if (!Reflect.hasField(contextAttributes, "background")) contextAttributes.background = 0; - if (!Reflect.hasField(contextAttributes, "colorDepth")) contextAttributes.colorDepth = 24; + if (transparent) contextAttributes.background = null; + else if (!Reflect.hasField(contextAttributes, "background")) contextAttributes.background = 0; + if (!Reflect.hasField(contextAttributes, "colorDepth")) contextAttributes.colorDepth = transparent ? 32 : 24; + else if (transparent && contextAttributes.colorDepth < 32) contextAttributes.colorDepth = 32; if (!Reflect.hasField(contextAttributes, "depth")) contextAttributes.depth = true; if (!Reflect.hasField(contextAttributes, "hardware")) contextAttributes.hardware = true; if (!Reflect.hasField(contextAttributes, "stencil")) contextAttributes.stencil = true; @@ -79,14 +83,19 @@ class NativeWindow contextAttributes.vsync = (resolvedVSyncMode != VSyncMode.Off); #if (cairo || (!lime_opengl && !lime_opengles)) - contextAttributes.type = CAIRO; + if (!Reflect.hasField(contextAttributes, "type") || contextAttributes.type != VULKAN) + { + contextAttributes.type = CAIRO; + } #end if (Reflect.hasField(contextAttributes, "type") && contextAttributes.type == CAIRO) contextAttributes.hardware = false; + if (Reflect.hasField(contextAttributes, "type") && contextAttributes.type == VULKAN) contextAttributes.hardware = true; if (Reflect.hasField(attributes, "allowHighDPI") && attributes.allowHighDPI) flags |= cast WindowFlags.WINDOW_FLAG_ALLOW_HIGHDPI; if (Reflect.hasField(attributes, "alwaysOnTop") && attributes.alwaysOnTop) flags |= cast WindowFlags.WINDOW_FLAG_ALWAYS_ON_TOP; if (Reflect.hasField(attributes, "borderless") && attributes.borderless) flags |= cast WindowFlags.WINDOW_FLAG_BORDERLESS; if (Reflect.hasField(attributes, "fullscreen") && attributes.fullscreen) flags |= cast WindowFlags.WINDOW_FLAG_FULLSCREEN; + if (transparent) flags |= cast WindowFlags.WINDOW_FLAG_TRANSPARENT; if (Reflect.hasField(attributes, "hidden") && attributes.hidden) flags |= cast WindowFlags.WINDOW_FLAG_HIDDEN; if (Reflect.hasField(attributes, "maximized") && attributes.maximized) flags |= cast WindowFlags.WINDOW_FLAG_MAXIMIZED; @@ -106,6 +115,7 @@ class NativeWindow if (contextAttributes.depth) flags |= cast WindowFlags.WINDOW_FLAG_DEPTH_BUFFER; if (contextAttributes.hardware) flags |= cast WindowFlags.WINDOW_FLAG_HARDWARE; + if (Reflect.hasField(contextAttributes, "type") && contextAttributes.type == VULKAN) flags |= cast WindowFlags.WINDOW_FLAG_VULKAN; if (contextAttributes.stencil) flags |= cast WindowFlags.WINDOW_FLAG_STENCIL_BUFFER; if (contextAttributes.vsync) flags |= cast WindowFlags.WINDOW_FLAG_VSYNC; @@ -115,17 +125,19 @@ class NativeWindow #if (!macro && lime_cffi) handle = NativeCFFI.lime_window_create(parent.application.__backend.handle, width, height, flags, title); - if (handle != null) + if (handle == null) { - parent.__width = NativeCFFI.lime_window_get_width(handle); + return; + } - parent.__height = NativeCFFI.lime_window_get_height(handle); - parent.__x = NativeCFFI.lime_window_get_x(handle); - parent.__y = NativeCFFI.lime_window_get_y(handle); - parent.__hidden = (Reflect.hasField(attributes, "hidden") && attributes.hidden); + parent.__width = NativeCFFI.lime_window_get_width(handle); - parent.id = NativeCFFI.lime_window_get_id(handle); - } + parent.__height = NativeCFFI.lime_window_get_height(handle); + parent.__x = NativeCFFI.lime_window_get_x(handle); + parent.__y = NativeCFFI.lime_window_get_y(handle); + parent.__hidden = (Reflect.hasField(attributes, "hidden") && attributes.hidden); + + parent.id = NativeCFFI.lime_window_get_id(handle); parent.__scale = NativeCFFI.lime_window_get_scale(handle); var context = new RenderContext(); @@ -156,6 +168,12 @@ class NativeWindow { GL.context = gl; } + case "vulkan": + useHardware = true; + contextAttributes.hardware = true; + context.vulkan = new VulkanRenderContext(handle); + context.type = VULKAN; + context.version = Reflect.hasField(contextAttributes, "version") && contextAttributes.version != null ? contextAttributes.version : ""; default: useHardware = false; @@ -742,4 +760,6 @@ class NativeWindow var WINDOW_FLAG_MAXIMIZED = 0x00004000; var WINDOW_FLAG_ALWAYS_ON_TOP = 0x00008000; var WINDOW_FLAG_COLOR_DEPTH_32_BIT = 0x00010000; + var WINDOW_FLAG_VULKAN = 0x00020000; + var WINDOW_FLAG_TRANSPARENT = 0x00040000; } diff --git a/src/lime/_internal/macros/EventMacro.hx b/src/lime/_internal/macros/EventMacro.hx index ba42ce3b6c..4071ce5841 100644 --- a/src/lime/_internal/macros/EventMacro.hx +++ b/src/lime/_internal/macros/EventMacro.hx @@ -89,30 +89,82 @@ class EventMacro var dispatch = macro { + var previousTimestamp = __timestamp; + __timestamp = lime.system.System.getTimer(); canceled = false; - var listeners = __listeners; - var repeat = __repeat; - var i = 0; - - while (i < listeners.length) + try { - listeners[i]($a{argNames}); + var listeners = __listeners; + var repeat = __repeat; + var i = 0; - if (!repeat[i]) - { - this.remove(cast listeners[i]); - } - else + while (i < listeners.length) { - i++; + listeners[i]($a{argNames}); + + if (!repeat[i]) + { + this.remove(cast listeners[i]); + } + else + { + i++; + } + + if (canceled) + { + break; + } } + } + catch (e:Dynamic) + { + __timestamp = previousTimestamp; + throw e; + } + + __timestamp = previousTimestamp; + } + + var timestampDispatch = macro + { + var previousTimestamp = __timestamp; + __timestamp = timestamp; + canceled = false; + + try + { + var listeners = __listeners; + var repeat = __repeat; + var i = 0; - if (canceled) + while (i < listeners.length) { - break; + listeners[i]($a{argNames}); + + if (!repeat[i]) + { + this.remove(cast listeners[i]); + } + else + { + i++; + } + + if (canceled) + { + break; + } } } + catch (e:Dynamic) + { + __timestamp = previousTimestamp; + throw e; + } + + __timestamp = previousTimestamp; } var i = 0; @@ -122,7 +174,7 @@ class EventMacro { field = fields[i]; - if (field.name == "__listeners" || field.name == "dispatch") + if (field.name == "__listeners" || field.name == "dispatch" || field.name == "__dispatchWithTimestamp") { fields.remove(field); } @@ -152,6 +204,23 @@ class EventMacro }), pos: pos }); + fields.push( + { + name: "__dispatchWithTimestamp", + access: [APublic], + kind: FFun( + { + args: [{name: "timestamp", type: macro:Int}].concat(args), + expr: timestampDispatch, + params: [], + ret: macro:Void + }), + meta: [ + {name: ":dox", params: [macro hide], pos: pos}, + {name: ":noCompletion", pos: pos} + ], + pos: pos + }); var meta:Array = [ {name: ":dox", params: [macro hide], pos: pos}, diff --git a/src/lime/app/Application.hx b/src/lime/app/Application.hx index 10d128991e..7c617d01d1 100644 --- a/src/lime/app/Application.hx +++ b/src/lime/app/Application.hx @@ -868,6 +868,7 @@ class Application extends Module return __vsyncMode; } + @:allow(lime.ui.Window) @:noCompletion private function __seedFrameConfiguration(attributes:WindowAttributes):Void { if (__frameConfigured) diff --git a/src/lime/app/Event.hx b/src/lime/app/Event.hx index ed4a799279..5c4b0a9daa 100644 --- a/src/lime/app/Event.hx +++ b/src/lime/app/Event.hx @@ -30,10 +30,17 @@ class Event **/ public var canceled(default, null):Bool; + /** + The timestamp for the current dispatch, in milliseconds. + When read outside of a dispatch, this returns the current timer value. + **/ + public var timestamp(get, never):Int; + @:noCompletion @:dox(hide) public var __listeners:Array; @:noCompletion @:dox(hide) public var __repeat:Array; @:noCompletion private var __priorities:Array; + @:noCompletion private var __timestamp:Int; /** Creates a new Event instance @@ -45,6 +52,7 @@ class Event __listeners = new Array(); __priorities = new Array(); __repeat = new Array(); + __timestamp = -1; #end } @@ -89,6 +97,7 @@ class Event takes two `Int` arguments, like `dispatch (1, 2);` **/ public var dispatch:Dynamic; + @:noCompletion @:dox(hide) public var __dispatchWithTimestamp:Dynamic; // macro public function dispatch (ethis:Expr, args:Array):Void { // @@ -169,4 +178,13 @@ class Event __repeat.splice(0, len); #end } + + private function get_timestamp():Int + { + #if (lime_doc_gen || macro) + return (__timestamp != -1) ? __timestamp : 0; + #else + return (__timestamp != -1) ? __timestamp : lime.system.System.getTimer(); + #end + } } diff --git a/src/lime/graphics/RenderContext.hx b/src/lime/graphics/RenderContext.hx index 4443ffee9b..d269542e76 100644 --- a/src/lime/graphics/RenderContext.hx +++ b/src/lime/graphics/RenderContext.hx @@ -86,6 +86,13 @@ class RenderContext #if (!lime_doc_gen || native || (js && html5)) public var webgl2(default, null):WebGL2RenderContext; #end + + /** + Access to the current Vulkan render API bootstrap helpers, if available + **/ + #if (!lime_doc_gen || native) + public var vulkan(default, null):VulkanRenderContext; + #end public var window(default, null):Window; @:noCompletion private function new() {} diff --git a/src/lime/graphics/RenderContextType.hx b/src/lime/graphics/RenderContextType.hx index 8dddd1aa48..6b0fa93ff7 100644 --- a/src/lime/graphics/RenderContextType.hx +++ b/src/lime/graphics/RenderContextType.hx @@ -40,6 +40,11 @@ package lime.graphics; **/ var WEBGL = "webgl"; + /** + Describes a Vulkan render context + **/ + var VULKAN = "vulkan"; + /** Describes a custom render context **/ diff --git a/src/lime/graphics/VulkanRenderContext.hx b/src/lime/graphics/VulkanRenderContext.hx new file mode 100644 index 0000000000..39e2e3c1b6 --- /dev/null +++ b/src/lime/graphics/VulkanRenderContext.hx @@ -0,0 +1,195 @@ +package lime.graphics; + +import haxe.Int64; +import lime.graphics.vulkan.VKRenderer; +import lime.math.Vector2; +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFI; +#end +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFIPointer; +#end + +#if hl +import hl.Bytes as HLBytes; +import hl.NativeArray; +#end +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +/** + The `VulkanRenderContext` exposes native Vulkan window bootstrap helpers when + Vulkan is the render context type of the current `Window`. + + This context owns the window-specific pieces of Lime's Vulkan API: + + - required instance extensions for the current window + - the current drawable size in pixels + - Vulkan surface creation for an existing `VkInstance` + - access to `vkGetInstanceProcAddr` + + Use `lime.graphics.vulkan.VK` and related classes for the broader Vulkan API + surface as it grows. +**/ +@:access(lime._internal.backend.native.NativeCFFI) +class VulkanRenderContext +{ + public var type(default, null):RenderContextType; + public var version(default, null):String; + + private var __windowHandle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end; + + @:allow(lime._internal.backend.native.NativeWindow) + private function new(windowHandle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end) + { + __windowHandle = windowHandle; + type = VULKAN; + version = ""; + } + + /** + Creates a Vulkan surface for the current window using an existing + `VkInstance` handle, or an object that exposes a `get()` method returning + that handle. + **/ + public function createSurface(instance:Dynamic):Int64 + { + var surfaceData:Dynamic = null; + + #if (!macro && lime_cffi) + var instanceHandle = __resolveHandle(instance); + if (instanceHandle.high != 0 || instanceHandle.low != 0) + { + surfaceData = NativeCFFI.lime_window_create_vulkan_surface(__windowHandle, instanceHandle.high, instanceHandle.low); + } + #end + + if (surfaceData != null) + { + return Int64.make(surfaceData.high, surfaceData.low); + } + + return Int64.ofInt(0); + } + + /** + Gets the current drawable size in pixels for the Vulkan surface. + **/ + public function getDrawableSize(result:Vector2 = null):Vector2 + { + if (result == null) result = new Vector2(); + + #if (!macro && lime_cffi) + var size:Dynamic = NativeCFFI.lime_window_get_vulkan_drawable_size(__windowHandle); + if (size != null) + { + result.x = size.width; + result.y = size.height; + return result; + } + #end + + result.x = 0; + result.y = 0; + return result; + } + + /** + Returns the list of Vulkan instance extensions required to create a + surface for this window. + **/ + public function getInstanceExtensions():Array + { + #if (!macro && lime_cffi) + #if hl + var bytes:NativeArray = cast NativeCFFI.lime_window_get_vulkan_instance_extensions(__windowHandle); + if (bytes != null) + { + var extensions = new Array(); + for (i in 0...bytes.length) + { + extensions[i] = CFFI.stringValue(bytes[i]); + } + return extensions; + } + #else + var extensions:Array = cast NativeCFFI.lime_window_get_vulkan_instance_extensions(__windowHandle); + if (extensions != null) + { + return extensions; + } + #end + #end + + return []; + } + + /** + Returns the native address of SDL's `vkGetInstanceProcAddr` function. + **/ + public function getInstanceProcAddr():Int64 + { + #if (!macro && lime_cffi) + var handleData:Dynamic = NativeCFFI.lime_window_get_vulkan_instance_proc_addr(__windowHandle); + if (handleData != null) + { + return Int64.make(handleData.high, handleData.low); + } + #end + + return Int64.ofInt(0); + } + + /** + Creates Lime's validation Vulkan swapchain renderer for the current window. + + This renderer exists for smoke tests and samples while the public `VK` + surface grows into the full rendering API. + The renderer respects the current Lime `vsyncMode` preference when it + chooses a swapchain present mode. + **/ + public function createRenderer(applicationName:String = "Lime"):VKRenderer + { + #if (!macro && lime_cffi) + var handle = NativeCFFI.lime_vulkan_renderer_create(__windowHandle, applicationName); + if (handle != null) + { + return new VKRenderer(handle); + } + #end + + return null; + } + + private static function __resolveHandle(value:Dynamic):Int64 + { + if (value == null) return Int64.ofInt(0); + + var high:Dynamic = Reflect.field(value, "high"); + var low:Dynamic = Reflect.field(value, "low"); + if (high != null && low != null) + { + return Int64.make(high, low); + } + + switch (Type.typeof(value)) + { + case TInt: + return Int64.ofInt(cast value); + default: + } + + var getField = Reflect.field(value, "get"); + if (getField != null) + { + try + { + return __resolveHandle(Reflect.callMethod(value, getField, [])); + } + catch (e:Dynamic) {} + } + + return Int64.ofInt(0); + } +} diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx new file mode 100644 index 0000000000..93e9a0137b --- /dev/null +++ b/src/lime/graphics/vulkan/VK.hx @@ -0,0 +1,485 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.graphics.VulkanRenderContext; +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFI; +#end + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + Entry point for Lime's Vulkan API surface. + + Like `lime.graphics.opengl.GL`, this class is the public place for low-level + graphics API access. Vulkan is explicit by design, so the API is organized + around handles and lifecycle objects instead of GL-style global state. +**/ +class VK +{ + public static inline var SUCCESS = 0; + public static inline var NOT_READY = 1; + public static inline var TIMEOUT = 2; + public static inline var EVENT_SET = 3; + public static inline var EVENT_RESET = 4; + public static inline var INCOMPLETE = 5; + public static inline var SUBOPTIMAL_KHR = 1000001003; + public static inline var ERROR_INITIALIZATION_FAILED = -3; + public static inline var ERROR_OUT_OF_DATE_KHR = -1000001004; + + public static inline var KHR_SWAPCHAIN_EXTENSION_NAME = "VK_KHR_swapchain"; + + public static inline var PHYSICAL_DEVICE_TYPE_OTHER = 0; + public static inline var PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1; + public static inline var PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2; + public static inline var PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3; + public static inline var PHYSICAL_DEVICE_TYPE_CPU = 4; + + public static inline var QUEUE_GRAPHICS_BIT = 0x00000001; + public static inline var QUEUE_COMPUTE_BIT = 0x00000002; + public static inline var QUEUE_TRANSFER_BIT = 0x00000004; + public static inline var QUEUE_SPARSE_BINDING_BIT = 0x00000008; + + public static inline var COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001; + public static inline var COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002; + public static inline var COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004; + + public static inline var COMMAND_BUFFER_LEVEL_PRIMARY = 0; + public static inline var COMMAND_BUFFER_LEVEL_SECONDARY = 1; + + public static inline var COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001; + public static inline var COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002; + public static inline var COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004; + + public static inline var COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001; + + public static inline var FENCE_CREATE_SIGNALED_BIT = 0x00000001; + + public static inline var DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001; + + public static inline var FORMAT_UNDEFINED = 0; + public static inline var FORMAT_R8_UNORM = 9; + public static inline var FORMAT_R8G8_UNORM = 16; + public static inline var FORMAT_R8G8B8A8_UNORM = 37; + public static inline var FORMAT_R8G8B8A8_SRGB = 43; + public static inline var FORMAT_B8G8R8A8_UNORM = 44; + public static inline var FORMAT_B8G8R8A8_SRGB = 50; + public static inline var FORMAT_R16G16B16A16_SFLOAT = 97; + public static inline var FORMAT_R32_SFLOAT = 100; + public static inline var FORMAT_R32G32_SFLOAT = 103; + public static inline var FORMAT_R32G32B32_SFLOAT = 106; + public static inline var FORMAT_R32G32B32A32_SFLOAT = 109; + public static inline var FORMAT_D16_UNORM = 124; + public static inline var FORMAT_X8_D24_UNORM_PACK32 = 125; + public static inline var FORMAT_D32_SFLOAT = 126; + public static inline var FORMAT_S8_UINT = 127; + public static inline var FORMAT_D24_UNORM_S8_UINT = 129; + public static inline var FORMAT_D32_SFLOAT_S8_UINT = 130; + + public static inline var COLOR_SPACE_SRGB_NONLINEAR_KHR = 0; + + public static inline var PRESENT_MODE_IMMEDIATE_KHR = 0; + public static inline var PRESENT_MODE_MAILBOX_KHR = 1; + public static inline var PRESENT_MODE_FIFO_KHR = 2; + public static inline var PRESENT_MODE_FIFO_RELAXED_KHR = 3; + + public static inline var BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001; + public static inline var BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002; + public static inline var BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004; + public static inline var BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008; + public static inline var BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010; + public static inline var BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020; + public static inline var BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040; + public static inline var BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080; + public static inline var BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100; + + public static inline var MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001; + public static inline var MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002; + public static inline var MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004; + public static inline var MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008; + public static inline var MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010; + + public static inline var IMAGE_TYPE_1D = 0; + public static inline var IMAGE_TYPE_2D = 1; + public static inline var IMAGE_TYPE_3D = 2; + + public static inline var IMAGE_TILING_OPTIMAL = 0; + public static inline var IMAGE_TILING_LINEAR = 1; + + public static inline var IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001; + public static inline var IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002; + public static inline var IMAGE_USAGE_SAMPLED_BIT = 0x00000004; + public static inline var IMAGE_USAGE_STORAGE_BIT = 0x00000008; + public static inline var IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010; + public static inline var IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020; + public static inline var IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040; + public static inline var IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080; + + public static inline var IMAGE_ASPECT_COLOR_BIT = 0x00000001; + public static inline var IMAGE_ASPECT_DEPTH_BIT = 0x00000002; + public static inline var IMAGE_ASPECT_STENCIL_BIT = 0x00000004; + public static inline var IMAGE_ASPECT_METADATA_BIT = 0x00000008; + + public static inline var COLOR_COMPONENT_R_BIT = 0x00000001; + public static inline var COLOR_COMPONENT_G_BIT = 0x00000002; + public static inline var COLOR_COMPONENT_B_BIT = 0x00000004; + public static inline var COLOR_COMPONENT_A_BIT = 0x00000008; + public static inline var COLOR_COMPONENT_RGBA_BITS = COLOR_COMPONENT_R_BIT | COLOR_COMPONENT_G_BIT | COLOR_COMPONENT_B_BIT | COLOR_COMPONENT_A_BIT; + + public static inline var IMAGE_LAYOUT_UNDEFINED = 0; + public static inline var IMAGE_LAYOUT_GENERAL = 1; + public static inline var IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2; + public static inline var IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3; + public static inline var IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4; + public static inline var IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5; + public static inline var IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6; + public static inline var IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7; + public static inline var IMAGE_LAYOUT_PREINITIALIZED = 8; + public static inline var IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002; + + public static inline var IMAGE_VIEW_TYPE_1D = 0; + public static inline var IMAGE_VIEW_TYPE_2D = 1; + public static inline var IMAGE_VIEW_TYPE_3D = 2; + public static inline var IMAGE_VIEW_TYPE_CUBE = 3; + public static inline var IMAGE_VIEW_TYPE_1D_ARRAY = 4; + public static inline var IMAGE_VIEW_TYPE_2D_ARRAY = 5; + public static inline var IMAGE_VIEW_TYPE_CUBE_ARRAY = 6; + + public static inline var PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001; + public static inline var PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002; + public static inline var PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004; + public static inline var PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008; + public static inline var PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080; + public static inline var PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100; + public static inline var PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200; + public static inline var PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400; + public static inline var PIPELINE_STAGE_TRANSFER_BIT = 0x00001000; + public static inline var PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000; + public static inline var PIPELINE_STAGE_HOST_BIT = 0x00004000; + public static inline var PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000; + public static inline var PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000; + + public static inline var ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001; + public static inline var ACCESS_INDEX_READ_BIT = 0x00000002; + public static inline var ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004; + public static inline var ACCESS_UNIFORM_READ_BIT = 0x00000008; + public static inline var ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010; + public static inline var ACCESS_SHADER_READ_BIT = 0x00000020; + public static inline var ACCESS_SHADER_WRITE_BIT = 0x00000040; + public static inline var ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080; + public static inline var ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100; + public static inline var ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200; + public static inline var ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400; + public static inline var ACCESS_TRANSFER_READ_BIT = 0x00000800; + public static inline var ACCESS_TRANSFER_WRITE_BIT = 0x00001000; + public static inline var ACCESS_HOST_READ_BIT = 0x00002000; + public static inline var ACCESS_HOST_WRITE_BIT = 0x00004000; + public static inline var ACCESS_MEMORY_READ_BIT = 0x00008000; + public static inline var ACCESS_MEMORY_WRITE_BIT = 0x00010000; + + public static inline var SHADER_STAGE_VERTEX_BIT = 0x00000001; + public static inline var SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002; + public static inline var SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004; + public static inline var SHADER_STAGE_GEOMETRY_BIT = 0x00000008; + public static inline var SHADER_STAGE_FRAGMENT_BIT = 0x00000010; + public static inline var SHADER_STAGE_COMPUTE_BIT = 0x00000020; + public static inline var SHADER_STAGE_ALL_GRAPHICS = 0x0000001F; + public static inline var SHADER_STAGE_ALL = 0x7FFFFFFF; + + public static inline var DESCRIPTOR_TYPE_SAMPLER = 0; + public static inline var DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1; + public static inline var DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2; + public static inline var DESCRIPTOR_TYPE_STORAGE_IMAGE = 3; + public static inline var DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4; + public static inline var DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5; + public static inline var DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6; + public static inline var DESCRIPTOR_TYPE_STORAGE_BUFFER = 7; + public static inline var DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8; + public static inline var DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9; + public static inline var DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10; + + public static inline var PRIMITIVE_TOPOLOGY_POINT_LIST = 0; + public static inline var PRIMITIVE_TOPOLOGY_LINE_LIST = 1; + public static inline var PRIMITIVE_TOPOLOGY_LINE_STRIP = 2; + public static inline var PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3; + public static inline var PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4; + public static inline var PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5; + + public static inline var POLYGON_MODE_FILL = 0; + public static inline var POLYGON_MODE_LINE = 1; + public static inline var POLYGON_MODE_POINT = 2; + + public static inline var CULL_MODE_NONE = 0; + public static inline var CULL_MODE_FRONT_BIT = 0x00000001; + public static inline var CULL_MODE_BACK_BIT = 0x00000002; + public static inline var CULL_MODE_FRONT_AND_BACK = 0x00000003; + + public static inline var FRONT_FACE_COUNTER_CLOCKWISE = 0; + public static inline var FRONT_FACE_CLOCKWISE = 1; + + public static inline var COMPARE_OP_NEVER = 0; + public static inline var COMPARE_OP_LESS = 1; + public static inline var COMPARE_OP_EQUAL = 2; + public static inline var COMPARE_OP_LESS_OR_EQUAL = 3; + public static inline var COMPARE_OP_GREATER = 4; + public static inline var COMPARE_OP_NOT_EQUAL = 5; + public static inline var COMPARE_OP_GREATER_OR_EQUAL = 6; + public static inline var COMPARE_OP_ALWAYS = 7; + + public static inline var STENCIL_OP_KEEP = 0; + public static inline var STENCIL_OP_ZERO = 1; + public static inline var STENCIL_OP_REPLACE = 2; + public static inline var STENCIL_OP_INCREMENT_AND_CLAMP = 3; + public static inline var STENCIL_OP_DECREMENT_AND_CLAMP = 4; + public static inline var STENCIL_OP_INVERT = 5; + public static inline var STENCIL_OP_INCREMENT_AND_WRAP = 6; + public static inline var STENCIL_OP_DECREMENT_AND_WRAP = 7; + + public static inline var BLEND_FACTOR_ZERO = 0; + public static inline var BLEND_FACTOR_ONE = 1; + public static inline var BLEND_FACTOR_SRC_COLOR = 2; + public static inline var BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3; + public static inline var BLEND_FACTOR_DST_COLOR = 4; + public static inline var BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5; + public static inline var BLEND_FACTOR_SRC_ALPHA = 6; + public static inline var BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7; + public static inline var BLEND_FACTOR_DST_ALPHA = 8; + public static inline var BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9; + public static inline var BLEND_FACTOR_CONSTANT_COLOR = 10; + public static inline var BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11; + public static inline var BLEND_FACTOR_CONSTANT_ALPHA = 12; + public static inline var BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13; + public static inline var BLEND_FACTOR_SRC_ALPHA_SATURATE = 14; + + public static inline var BLEND_OP_ADD = 0; + public static inline var BLEND_OP_SUBTRACT = 1; + public static inline var BLEND_OP_REVERSE_SUBTRACT = 2; + public static inline var BLEND_OP_MIN = 3; + public static inline var BLEND_OP_MAX = 4; + + public static inline var DYNAMIC_STATE_VIEWPORT = 0; + public static inline var DYNAMIC_STATE_SCISSOR = 1; + public static inline var DYNAMIC_STATE_LINE_WIDTH = 2; + public static inline var DYNAMIC_STATE_DEPTH_BIAS = 3; + public static inline var DYNAMIC_STATE_BLEND_CONSTANTS = 4; + public static inline var DYNAMIC_STATE_DEPTH_BOUNDS = 5; + public static inline var DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6; + public static inline var DYNAMIC_STATE_STENCIL_WRITE_MASK = 7; + public static inline var DYNAMIC_STATE_STENCIL_REFERENCE = 8; + public static inline var DYNAMIC_STATE_VIEWPORT_BIT = 0x00000001; + public static inline var DYNAMIC_STATE_SCISSOR_BIT = 0x00000002; + + public static inline var SAMPLE_COUNT_1_BIT = 0x00000001; + public static inline var SAMPLE_COUNT_2_BIT = 0x00000002; + public static inline var SAMPLE_COUNT_4_BIT = 0x00000004; + public static inline var SAMPLE_COUNT_8_BIT = 0x00000008; + public static inline var SAMPLE_COUNT_16_BIT = 0x00000010; + public static inline var SAMPLE_COUNT_32_BIT = 0x00000020; + public static inline var SAMPLE_COUNT_64_BIT = 0x00000040; + + public static inline var INDEX_TYPE_UINT16 = 0; + public static inline var INDEX_TYPE_UINT32 = 1; + public static inline var INDEX_TYPE_UINT8_KHR = 1000265000; + + public static inline var ATTACHMENT_LOAD_OP_LOAD = 0; + public static inline var ATTACHMENT_LOAD_OP_CLEAR = 1; + public static inline var ATTACHMENT_LOAD_OP_DONT_CARE = 2; + public static inline var ATTACHMENT_STORE_OP_STORE = 0; + public static inline var ATTACHMENT_STORE_OP_DONT_CARE = 1; + + public static inline var FILTER_NEAREST = 0; + public static inline var FILTER_LINEAR = 1; + public static inline var SAMPLER_MIPMAP_MODE_NEAREST = 0; + public static inline var SAMPLER_MIPMAP_MODE_LINEAR = 1; + public static inline var SAMPLER_ADDRESS_MODE_REPEAT = 0; + public static inline var SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1; + public static inline var SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2; + public static inline var SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3; + + public static inline var PIPELINE_BIND_POINT_GRAPHICS = 0; + public static inline var SUBPASS_CONTENTS_INLINE = 0; + public static inline var SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1; + public static inline var VERTEX_INPUT_RATE_VERTEX = 0; + public static inline var VERTEX_INPUT_RATE_INSTANCE = 1; + + /** + Creates a managed `VkInstance` for the current Lime Vulkan window. + **/ + public static function createInstance(context:VulkanRenderContext, applicationName:String = "Lime"):VKInstance + { + if (context == null) + { + return null; + } + + #if (!macro && lime_cffi) + var handleData:Dynamic = NativeCFFI.lime_vk_create_instance(context.__windowHandle, applicationName); + if (handleData != null) + { + var handle = __makeHandle(handleData); + if (!__isZero(handle)) + { + return new VKInstance(context, handle); + } + } + #end + + return null; + } + + /** + Returns the last bootstrap-layer Vulkan error surfaced by Lime. + **/ + public static function getLastError():String + { + #if (!macro && lime_cffi) + var value:Dynamic = NativeCFFI.lime_vk_get_last_error(); + if (value != null) + { + return CFFI.stringValue(value); + } + #end + + return ""; + } + + /** + Picks a preferred physical device from an enumerated device list. + This currently prefers graphics-capable devices, optionally requiring + present support, and favors discrete GPUs by default. + **/ + public static function pickPhysicalDevice(devices:Array, requirePresent:Bool = false, + preferDiscrete:Bool = true):VKPhysicalDevice + { + if (devices == null || devices.length == 0) + { + return null; + } + + var bestDevice:VKPhysicalDevice = null; + var bestScore = -1; + + for (device in devices) + { + var score = __scorePhysicalDevice(device, requirePresent, preferDiscrete); + if (score > bestScore) + { + bestScore = score; + bestDevice = device; + } + } + + return bestDevice; + } + + public static inline function versionString(version:Int):String + { + var major = version >>> 22; + var minor = (version >>> 12) & 0x3FF; + var patch = version & 0xFFF; + return major + "." + minor + "." + patch; + } + + @:allow(lime.graphics.VulkanRenderContext) + @:allow(lime.graphics.vulkan.VKBuffer) + @:allow(lime.graphics.vulkan.VKCommandBuffer) + @:allow(lime.graphics.vulkan.VKCommandPool) + @:allow(lime.graphics.vulkan.VKDescriptorPool) + @:allow(lime.graphics.vulkan.VKDescriptorSet) + @:allow(lime.graphics.vulkan.VKDescriptorSetLayout) + @:allow(lime.graphics.vulkan.VKDevice) + @:allow(lime.graphics.vulkan.VKDeviceMemory) + @:allow(lime.graphics.vulkan.VKFence) + @:allow(lime.graphics.vulkan.VKFramebuffer) + @:allow(lime.graphics.vulkan.VKImage) + @:allow(lime.graphics.vulkan.VKImageView) + @:allow(lime.graphics.vulkan.VKInstance) + @:allow(lime.graphics.vulkan.VKMemoryRequirements) + @:allow(lime.graphics.vulkan.VKPhysicalDevice) + @:allow(lime.graphics.vulkan.VKPipeline) + @:allow(lime.graphics.vulkan.VKPipelineCache) + @:allow(lime.graphics.vulkan.VKPipelineLayout) + @:allow(lime.graphics.vulkan.VKQueue) + @:allow(lime.graphics.vulkan.VKRenderPass) + @:allow(lime.graphics.vulkan.VKSampler) + @:allow(lime.graphics.vulkan.VKSemaphore) + @:allow(lime.graphics.vulkan.VKShaderModule) + @:allow(lime.graphics.vulkan.VKSwapchain) + private static function __makeHandle(value:Dynamic):Int64 + { + if (value == null) + { + return Int64.ofInt(0); + } + + return Int64.make(value.high, value.low); + } + + @:allow(lime.graphics.VulkanRenderContext) + @:allow(lime.graphics.vulkan.VKBuffer) + @:allow(lime.graphics.vulkan.VKCommandBuffer) + @:allow(lime.graphics.vulkan.VKCommandPool) + @:allow(lime.graphics.vulkan.VKDescriptorPool) + @:allow(lime.graphics.vulkan.VKDescriptorSet) + @:allow(lime.graphics.vulkan.VKDescriptorSetLayout) + @:allow(lime.graphics.vulkan.VKDevice) + @:allow(lime.graphics.vulkan.VKDeviceMemory) + @:allow(lime.graphics.vulkan.VKFence) + @:allow(lime.graphics.vulkan.VKFramebuffer) + @:allow(lime.graphics.vulkan.VKImage) + @:allow(lime.graphics.vulkan.VKImageView) + @:allow(lime.graphics.vulkan.VKInstance) + @:allow(lime.graphics.vulkan.VKMemoryRequirements) + @:allow(lime.graphics.vulkan.VKQueue) + @:allow(lime.graphics.vulkan.VKPipeline) + @:allow(lime.graphics.vulkan.VKPipelineCache) + @:allow(lime.graphics.vulkan.VKPipelineLayout) + @:allow(lime.graphics.vulkan.VKRenderPass) + @:allow(lime.graphics.vulkan.VKSampler) + @:allow(lime.graphics.vulkan.VKSemaphore) + @:allow(lime.graphics.vulkan.VKShaderModule) + @:allow(lime.graphics.vulkan.VKSwapchain) + private static inline function __isZero(handle:Int64):Bool + { + return handle.high == 0 && handle.low == 0; + } + + private static function __scorePhysicalDevice(device:VKPhysicalDevice, requirePresent:Bool, preferDiscrete:Bool):Int + { + if (device == null || !device.hasQueueFamily(true, requirePresent)) + { + return -1; + } + + var score = 0; + + switch (device.deviceType) + { + case PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + score += preferDiscrete ? 400 : 250; + case PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + score += preferDiscrete ? 300 : 400; + case PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + score += 150; + case PHYSICAL_DEVICE_TYPE_CPU: + score += 100; + default: + score += 50; + } + + var primaryQueue = device.getQueueFamily(true, requirePresent); + if (primaryQueue != null) + { + score += primaryQueue.queueCount * 2; + if (primaryQueue.supportsTransfer) score += 4; + if (primaryQueue.supportsCompute) score += 2; + } + + score += device.queueFamilies.length; + return score; + } +} diff --git a/src/lime/graphics/vulkan/VKAcquireResult.hx b/src/lime/graphics/vulkan/VKAcquireResult.hx new file mode 100644 index 0000000000..60b269426d --- /dev/null +++ b/src/lime/graphics/vulkan/VKAcquireResult.hx @@ -0,0 +1,22 @@ +package lime.graphics.vulkan; + +/** + Result metadata from `vkAcquireNextImageKHR`. +**/ +class VKAcquireResult +{ + public var imageIndex(default, null):Int; + public var result(default, null):Int; + + @:allow(lime.graphics.vulkan.VKSwapchain) + private function new(result:Int, imageIndex:Int) + { + this.result = result; + this.imageIndex = imageIndex; + } + + public inline function isSuccess():Bool + { + return result == VK.SUCCESS || result == VK.SUBOPTIMAL_KHR; + } +} diff --git a/src/lime/graphics/vulkan/VKBuffer.hx b/src/lime/graphics/vulkan/VKBuffer.hx new file mode 100644 index 0000000000..de31962199 --- /dev/null +++ b/src/lime/graphics/vulkan/VKBuffer.hx @@ -0,0 +1,156 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import haxe.io.Bytes; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan buffer usable for vertex, index, uniform, staging, or storage data. +**/ +class VKBuffer +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var memory(default, null):VKDeviceMemory; + public var size(default, null):Int64; + public var usage(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64, size:Int64, usage:Int) + { + this.device = device; + this.handle = handle; + this.size = size; + this.usage = usage; + } + + public function allocateMemory(properties:Int):VKDeviceMemory + { + if (device == null) + { + return null; + } + + var allocated = device.allocateMemory(getMemoryRequirements(), properties); + if (allocated != null && bindMemory(allocated)) + { + memory = allocated; + return allocated; + } + + if (allocated != null) + { + allocated.dispose(); + } + return null; + } + + public function bindMemory(memory:VKDeviceMemory, offset:Int64 = null):Bool + { + if (offset == null) + { + offset = Int64.ofInt(0); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && memory != null && memory.isValid()) + { + var result = NativeCFFI.lime_vk_bind_buffer_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, memory.handle.high, memory.handle.low, + offset.high, offset.low); + if (result) + { + this.memory = memory; + } + return result; + } + #end + + return false; + } + + public function dispose(destroyMemory:Bool = false):Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_buffer(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + + if (destroyMemory && memory != null) + { + memory.dispose(); + memory = null; + } + } + + public inline function get():Int64 + { + return handle; + } + + public function getMemoryRequirements():VKMemoryRequirements + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_get_buffer_memory_requirements(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low); + return VKMemoryRequirements.fromDynamic(data); + } + #end + + return null; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function map(offset:Int64 = null, size:Int64 = null, flags:Int = 0):Bool + { + return memory != null && memory.map(offset, size, flags); + } + + public function unmap():Void + { + if (memory != null) + { + memory.unmap(); + } + } + + public function writeBytes(bytes:Bytes, srcOffset:Int = 0, length:Int = -1, dstOffset:Int64 = null):Bool + { + return memory != null && memory.writeBytes(bytes, srcOffset, length, dstOffset); + } + + public function flush(offset:Int64 = null, size:Int64 = null):Bool + { + return memory != null && memory.flush(offset, size); + } + + public function invalidate(offset:Int64 = null, size:Int64 = null):Bool + { + return memory != null && memory.invalidate(offset, size); + } + + public function upload(bytes:Bytes, memoryOffset:Int64 = null, byteOffset:Int = 0, byteLength:Int = -1):Bool + { + return memory != null && memory.upload(bytes, memoryOffset, byteOffset, byteLength); + } + + public function download(bytes:Bytes, memoryOffset:Int64 = null, byteOffset:Int = 0, byteLength:Int = -1):Bool + { + return memory != null && memory.download(bytes, memoryOffset, byteOffset, byteLength); + } +} diff --git a/src/lime/graphics/vulkan/VKCommandBuffer.hx b/src/lime/graphics/vulkan/VKCommandBuffer.hx new file mode 100644 index 0000000000..12638f2e2a --- /dev/null +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -0,0 +1,543 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan command buffer allocated from a `VKCommandPool`. +**/ +class VKCommandBuffer +{ + public var device(get, never):VKDevice; + public var handle(default, null):Int64; + public var level(default, null):Int; + public var pool(default, null):VKCommandPool; + + @:allow(lime.graphics.vulkan.VKCommandPool) + private function new(pool:VKCommandPool, handle:Int64, level:Int) + { + this.pool = pool; + this.handle = handle; + this.level = level; + } + + public function begin(flags:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && pool != null && pool.device != null && pool.device.isValid()) + { + return NativeCFFI.lime_vk_begin_command_buffer(pool.device.instance.context.__windowHandle, pool.device.instance.handle.high, + pool.device.instance.handle.low, pool.device.handle.high, pool.device.handle.low, handle.high, handle.low, flags); + } + #end + + return false; + } + + public function dispose():Void + { + if (pool != null) + { + pool.free(this); + } + } + + public function beginRenderPass(renderPass:VKRenderPass, framebuffer:VKFramebuffer, width:Int, height:Int, + clearRed:Float = 0, clearGreen:Float = 0, clearBlue:Float = 0, clearAlpha:Float = 1, + clearDepth:Float = 1, clearStencil:Int = 0, x:Int = 0, y:Int = 0):Bool + { + var clearValueCount = renderPass != null && renderPass.depthStencilFormat != VK.FORMAT_UNDEFINED ? 2 : 1; + var state = [x, y, width, height, clearStencil, clearValueCount]; + var clear = [clearRed, clearGreen, clearBlue, clearAlpha, clearDepth]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && renderPass != null && renderPass.isValid() && framebuffer != null + && framebuffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_begin_render_pass(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, renderPass.handle.high, + renderPass.handle.low, framebuffer.handle.high, framebuffer.handle.low, state, clear); + } + #end + + return false; + } + + public function bindDescriptorSet(layout:VKPipelineLayout, descriptorSet:VKDescriptorSet, firstSet:Int = 0, + bindPoint:Int = VK.PIPELINE_BIND_POINT_GRAPHICS, dynamicOffsets:Array = null):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && layout != null && layout.isValid() && descriptorSet != null && descriptorSet.isValid()) + { + if (dynamicOffsets != null && dynamicOffsets.length > 0) + { + var state = [bindPoint, firstSet, dynamicOffsets.length]; + for (offset in dynamicOffsets) + { + state.push(offset); + } + return NativeCFFI.lime_vk_cmd_bind_descriptor_set_ex(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, layout.handle.high, layout.handle.low, + descriptorSet.handle.high, descriptorSet.handle.low, state); + } + + return NativeCFFI.lime_vk_cmd_bind_descriptor_set(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, layout.handle.high, layout.handle.low, + descriptorSet.handle.high, descriptorSet.handle.low, bindPoint, firstSet); + } + #end + + return false; + } + + public function bindDescriptorSetDynamicOffset(layout:VKPipelineLayout, descriptorSet:VKDescriptorSet, dynamicOffset:Int, firstSet:Int = 0, + bindPoint:Int = VK.PIPELINE_BIND_POINT_GRAPHICS):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && layout != null && layout.isValid() && descriptorSet != null && descriptorSet.isValid()) + { + return NativeCFFI.lime_vk_cmd_bind_descriptor_set_dynamic_offset(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, layout.handle.high, layout.handle.low, + descriptorSet.handle.high, descriptorSet.handle.low, dynamicOffset, firstSet, bindPoint); + } + #end + + return false; + } + + public function bindIndexBuffer(buffer:VKBuffer, offset:Int64 = null, indexType:Int = VK.INDEX_TYPE_UINT16):Bool + { + if (offset == null) + { + offset = Int64.ofInt(0); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_bind_index_buffer(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, buffer.handle.high, buffer.handle.low, + offset.high, offset.low, indexType); + } + #end + + return false; + } + + public function bindPipeline(pipeline:VKPipeline, bindPoint:Int = VK.PIPELINE_BIND_POINT_GRAPHICS):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && pipeline != null && pipeline.isValid()) + { + return NativeCFFI.lime_vk_cmd_bind_pipeline(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, pipeline.handle.high, pipeline.handle.low, + bindPoint); + } + #end + + return false; + } + + public function bindVertexBuffer(buffer:VKBuffer, binding:Int = 0, offset:Int64 = null):Bool + { + if (offset == null) + { + offset = Int64.ofInt(0); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_bind_vertex_buffer(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, buffer.handle.high, buffer.handle.low, + binding, offset.high, offset.low); + } + #end + + return false; + } + + public function blitImage(source:VKImage, destination:VKImage, width:Int, height:Int, sourceLayout:Int = VK.IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + destinationLayout:Int = VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, filter:Int = VK.FILTER_LINEAR):Bool + { + return blitImageRegion(source, destination, width, height, sourceLayout, destinationLayout, filter); + } + + public function blitImageRegion(source:VKImage, destination:VKImage, sourceWidth:Int, sourceHeight:Int, + sourceLayout:Int = VK.IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destinationLayout:Int = VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + filter:Int = VK.FILTER_LINEAR, destinationWidth:Int = -1, destinationHeight:Int = -1, sourceX:Int = 0, sourceY:Int = 0, + sourceZ:Int = 0, destinationX:Int = 0, destinationY:Int = 0, destinationZ:Int = 0, sourceDepth:Int = 1, destinationDepth:Int = 1, + sourceMipLevel:Int = 0, destinationMipLevel:Int = 0, sourceBaseArrayLayer:Int = 0, destinationBaseArrayLayer:Int = 0, layerCount:Int = 1, + aspectMask:Int = VK.IMAGE_ASPECT_COLOR_BIT):Bool + { + if (destinationWidth < 0) destinationWidth = sourceWidth; + if (destinationHeight < 0) destinationHeight = sourceHeight; + var state = [ + sourceX, + sourceY, + sourceZ, + sourceX + sourceWidth, + sourceY + sourceHeight, + sourceZ + sourceDepth, + destinationX, + destinationY, + destinationZ, + destinationX + destinationWidth, + destinationY + destinationHeight, + destinationZ + destinationDepth, + sourceLayout, + destinationLayout, + filter, + sourceMipLevel, + destinationMipLevel, + sourceBaseArrayLayer, + destinationBaseArrayLayer, + layerCount, + aspectMask + ]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && source != null && source.isValid() && destination != null && destination.isValid()) + { + return NativeCFFI.lime_vk_cmd_blit_image(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, source.handle.high, source.handle.low, destination.handle.high, + destination.handle.low, state); + } + #end + + return false; + } + + public function clearColorImage(image:VKImage, layout:Int, red:Float, green:Float, blue:Float, alpha:Float, + aspectMask:Int = VK.IMAGE_ASPECT_COLOR_BIT):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && image != null && image.isValid()) + { + return NativeCFFI.lime_vk_cmd_clear_color_image(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, image.handle.high, image.handle.low, + layout, aspectMask, [red, green, blue, alpha]); + } + #end + + return false; + } + + public function clearDepthStencilImage(image:VKImage, layout:Int, depth:Float = 1, stencil:Int = 0, + aspectMask:Int = VK.IMAGE_ASPECT_DEPTH_BIT | VK.IMAGE_ASPECT_STENCIL_BIT, baseMipLevel:Int = 0, levelCount:Int = 1, + baseArrayLayer:Int = 0, layerCount:Int = 1):Bool + { + var state = [layout, stencil, aspectMask, baseMipLevel, levelCount, baseArrayLayer, layerCount]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && image != null && image.isValid()) + { + return NativeCFFI.lime_vk_cmd_clear_depth_stencil_image(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, image.handle.high, image.handle.low, + state, [depth]); + } + #end + + return false; + } + + public function clearAttachments(color:Bool, depth:Bool, stencil:Bool, x:Int, y:Int, width:Int, height:Int, red:Float = 0, + green:Float = 0, blue:Float = 0, alpha:Float = 0, depthValue:Float = 1, stencilValue:Int = 0):Bool + { + var state = [color ? 1 : 0, depth ? 1 : 0, stencil ? 1 : 0, x, y, width, height, stencilValue]; + var clear = [red, green, blue, alpha, depthValue]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_clear_attachments(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, state, clear); + } + #end + + return false; + } + + public function copyBuffer(source:VKBuffer, destination:VKBuffer, size:Int64, sourceOffset:Int64 = null, destinationOffset:Int64 = null):Bool + { + if (sourceOffset == null) sourceOffset = Int64.ofInt(0); + if (destinationOffset == null) destinationOffset = Int64.ofInt(0); + var state = [size.high, size.low, sourceOffset.high, sourceOffset.low, destinationOffset.high, destinationOffset.low]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && source != null && source.isValid() && destination != null && destination.isValid()) + { + return NativeCFFI.lime_vk_cmd_copy_buffer(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, source.handle.high, source.handle.low, destination.handle.high, + destination.handle.low, state); + } + #end + + return false; + } + + public function copyBufferToImage(buffer:VKBuffer, image:VKImage, width:Int, height:Int, + layout:Int = VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL):Bool + { + return copyBufferToImageRegion(buffer, image, width, height, layout); + } + + public function copyBufferToImageRegion(buffer:VKBuffer, image:VKImage, width:Int, height:Int, + layout:Int = VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, depth:Int = 1, bufferOffset:Int64 = null, bufferRowLength:Int = 0, + bufferImageHeight:Int = 0, imageX:Int = 0, imageY:Int = 0, imageZ:Int = 0, mipLevel:Int = 0, baseArrayLayer:Int = 0, + layerCount:Int = 1, aspectMask:Int = VK.IMAGE_ASPECT_COLOR_BIT):Bool + { + if (bufferOffset == null) bufferOffset = Int64.ofInt(0); + var state = [ + width, + height, + depth, + layout, + bufferOffset.high, + bufferOffset.low, + bufferRowLength, + bufferImageHeight, + imageX, + imageY, + imageZ, + mipLevel, + baseArrayLayer, + layerCount, + aspectMask + ]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid() && image != null && image.isValid()) + { + return NativeCFFI.lime_vk_cmd_copy_buffer_to_image_region(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, buffer.handle.high, buffer.handle.low, + image.handle.high, image.handle.low, state); + } + #end + + return false; + } + + public function copyImageToBufferRegion(image:VKImage, buffer:VKBuffer, width:Int, height:Int, + layout:Int = VK.IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depth:Int = 1, bufferOffset:Int64 = null, bufferRowLength:Int = 0, + bufferImageHeight:Int = 0, imageX:Int = 0, imageY:Int = 0, imageZ:Int = 0, mipLevel:Int = 0, baseArrayLayer:Int = 0, + layerCount:Int = 1, aspectMask:Int = VK.IMAGE_ASPECT_COLOR_BIT):Bool + { + if (bufferOffset == null) bufferOffset = Int64.ofInt(0); + var state = [ + width, + height, + depth, + layout, + bufferOffset.high, + bufferOffset.low, + bufferRowLength, + bufferImageHeight, + imageX, + imageY, + imageZ, + mipLevel, + baseArrayLayer, + layerCount, + aspectMask + ]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && image != null && image.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_copy_image_to_buffer_region(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, image.handle.high, image.handle.low, + buffer.handle.high, buffer.handle.low, state); + } + #end + + return false; + } + + public function draw(vertexCount:Int, instanceCount:Int = 1, firstVertex:Int = 0, firstInstance:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_draw(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, vertexCount, instanceCount, firstVertex, firstInstance); + } + #end + + return false; + } + + public function drawIndexed(indexCount:Int, instanceCount:Int = 1, firstIndex:Int = 0, vertexOffset:Int = 0, firstInstance:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_draw_indexed(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + } + #end + + return false; + } + + public function drawIndirect(buffer:VKBuffer, offset:Int64, drawCount:Int, stride:Int):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_draw_indirect(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, buffer.handle.high, buffer.handle.low, + offset.high, offset.low, drawCount, stride); + } + #end + + return false; + } + + public function drawIndexedIndirect(buffer:VKBuffer, offset:Int64, drawCount:Int, stride:Int):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_cmd_draw_indexed_indirect(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, buffer.handle.high, buffer.handle.low, + offset.high, offset.low, drawCount, stride); + } + #end + + return false; + } + + public function end():Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && pool != null && pool.device != null && pool.device.isValid()) + { + return NativeCFFI.lime_vk_end_command_buffer(pool.device.instance.context.__windowHandle, pool.device.instance.handle.high, + pool.device.instance.handle.low, pool.device.handle.high, pool.device.handle.low, handle.high, handle.low); + } + #end + + return false; + } + + public function endRenderPass():Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_end_render_pass(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low); + } + #end + + return false; + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function reset(flags:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && pool != null && pool.device != null && pool.device.isValid()) + { + return NativeCFFI.lime_vk_reset_command_buffer(pool.device.instance.context.__windowHandle, pool.device.instance.handle.high, + pool.device.instance.handle.low, pool.device.handle.high, pool.device.handle.low, handle.high, handle.low, flags); + } + #end + + return false; + } + + public function pipelineBarrierImage(image:VKImage, oldLayout:Int, newLayout:Int, srcStageMask:Int, dstStageMask:Int, srcAccessMask:Int, + dstAccessMask:Int, aspectMask:Int, baseMipLevel:Int = 0, levelCount:Int = 1, baseArrayLayer:Int = 0, layerCount:Int = 1):Bool + { + var state = [oldLayout, newLayout, srcStageMask, dstStageMask, srcAccessMask, dstAccessMask, aspectMask, baseMipLevel, levelCount, + baseArrayLayer, layerCount]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && image != null && image.isValid()) + { + return NativeCFFI.lime_vk_cmd_pipeline_barrier_image(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, image.handle.high, image.handle.low, state); + } + #end + + return false; + } + + public function pushConstants(layout:VKPipelineLayout, stageFlags:Int, bytes:haxe.io.Bytes, offset:Int = 0, byteOffset:Int = 0, + byteLength:Int = -1):Bool + { + if (bytes == null || layout == null) + { + return false; + } + if (byteLength < 0) + { + byteLength = bytes.length - byteOffset; + } + var state = [stageFlags, offset, byteOffset, byteLength]; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && layout.isValid()) + { + return NativeCFFI.lime_vk_cmd_push_constants(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, layout.handle.high, layout.handle.low, state, + bytes); + } + #end + + return false; + } + + public function setScissor(x:Int, y:Int, width:Int, height:Int):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_set_scissor(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, x, y, width, height); + } + #end + + return false; + } + + public function setViewport(x:Float, y:Float, width:Float, height:Float, minDepth:Float = 0, maxDepth:Float = 1):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_cmd_set_viewport(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, x, y, width, height, minDepth, maxDepth); + } + #end + + return false; + } + + @:allow(lime.graphics.vulkan.VKCommandPool) + private function __invalidate():Void + { + handle = Int64.ofInt(0); + } + + private inline function get_device():VKDevice + { + return (pool != null) ? pool.device : null; + } +} diff --git a/src/lime/graphics/vulkan/VKCommandPool.hx b/src/lime/graphics/vulkan/VKCommandPool.hx new file mode 100644 index 0000000000..a95be9ee2e --- /dev/null +++ b/src/lime/graphics/vulkan/VKCommandPool.hx @@ -0,0 +1,93 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan command pool created from a `VKDevice`. +**/ +class VKCommandPool +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var queueFamilyIndex(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, queueFamilyIndex:Int, handle:Int64) + { + this.device = device; + this.queueFamilyIndex = queueFamilyIndex; + this.handle = handle; + } + + public function allocateCommandBuffer(level:Int = VK.COMMAND_BUFFER_LEVEL_PRIMARY):VKCommandBuffer + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_allocate_command_buffer(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, level); + var commandBufferHandle = VK.__makeHandle(data); + if (!VK.__isZero(commandBufferHandle)) + { + return new VKCommandBuffer(this, commandBufferHandle, level); + } + } + #end + + return null; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_command_pool(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function reset(flags:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_reset_command_pool(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, flags); + } + #end + + return false; + } + + @:allow(lime.graphics.vulkan.VKCommandBuffer) + private function free(commandBuffer:VKCommandBuffer):Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (commandBuffer != null && commandBuffer.isValid() && isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_free_command_buffer(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, commandBuffer.handle.high, commandBuffer.handle.low); + commandBuffer.__invalidate(); + } + #end + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorPool.hx b/src/lime/graphics/vulkan/VKDescriptorPool.hx new file mode 100644 index 0000000000..e754efbb31 --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorPool.hx @@ -0,0 +1,75 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKDescriptorPool +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function allocate(layout:VKDescriptorSetLayout):VKDescriptorSet + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && layout != null && layout.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_allocate_descriptor_set(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, layout.handle.high, layout.handle.low); + var descriptorSetHandle = VK.__makeHandle(data); + if (!VK.__isZero(descriptorSetHandle)) + { + return new VKDescriptorSet(this, layout, descriptorSetHandle); + } + } + #end + + return null; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_descriptor_pool(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function reset(flags:Int = 0):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_reset_descriptor_pool(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, flags); + } + #end + + return false; + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorPoolSize.hx b/src/lime/graphics/vulkan/VKDescriptorPoolSize.hx new file mode 100644 index 0000000000..6b83cab5ef --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorPoolSize.hx @@ -0,0 +1,13 @@ +package lime.graphics.vulkan; + +class VKDescriptorPoolSize +{ + public var descriptorCount:Int; + public var descriptorType:Int; + + public function new(descriptorType:Int, descriptorCount:Int) + { + this.descriptorType = descriptorType; + this.descriptorCount = descriptorCount; + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorSet.hx b/src/lime/graphics/vulkan/VKDescriptorSet.hx new file mode 100644 index 0000000000..26c7d806c6 --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorSet.hx @@ -0,0 +1,73 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKDescriptorSet +{ + public var device(get, never):VKDevice; + public var handle(default, null):Int64; + public var layout(default, null):VKDescriptorSetLayout; + public var pool(default, null):VKDescriptorPool; + + @:allow(lime.graphics.vulkan.VKDescriptorPool) + private function new(pool:VKDescriptorPool, layout:VKDescriptorSetLayout, handle:Int64) + { + this.pool = pool; + this.layout = layout; + this.handle = handle; + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function updateBuffer(binding:Int, buffer:VKBuffer, range:Int, offset:Int = 0, + descriptorType:Int = VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + var device = get_device(); + if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid()) + { + return NativeCFFI.lime_vk_update_descriptor_set_buffer(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, binding, descriptorType, + buffer.handle.high, buffer.handle.low, offset, range); + } + #end + + return false; + } + + public function updateImage(binding:Int, imageView:VKImageView, sampler:VKSampler = null, + layout:Int = VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, descriptorType:Int = VK.DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + var device = get_device(); + if (isValid() && device != null && device.isValid() && imageView != null && imageView.isValid()) + { + var samplerHandle = (sampler != null && sampler.isValid()) ? sampler.handle : Int64.ofInt(0); + return NativeCFFI.lime_vk_update_descriptor_set_image(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, binding, descriptorType, + imageView.handle.high, imageView.handle.low, samplerHandle.high, samplerHandle.low, layout); + } + #end + + return false; + } + + private inline function get_device():VKDevice + { + return pool != null ? pool.device : null; + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx b/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx new file mode 100644 index 0000000000..d14fb572ba --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx @@ -0,0 +1,44 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKDescriptorSetLayout +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_descriptor_set_layout(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorSetLayoutBinding.hx b/src/lime/graphics/vulkan/VKDescriptorSetLayoutBinding.hx new file mode 100644 index 0000000000..b3ab2368ae --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorSetLayoutBinding.hx @@ -0,0 +1,17 @@ +package lime.graphics.vulkan; + +class VKDescriptorSetLayoutBinding +{ + public var binding:Int; + public var descriptorCount:Int; + public var descriptorType:Int; + public var stageFlags:Int; + + public function new(binding:Int, descriptorType:Int, stageFlags:Int, descriptorCount:Int = 1) + { + this.binding = binding; + this.descriptorType = descriptorType; + this.stageFlags = stageFlags; + this.descriptorCount = descriptorCount; + } +} diff --git a/src/lime/graphics/vulkan/VKDescriptorWrite.hx b/src/lime/graphics/vulkan/VKDescriptorWrite.hx new file mode 100644 index 0000000000..5768a76244 --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorWrite.hx @@ -0,0 +1,115 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +/** + A single descriptor write used by `VKDevice.updateDescriptorSets()`. +**/ +class VKDescriptorWrite +{ + private static inline var KIND_BUFFER = 0; + private static inline var KIND_IMAGE = 1; + + public var arrayElement:Int; + public var binding:Int; + public var buffer:VKBuffer; + public var descriptorSet:VKDescriptorSet; + public var descriptorType:Int; + public var imageLayout:Int; + public var imageView:VKImageView; + public var offset:Int64; + public var range:Int64; + public var sampler:VKSampler; + + private var kind:Int; + + public function new() + { + arrayElement = 0; + binding = 0; + descriptorType = VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER; + imageLayout = VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + kind = KIND_BUFFER; + offset = Int64.ofInt(0); + range = Int64.ofInt(0); + } + + public static function forBuffer(descriptorSet:VKDescriptorSet, binding:Int, buffer:VKBuffer, range:Int64 = null, + offset:Int64 = null, descriptorType:Int = VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER, arrayElement:Int = 0):VKDescriptorWrite + { + var write = new VKDescriptorWrite(); + write.kind = KIND_BUFFER; + write.descriptorSet = descriptorSet; + write.binding = binding; + write.buffer = buffer; + write.range = range != null ? range : Int64.ofInt(0); + write.offset = offset != null ? offset : Int64.ofInt(0); + write.descriptorType = descriptorType; + write.arrayElement = arrayElement; + return write; + } + + public static function forImage(descriptorSet:VKDescriptorSet, binding:Int, imageView:VKImageView, sampler:VKSampler = null, + imageLayout:Int = VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + descriptorType:Int = VK.DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arrayElement:Int = 0):VKDescriptorWrite + { + var write = new VKDescriptorWrite(); + write.kind = KIND_IMAGE; + write.descriptorSet = descriptorSet; + write.binding = binding; + write.imageView = imageView; + write.sampler = sampler; + write.imageLayout = imageLayout; + write.descriptorType = descriptorType; + write.arrayElement = arrayElement; + return write; + } + + @:allow(lime.graphics.vulkan.VKDevice) + private function pack(result:Array):Bool + { + if (descriptorSet == null || !descriptorSet.isValid()) + { + return false; + } + + if (kind == KIND_IMAGE) + { + if (imageView == null || !imageView.isValid()) + { + return false; + } + var samplerHandle = (sampler != null && sampler.isValid()) ? sampler.handle : Int64.ofInt(0); + result.push(KIND_IMAGE); + result.push(descriptorSet.handle.high); + result.push(descriptorSet.handle.low); + result.push(binding); + result.push(arrayElement); + result.push(descriptorType); + result.push(imageView.handle.high); + result.push(imageView.handle.low); + result.push(samplerHandle.high); + result.push(samplerHandle.low); + result.push(imageLayout); + return true; + } + + if (buffer == null || !buffer.isValid()) + { + return false; + } + result.push(KIND_BUFFER); + result.push(descriptorSet.handle.high); + result.push(descriptorSet.handle.low); + result.push(binding); + result.push(arrayElement); + result.push(descriptorType); + result.push(buffer.handle.high); + result.push(buffer.handle.low); + result.push(offset.high); + result.push(offset.low); + result.push(range.high); + result.push(range.low); + return true; + } +} diff --git a/src/lime/graphics/vulkan/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx new file mode 100644 index 0000000000..28e375114e --- /dev/null +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -0,0 +1,575 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import haxe.io.Bytes; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A logical Vulkan device created from a `VKPhysicalDevice`. +**/ +class VKDevice +{ + public var extensions(default, null):Array; + public var graphicsQueue(default, null):VKQueue; + public var handle(default, null):Int64; + public var instance(default, null):VKInstance; + public var physicalDevice(default, null):VKPhysicalDevice; + public var queueFamily(default, null):VKQueueFamilyInfo; + + @:allow(lime.graphics.vulkan.VKPhysicalDevice) + private function new(physicalDevice:VKPhysicalDevice, queueFamily:VKQueueFamilyInfo, extensions:Array, data:Dynamic) + { + this.physicalDevice = physicalDevice; + this.instance = physicalDevice.instance; + this.queueFamily = queueFamily; + this.extensions = extensions.copy(); + handle = VK.__makeHandle(data.handle); + graphicsQueue = new VKQueue(this, VK.__makeHandle(data.queue), data.queueFamilyIndex, 0); + } + + public function createCommandPool(queueFamily:VKQueueFamilyInfo = null, flags:Int = VK.COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT):VKCommandPool + { + if (queueFamily == null) + { + queueFamily = this.queueFamily; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && queueFamily != null) + { + var data:Dynamic = NativeCFFI.lime_vk_create_command_pool(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, queueFamily.index, flags); + var commandPoolHandle = VK.__makeHandle(data); + if (!VK.__isZero(commandPoolHandle)) + { + return new VKCommandPool(this, queueFamily.index, commandPoolHandle); + } + } + #end + + return null; + } + + public function createFence(signaled:Bool = false):VKFence + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var flags = signaled ? VK.FENCE_CREATE_SIGNALED_BIT : 0; + var data:Dynamic = NativeCFFI.lime_vk_create_fence(instance.context.__windowHandle, instance.handle.high, instance.handle.low, handle.high, + handle.low, flags); + var fenceHandle = VK.__makeHandle(data); + if (!VK.__isZero(fenceHandle)) + { + return new VKFence(this, fenceHandle); + } + } + #end + + return null; + } + + public function allocateMemory(requirements:VKMemoryRequirements, properties:Int):VKDeviceMemory + { + if (requirements == null) + { + return null; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_allocate_memory(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + physicalDevice.handle.high, physicalDevice.handle.low, handle.high, handle.low, requirements.size.high, requirements.size.low, + requirements.memoryTypeBits, properties); + var memoryHandle = VK.__makeHandle(data != null ? data.handle : null); + if (!VK.__isZero(memoryHandle)) + { + return new VKDeviceMemory(this, memoryHandle, requirements.size, data.memoryTypeIndex, properties); + } + } + #end + + return null; + } + + public function createBuffer(size:Int64, usage:Int):VKBuffer + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_buffer(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, size.high, size.low, usage); + var bufferHandle = VK.__makeHandle(data); + if (!VK.__isZero(bufferHandle)) + { + return new VKBuffer(this, bufferHandle, size, usage); + } + } + #end + + return null; + } + + public function createBufferWithMemory(size:Int64, usage:Int, properties:Int, bytes:Bytes = null):VKBuffer + { + var buffer = createBuffer(size, usage); + if (buffer == null) + { + return null; + } + + var memory = buffer.allocateMemory(properties); + if (memory == null) + { + buffer.dispose(); + return null; + } + + if (bytes != null && !buffer.upload(bytes)) + { + buffer.dispose(true); + return null; + } + + return buffer; + } + + public inline function createIndexBuffer(size:Int64, properties:Int, bytes:Bytes = null):VKBuffer + { + return createBufferWithMemory(size, VK.BUFFER_USAGE_INDEX_BUFFER_BIT, properties, bytes); + } + + public inline function createStagingBuffer(size:Int64, bytes:Bytes = null):VKBuffer + { + return createBufferWithMemory(size, VK.BUFFER_USAGE_TRANSFER_SRC_BIT, + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT, bytes); + } + + public inline function createUploadRing(byteCapacity:Int, usage:Int = VK.BUFFER_USAGE_TRANSFER_SRC_BIT, + properties:Int = VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT):VKUploadRing + { + return new VKUploadRing(this, byteCapacity, usage, properties); + } + + public inline function createStorageBuffer(size:Int64, properties:Int, bytes:Bytes = null):VKBuffer + { + return createBufferWithMemory(size, VK.BUFFER_USAGE_STORAGE_BUFFER_BIT, properties, bytes); + } + + public inline function createUniformBuffer(size:Int64, properties:Int, bytes:Bytes = null):VKBuffer + { + return createBufferWithMemory(size, VK.BUFFER_USAGE_UNIFORM_BUFFER_BIT, properties, bytes); + } + + public inline function createVertexBuffer(size:Int64, properties:Int, bytes:Bytes = null):VKBuffer + { + return createBufferWithMemory(size, VK.BUFFER_USAGE_VERTEX_BUFFER_BIT, properties, bytes); + } + + public function createDescriptorPool(maxSets:Int, poolSizes:Array, flags:Int = 0):VKDescriptorPool + { + var packed = [flags, maxSets, poolSizes != null ? poolSizes.length : 0]; + if (poolSizes != null) + { + for (poolSize in poolSizes) + { + packed.push(poolSize.descriptorType); + packed.push(poolSize.descriptorCount); + } + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_descriptor_pool(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, packed); + var descriptorPoolHandle = VK.__makeHandle(data); + if (!VK.__isZero(descriptorPoolHandle)) + { + return new VKDescriptorPool(this, descriptorPoolHandle); + } + } + #end + + return null; + } + + public function createDescriptorSetLayout(bindings:Array, flags:Int = 0):VKDescriptorSetLayout + { + var packed = [flags, bindings != null ? bindings.length : 0]; + if (bindings != null) + { + for (binding in bindings) + { + packed.push(binding.binding); + packed.push(binding.descriptorType); + packed.push(binding.descriptorCount); + packed.push(binding.stageFlags); + } + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_descriptor_set_layout(instance.context.__windowHandle, instance.handle.high, + instance.handle.low, handle.high, handle.low, packed); + var descriptorSetLayoutHandle = VK.__makeHandle(data); + if (!VK.__isZero(descriptorSetLayoutHandle)) + { + return new VKDescriptorSetLayout(this, descriptorSetLayoutHandle); + } + } + #end + + return null; + } + + public function updateDescriptorSets(writes:Array):Bool + { + if (writes == null || writes.length == 0) + { + return true; + } + + var packed = [writes.length]; + for (write in writes) + { + if (write == null || !write.pack(packed)) + { + return false; + } + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + return NativeCFFI.lime_vk_update_descriptor_sets(instance.context.__windowHandle, instance.handle.high, instance.handle.low, handle.high, + handle.low, packed); + } + #end + + return false; + } + + public function createFramebuffer(renderPass:VKRenderPass, attachments:Array, width:Int, height:Int, layers:Int = 1):VKFramebuffer + { + if (renderPass == null || !renderPass.isValid() || attachments == null || attachments.length == 0) + { + return null; + } + + var packed = [attachments.length]; + for (attachment in attachments) + { + if (attachment == null || !attachment.isValid()) + { + return null; + } + packed.push(attachment.handle.high); + packed.push(attachment.handle.low); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_framebuffer(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, renderPass.handle.high, renderPass.handle.low, packed, width, height, layers); + var framebufferHandle = VK.__makeHandle(data); + if (!VK.__isZero(framebufferHandle)) + { + return new VKFramebuffer(this, renderPass, framebufferHandle, width, height); + } + } + #end + + return null; + } + + public function createGraphicsPipeline(renderPass:VKRenderPass, layout:VKPipelineLayout, vertexShader:VKShaderModule, + fragmentShader:VKShaderModule, info:VKGraphicsPipelineInfo, cache:VKPipelineCache = null):VKPipeline + { + if (renderPass == null || layout == null || vertexShader == null || fragmentShader == null) + { + return null; + } + if (info == null) + { + info = new VKGraphicsPipelineInfo(); + } + + var cacheHandle = cache != null && cache.isValid() ? cache.handle : Int64.ofInt(0); + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && renderPass.isValid() && layout.isValid() && vertexShader.isValid() && fragmentShader.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_graphics_pipeline(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, renderPass.handle.high, renderPass.handle.low, layout.handle.high, layout.handle.low, + vertexShader.handle.high, vertexShader.handle.low, fragmentShader.handle.high, fragmentShader.handle.low, info.pack(cacheHandle)); + var pipelineHandle = VK.__makeHandle(data); + if (!VK.__isZero(pipelineHandle)) + { + return new VKPipeline(this, layout, pipelineHandle); + } + } + #end + + return null; + } + + public function createImage(width:Int, height:Int, format:Int, usage:Int, depth:Int = 1, mipLevels:Int = 1, arrayLayers:Int = 1, + imageType:Int = VK.IMAGE_TYPE_2D, tiling:Int = VK.IMAGE_TILING_OPTIMAL, samples:Int = VK.SAMPLE_COUNT_1_BIT):VKImage + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_image(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, width, height, depth, mipLevels, arrayLayers, format, imageType, tiling, usage, samples); + var imageHandle = VK.__makeHandle(data); + if (!VK.__isZero(imageHandle)) + { + return VKImage.createOwned(this, imageHandle, width, height, format); + } + } + #end + + return null; + } + + public function createPipelineCache(bytes:Bytes = null, byteOffset:Int = 0, byteLength:Int = -1):VKPipelineCache + { + if (byteLength < 0 && bytes != null) + { + byteLength = bytes.length - byteOffset; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_pipeline_cache(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, bytes, byteOffset, byteLength); + var pipelineCacheHandle = VK.__makeHandle(data); + if (!VK.__isZero(pipelineCacheHandle)) + { + return new VKPipelineCache(this, pipelineCacheHandle); + } + } + #end + + return null; + } + + public function createPipelineLayout(descriptorSetLayouts:Array = null, pushConstantStages:Int = 0, + pushConstantSize:Int = 0):VKPipelineLayout + { + var packed = [descriptorSetLayouts != null ? descriptorSetLayouts.length : 0]; + if (descriptorSetLayouts != null) + { + for (layout in descriptorSetLayouts) + { + if (layout == null || !layout.isValid()) + { + return null; + } + packed.push(layout.handle.high); + packed.push(layout.handle.low); + } + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_pipeline_layout(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, packed, pushConstantStages, pushConstantSize); + var pipelineLayoutHandle = VK.__makeHandle(data); + if (!VK.__isZero(pipelineLayoutHandle)) + { + return new VKPipelineLayout(this, pipelineLayoutHandle); + } + } + #end + + return null; + } + + public function createRenderPass(colorFormat:Int, depthStencilFormat:Int = VK.FORMAT_UNDEFINED, + samples:Int = VK.SAMPLE_COUNT_1_BIT, colorLoadOp:Int = VK.ATTACHMENT_LOAD_OP_CLEAR, + colorStoreOp:Int = VK.ATTACHMENT_STORE_OP_STORE, colorInitialLayout:Int = VK.IMAGE_LAYOUT_UNDEFINED, + colorFinalLayout:Int = VK.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + depthInitialLayout:Int = VK.IMAGE_LAYOUT_UNDEFINED, + depthFinalLayout:Int = VK.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + depthLoadOp:Int = VK.ATTACHMENT_LOAD_OP_CLEAR, depthStoreOp:Int = VK.ATTACHMENT_STORE_OP_DONT_CARE, + resolveFormat:Int = VK.FORMAT_UNDEFINED, resolveLoadOp:Int = VK.ATTACHMENT_LOAD_OP_DONT_CARE, + resolveStoreOp:Int = VK.ATTACHMENT_STORE_OP_STORE, resolveInitialLayout:Int = VK.IMAGE_LAYOUT_UNDEFINED, + resolveFinalLayout:Int = VK.IMAGE_LAYOUT_PRESENT_SRC_KHR):VKRenderPass + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var state = [ + colorFormat, + depthStencilFormat, + samples, + colorLoadOp, + colorStoreOp, + colorInitialLayout, + colorFinalLayout, + depthInitialLayout, + depthFinalLayout, + depthLoadOp, + depthStoreOp, + resolveFormat, + resolveLoadOp, + resolveStoreOp, + resolveInitialLayout, + resolveFinalLayout + ]; + var data:Dynamic = NativeCFFI.lime_vk_create_render_pass(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, state); + var renderPassHandle = VK.__makeHandle(data); + if (!VK.__isZero(renderPassHandle)) + { + return new VKRenderPass(this, renderPassHandle, colorFormat, depthStencilFormat, samples, resolveFormat); + } + } + #end + + return null; + } + + public function createSampler(filter:Int = VK.FILTER_LINEAR, addressMode:Int = VK.SAMPLER_ADDRESS_MODE_REPEAT, + mipmapMode:Int = VK.SAMPLER_MIPMAP_MODE_LINEAR, anisotropyEnable:Bool = false, maxAnisotropy:Float = 1, + compareOp:Int = -1, minLod:Float = 0, maxLod:Float = 0):VKSampler + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_sampler(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, filter, addressMode, mipmapMode, anisotropyEnable, maxAnisotropy, compareOp, minLod, maxLod); + var samplerHandle = VK.__makeHandle(data); + if (!VK.__isZero(samplerHandle)) + { + return new VKSampler(this, samplerHandle); + } + } + #end + + return null; + } + + public function createSemaphore():VKSemaphore + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_semaphore(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low); + var semaphoreHandle = VK.__makeHandle(data); + if (!VK.__isZero(semaphoreHandle)) + { + return new VKSemaphore(this, semaphoreHandle); + } + } + #end + + return null; + } + + public function createShaderModule(bytes:Bytes, byteOffset:Int = 0, byteLength:Int = -1):VKShaderModule + { + if (bytes == null) + { + return null; + } + if (byteLength < 0) + { + byteLength = bytes.length - byteOffset; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_shader_module(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, bytes, byteOffset, byteLength); + var shaderModuleHandle = VK.__makeHandle(data); + if (!VK.__isZero(shaderModuleHandle)) + { + return new VKShaderModule(this, shaderModuleHandle); + } + } + #end + + return null; + } + + /** + Creates a swapchain for a window surface. Pass an existing swapchain as + `oldSwapchain` when recreating resources after a resize. + **/ + public function createSwapchain(surface:VKSurface, width:Int = 0, height:Int = 0, presentMode:Int = VK.PRESENT_MODE_FIFO_KHR, + oldSwapchain:VKSwapchain = null):VKSwapchain + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && surface != null && surface.isValid() && queueFamily != null) + { + var oldSwapchainHandle = (oldSwapchain != null && oldSwapchain.isValid()) ? oldSwapchain.handle : Int64.ofInt(0); + var data:Dynamic = NativeCFFI.lime_vk_create_swapchain(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + physicalDevice.handle.high, physicalDevice.handle.low, handle.high, handle.low, surface.high, surface.low, queueFamily.index, width, + height, presentMode, oldSwapchainHandle.high, oldSwapchainHandle.low); + var swapchainHandle = VK.__makeHandle(data != null ? data.handle : null); + if (!VK.__isZero(swapchainHandle)) + { + return new VKSwapchain(this, surface, data); + } + } + #end + + return null; + } + + /** + Destroys the logical device. All resources created from the device should + be destroyed before calling this method. + **/ + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + NativeCFFI.lime_vk_destroy_device(instance.context.__windowHandle, instance.handle.high, instance.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + graphicsQueue = null; + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + /** + Blocks until the logical device has completed all submitted work. + **/ + public function waitIdle():Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + return NativeCFFI.lime_vk_device_wait_idle(instance.context.__windowHandle, instance.handle.high, instance.handle.low, handle.high, handle.low); + } + #end + + return false; + } +} diff --git a/src/lime/graphics/vulkan/VKDeviceMemory.hx b/src/lime/graphics/vulkan/VKDeviceMemory.hx new file mode 100644 index 0000000000..39dc6ad5ee --- /dev/null +++ b/src/lime/graphics/vulkan/VKDeviceMemory.hx @@ -0,0 +1,257 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import haxe.io.Bytes; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + Device memory allocated from a `VKDevice`. +**/ +class VKDeviceMemory +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var memoryTypeIndex(default, null):Int; + public var mapped(default, null):Bool = false; + public var mappedOffset(default, null):Int64 = Int64.ofInt(0); + public var mappedSize(default, null):Int64 = Int64.ofInt(0); + public var properties(default, null):Int; + public var size(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64, size:Int64, memoryTypeIndex:Int, properties:Int) + { + this.device = device; + this.handle = handle; + this.size = size; + this.memoryTypeIndex = memoryTypeIndex; + this.properties = properties; + } + + public function dispose():Void + { + if (mapped) + { + unmap(); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_free_memory(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + /** + Maps host-visible memory and keeps it mapped for repeated writes or + readback. Passing `size` as `null` maps the rest of the allocation. + **/ + public function map(offset:Int64 = null, size:Int64 = null, flags:Int = 0):Bool + { + if (offset == null) + { + offset = Int64.ofInt(0); + } + if (size == null) + { + size = Int64.ofInt(0); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var result = NativeCFFI.lime_vk_map_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, offset.high, offset.low, size.high, + size.low, flags); + if (result) + { + mapped = true; + mappedOffset = offset; + mappedSize = size; + } + return result; + } + #end + + return false; + } + + public function unmap():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (mapped && isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_unmap_memory(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + } + #end + + mapped = false; + mappedOffset = Int64.ofInt(0); + mappedSize = Int64.ofInt(0); + } + + /** + Copies bytes into a currently mapped range without unmapping. This is the + hot-path companion to `upload()` for dynamic vertex/uniform streaming. + **/ + public function writeBytes(bytes:Bytes, srcOffset:Int = 0, length:Int = -1, dstOffset:Int64 = null):Bool + { + if (bytes == null || !mapped) + { + return false; + } + if (dstOffset == null) + { + dstOffset = mappedOffset; + } + if (length < 0) + { + length = bytes.length - srcOffset; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_write_mapped_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, dstOffset.high, dstOffset.low, bytes, + srcOffset, length); + } + #end + + return false; + } + + public function flush(offset:Int64 = null, size:Int64 = null):Bool + { + if (!mapped) + { + return false; + } + if (offset == null) + { + offset = mappedOffset; + } + if (size == null) + { + size = mappedSize; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_flush_mapped_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, offset.high, offset.low, size.high, + size.low); + } + #end + + return false; + } + + public function invalidate(offset:Int64 = null, size:Int64 = null):Bool + { + if (!mapped) + { + return false; + } + if (offset == null) + { + offset = mappedOffset; + } + if (size == null) + { + size = mappedSize; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_invalidate_mapped_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, offset.high, offset.low, size.high, + size.low); + } + #end + + return false; + } + + /** + Copies bytes into host-visible memory. This maps and unmaps internally, + which is convenient for staging/uniform data and avoids exposing unsafe + raw pointers at the Lime boundary. + **/ + public function upload(bytes:Bytes, memoryOffset:Int64 = null, byteOffset:Int = 0, byteLength:Int = -1):Bool + { + if (memoryOffset == null) + { + memoryOffset = Int64.ofInt(0); + } + if (bytes == null) + { + return false; + } + if (byteLength < 0) + { + byteLength = bytes.length - byteOffset; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_upload_memory(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, memoryOffset.high, memoryOffset.low, bytes, byteOffset, byteLength); + } + #end + + return false; + } + + /** + Copies host-visible memory into a Haxe `Bytes` buffer. Use this after an + image-to-buffer transfer for render target and texture capture paths. + **/ + public function download(bytes:Bytes, memoryOffset:Int64 = null, byteOffset:Int = 0, byteLength:Int = -1):Bool + { + if (memoryOffset == null) + { + memoryOffset = Int64.ofInt(0); + } + if (bytes == null) + { + return false; + } + if (byteLength < 0) + { + byteLength = bytes.length - byteOffset; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_download_memory(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, memoryOffset.high, memoryOffset.low, bytes, byteOffset, byteLength); + } + #end + + return false; + } +} diff --git a/src/lime/graphics/vulkan/VKFence.hx b/src/lime/graphics/vulkan/VKFence.hx new file mode 100644 index 0000000000..6fd009ac1f --- /dev/null +++ b/src/lime/graphics/vulkan/VKFence.hx @@ -0,0 +1,78 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan fence used for CPU/GPU synchronization. +**/ +class VKFence +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_fence(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function reset():Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_reset_fence(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + } + #end + + return false; + } + + public function wait(timeout:Int64):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_wait_for_fence(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, timeout.high, timeout.low); + } + #end + + return false; + } + + public function waitForever():Bool + { + return wait(Int64.make(-1, -1)); + } +} diff --git a/src/lime/graphics/vulkan/VKFramebuffer.hx b/src/lime/graphics/vulkan/VKFramebuffer.hx new file mode 100644 index 0000000000..be12eaf8b9 --- /dev/null +++ b/src/lime/graphics/vulkan/VKFramebuffer.hx @@ -0,0 +1,50 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKFramebuffer +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var height(default, null):Int; + public var renderPass(default, null):VKRenderPass; + public var width(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, renderPass:VKRenderPass, handle:Int64, width:Int, height:Int) + { + this.device = device; + this.renderPass = renderPass; + this.handle = handle; + this.width = width; + this.height = height; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_framebuffer(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx new file mode 100644 index 0000000000..527a44ada0 --- /dev/null +++ b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx @@ -0,0 +1,121 @@ +package lime.graphics.vulkan; + +class VKGraphicsPipelineInfo +{ + public var alphaBlendOp:Int = VK.BLEND_OP_ADD; + public var colorBlendOp:Int = VK.BLEND_OP_ADD; + public var colorWriteMask:Int = VK.COLOR_COMPONENT_RGBA_BITS; + public var cullMode:Int = VK.CULL_MODE_BACK_BIT; + public var backCompareMask:Int = -1; + public var backCompareOp:Int = VK.COMPARE_OP_ALWAYS; + public var backDepthFailOp:Int = VK.STENCIL_OP_KEEP; + public var backFailOp:Int = VK.STENCIL_OP_KEEP; + public var backPassOp:Int = VK.STENCIL_OP_KEEP; + public var backReference:Int = 0; + public var backWriteMask:Int = -1; + public var depthCompareOp:Int = VK.COMPARE_OP_LESS; + public var depthTest:Bool = false; + public var depthWrite:Bool = false; + public var dstAlphaBlendFactor:Int = VK.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + public var dstColorBlendFactor:Int = VK.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + public var dynamicStateFlags:Int = VK.DYNAMIC_STATE_VIEWPORT_BIT | VK.DYNAMIC_STATE_SCISSOR_BIT; + public var frontCompareMask:Int = -1; + public var frontCompareOp:Int = VK.COMPARE_OP_ALWAYS; + public var frontDepthFailOp:Int = VK.STENCIL_OP_KEEP; + public var frontFailOp:Int = VK.STENCIL_OP_KEEP; + public var frontFace:Int = VK.FRONT_FACE_COUNTER_CLOCKWISE; + public var frontPassOp:Int = VK.STENCIL_OP_KEEP; + public var frontReference:Int = 0; + public var frontWriteMask:Int = -1; + public var polygonMode:Int = VK.POLYGON_MODE_FILL; + public var primitiveRestart:Bool = false; + public var rasterizationSamples:Int = VK.SAMPLE_COUNT_1_BIT; + public var sampleShading:Bool = false; + public var minSampleShading:Float = 0; + public var sampleMask:Int = 0; + public var alphaToCoverage:Bool = false; + public var alphaToOne:Bool = false; + public var srcAlphaBlendFactor:Int = VK.BLEND_FACTOR_ONE; + public var srcColorBlendFactor:Int = VK.BLEND_FACTOR_SRC_ALPHA; + public var stencilTest:Bool = false; + public var topology:Int = VK.PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + public var vertexAttributes:Array; + public var vertexBindings:Array; + public var blend:Bool = false; + + public function new() + { + vertexAttributes = []; + vertexBindings = []; + } + + @:allow(lime.graphics.vulkan.VKDevice) + private function pack(cacheHandle:haxe.Int64 = null):Array + { + if (cacheHandle == null) + { + cacheHandle = haxe.Int64.ofInt(0); + } + var result = [ + cacheHandle.high, + cacheHandle.low, + topology, + primitiveRestart ? 1 : 0, + polygonMode, + cullMode, + frontFace, + depthTest ? 1 : 0, + depthWrite ? 1 : 0, + depthCompareOp, + blend ? 1 : 0, + srcColorBlendFactor, + dstColorBlendFactor, + colorBlendOp, + srcAlphaBlendFactor, + dstAlphaBlendFactor, + alphaBlendOp, + dynamicStateFlags, + colorWriteMask, + stencilTest ? 1 : 0, + frontFailOp, + frontPassOp, + frontDepthFailOp, + frontCompareOp, + frontCompareMask, + frontWriteMask, + frontReference, + backFailOp, + backPassOp, + backDepthFailOp, + backCompareOp, + backCompareMask, + backWriteMask, + backReference, + rasterizationSamples, + sampleShading ? 1 : 0, + Std.int(minSampleShading * 1000000), + sampleMask, + alphaToCoverage ? 1 : 0, + alphaToOne ? 1 : 0, + vertexBindings.length + ]; + + for (binding in vertexBindings) + { + result.push(binding.binding); + result.push(binding.stride); + result.push(binding.inputRate); + } + + result.push(vertexAttributes.length); + for (attribute in vertexAttributes) + { + result.push(attribute.location); + result.push(attribute.binding); + result.push(attribute.format); + result.push(attribute.offset); + } + + return result; + } +} diff --git a/src/lime/graphics/vulkan/VKImage.hx b/src/lime/graphics/vulkan/VKImage.hx new file mode 100644 index 0000000000..491f40350a --- /dev/null +++ b/src/lime/graphics/vulkan/VKImage.hx @@ -0,0 +1,165 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan image handle. Swapchain images are owned by their `VKSwapchain`. +**/ +class VKImage +{ + public var device(default, null):VKDevice; + public var format(default, null):Int; + public var handle(default, null):Int64; + public var height(default, null):Int; + public var index(default, null):Int; + public var memory(default, null):VKDeviceMemory; + public var ownsHandle(default, null):Bool; + public var swapchain(default, null):VKSwapchain; + public var width(default, null):Int; + + @:allow(lime.graphics.vulkan.VKSwapchain) + private function new(swapchain:VKSwapchain, handle:Int64, index:Int) + { + this.swapchain = swapchain; + this.device = swapchain != null ? swapchain.device : null; + this.handle = handle; + this.index = index; + this.format = swapchain != null ? swapchain.format : VK.FORMAT_UNDEFINED; + this.width = swapchain != null ? swapchain.width : 0; + this.height = swapchain != null ? swapchain.height : 0; + this.ownsHandle = false; + } + + @:allow(lime.graphics.vulkan.VKDevice) + private static function createOwned(device:VKDevice, handle:Int64, width:Int, height:Int, format:Int):VKImage + { + var image = new VKImage(null, handle, -1); + image.swapchain = null; + image.device = device; + image.handle = handle; + image.index = -1; + image.format = format; + image.width = width; + image.height = height; + image.ownsHandle = true; + return image; + } + + public function allocateMemory(properties:Int):VKDeviceMemory + { + if (device == null) + { + return null; + } + + var allocated = device.allocateMemory(getMemoryRequirements(), properties); + if (allocated != null && bindMemory(allocated)) + { + memory = allocated; + return allocated; + } + + if (allocated != null) + { + allocated.dispose(); + } + return null; + } + + public function bindMemory(memory:VKDeviceMemory, offset:Int64 = null):Bool + { + if (offset == null) + { + offset = Int64.ofInt(0); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && memory != null && memory.isValid()) + { + var result = NativeCFFI.lime_vk_bind_image_memory(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, memory.handle.high, memory.handle.low, + offset.high, offset.low); + if (result) + { + this.memory = memory; + } + return result; + } + #end + + return false; + } + + public function createView(format:Int = 0, aspectMask:Int = VK.IMAGE_ASPECT_COLOR_BIT, viewType:Int = VK.IMAGE_VIEW_TYPE_2D, + baseMipLevel:Int = 0, levelCount:Int = 1, baseArrayLayer:Int = 0, layerCount:Int = 1):VKImageView + { + if (format == 0) + { + format = this.format; + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_image_view_ex(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, format, aspectMask, viewType, + baseMipLevel, levelCount, baseArrayLayer, layerCount); + var imageViewHandle = VK.__makeHandle(data); + if (!VK.__isZero(imageViewHandle)) + { + return new VKImageView(this, imageViewHandle, format, aspectMask, viewType); + } + } + #end + + return null; + } + + public function dispose(destroyMemory:Bool = false):Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (ownsHandle && isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_image(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + + if (destroyMemory && memory != null) + { + memory.dispose(); + memory = null; + } + } + + public inline function get():Int64 + { + return handle; + } + + public function getMemoryRequirements():VKMemoryRequirements + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_get_image_memory_requirements(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low); + return VKMemoryRequirements.fromDynamic(data); + } + #end + + return null; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKImageView.hx b/src/lime/graphics/vulkan/VKImageView.hx new file mode 100644 index 0000000000..5cf888f93a --- /dev/null +++ b/src/lime/graphics/vulkan/VKImageView.hx @@ -0,0 +1,55 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan image view created for a `VKImage`. +**/ +class VKImageView +{ + public var aspectMask(default, null):Int; + public var device(default, null):VKDevice; + public var format(default, null):Int; + public var handle(default, null):Int64; + public var image(default, null):VKImage; + public var viewType(default, null):Int; + + @:allow(lime.graphics.vulkan.VKImage) + private function new(image:VKImage, handle:Int64, format:Int, aspectMask:Int, viewType:Int) + { + this.image = image; + this.device = image.device; + this.handle = handle; + this.format = format; + this.aspectMask = aspectMask; + this.viewType = viewType; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_image_view(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKInstance.hx b/src/lime/graphics/vulkan/VKInstance.hx new file mode 100644 index 0000000000..71d4e079a3 --- /dev/null +++ b/src/lime/graphics/vulkan/VKInstance.hx @@ -0,0 +1,111 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.graphics.VulkanRenderContext; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A lightweight managed `VkInstance` wrapper created through `VK.createInstance`. +**/ +class VKInstance +{ + public var context(default, null):VulkanRenderContext; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VK) + private function new(context:VulkanRenderContext, handle:Int64) + { + this.context = context; + this.handle = handle; + } + + /** + Creates a `VKSurface` for the current window using this instance. + **/ + public function createSurface(contextOverride:VulkanRenderContext = null):VKSurface + { + var activeContext = (contextOverride != null) ? contextOverride : context; + + if (activeContext == null || VK.__isZero(handle)) + { + return null; + } + + #if (!macro && lime_cffi) + var surfaceData:Dynamic = NativeCFFI.lime_window_create_vulkan_surface(activeContext.__windowHandle, handle.high, handle.low); + if (surfaceData != null) + { + return new VKSurface(activeContext, this, surfaceData.high, surfaceData.low); + } + #end + + return null; + } + + /** + Destroys the managed `VkInstance`. + **/ + public function dispose():Void + { + #if (!macro && lime_cffi) + if (context != null && !VK.__isZero(handle)) + { + NativeCFFI.lime_vk_destroy_instance(context.__windowHandle, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + /** + Enumerates physical devices visible to this instance. If a surface is + provided, queue family presentation support is populated for that surface. + **/ + public function enumeratePhysicalDevices(surface:VKSurface = null):Array + { + var devices = new Array(); + + if (context == null || VK.__isZero(handle)) + { + return devices; + } + + #if (!macro && lime_cffi) + var result:Dynamic = NativeCFFI.lime_vk_get_physical_devices(context.__windowHandle, handle.high, handle.low, surface != null ? surface.high : 0, + surface != null ? surface.low : 0); + + if (result != null) + { + var length:Int = untyped result.length; + for (i in 0...length) + { + devices.push(new VKPhysicalDevice(this, untyped result[i])); + } + } + #end + + return devices; + } + + /** + Selects a preferred physical device using Lime's lightweight heuristics. + **/ + public function pickPhysicalDevice(surface:VKSurface = null, preferDiscrete:Bool = true):VKPhysicalDevice + { + return VK.pickPhysicalDevice(enumeratePhysicalDevices(surface), surface != null && surface.isValid(), preferDiscrete); + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKMemoryRequirements.hx b/src/lime/graphics/vulkan/VKMemoryRequirements.hx new file mode 100644 index 0000000000..5be95984ff --- /dev/null +++ b/src/lime/graphics/vulkan/VKMemoryRequirements.hx @@ -0,0 +1,32 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +/** + Memory requirements returned by Vulkan for buffers and images. +**/ +class VKMemoryRequirements +{ + public var alignment(default, null):Int64; + public var memoryTypeBits(default, null):Int; + public var size(default, null):Int64; + + public function new(size:Int64, alignment:Int64, memoryTypeBits:Int) + { + this.size = size; + this.alignment = alignment; + this.memoryTypeBits = memoryTypeBits; + } + + @:allow(lime.graphics.vulkan.VKBuffer) + @:allow(lime.graphics.vulkan.VKImage) + private static function fromDynamic(data:Dynamic):VKMemoryRequirements + { + if (data == null) + { + return null; + } + + return new VKMemoryRequirements(VK.__makeHandle(data.size), VK.__makeHandle(data.alignment), data.memoryTypeBits); + } +} diff --git a/src/lime/graphics/vulkan/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx new file mode 100644 index 0000000000..c05a23fc4f --- /dev/null +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -0,0 +1,180 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFI; +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + Describes a Vulkan physical device discovered through a `VKInstance`. +**/ +class VKPhysicalDevice +{ + public var instance(default, null):VKInstance; + public var handle(default, null):Int64; + public var name(default, null):String; + public var apiVersion(default, null):Int; + public var apiVersionString(default, null):String; + public var driverVersion(default, null):Int; + public var vendorID(default, null):Int; + public var deviceID(default, null):Int; + public var deviceType(default, null):Int; + public var deviceTypeName(default, null):String; + public var framebufferColorSampleCounts(default, null):Int; + public var framebufferDepthSampleCounts(default, null):Int; + public var framebufferNoAttachmentsSampleCounts(default, null):Int; + public var framebufferStencilSampleCounts(default, null):Int; + public var isDiscrete(default, null):Bool; + public var maxPushConstantsSize(default, null):Int; + public var minStorageBufferOffsetAlignment(default, null):Int64; + public var minUniformBufferOffsetAlignment(default, null):Int64; + public var nonCoherentAtomSize(default, null):Int64; + public var supportsPresent(default, null):Bool; + public var queueFamilies(default, null):Array; + + @:allow(lime.graphics.vulkan.VKInstance) + private function new(instance:VKInstance, data:Dynamic) + { + this.instance = instance; + handle = VK.__makeHandle(data.handle); + name = (data.name != null) ? #if (!lime_doc_gen || lime_cffi) CFFI.stringValue(data.name) #else cast data.name #end : ""; + apiVersion = data.apiVersion; + apiVersionString = VK.versionString(apiVersion); + driverVersion = data.driverVersion; + vendorID = data.vendorID; + deviceID = data.deviceID; + deviceType = data.deviceType; + framebufferColorSampleCounts = data.framebufferColorSampleCounts; + framebufferDepthSampleCounts = data.framebufferDepthSampleCounts; + framebufferNoAttachmentsSampleCounts = data.framebufferNoAttachmentsSampleCounts; + framebufferStencilSampleCounts = data.framebufferStencilSampleCounts; + maxPushConstantsSize = data.maxPushConstantsSize; + minStorageBufferOffsetAlignment = VK.__makeHandle(data.minStorageBufferOffsetAlignment); + minUniformBufferOffsetAlignment = VK.__makeHandle(data.minUniformBufferOffsetAlignment); + nonCoherentAtomSize = VK.__makeHandle(data.nonCoherentAtomSize); + deviceTypeName = switch (deviceType) + { + case 1: "integrated-gpu"; + case 2: "discrete-gpu"; + case 3: "virtual-gpu"; + case 4: "cpu"; + default: "other"; + } + isDiscrete = (deviceType == 2); + supportsPresent = false; + + queueFamilies = []; + var rawQueueFamilies:Dynamic = data.queueFamilies; + if (rawQueueFamilies != null) + { + var length:Int = untyped rawQueueFamilies.length; + for (i in 0...length) + { + var queueFamily = new VKQueueFamilyInfo(untyped rawQueueFamilies[i]); + queueFamilies.push(queueFamily); + if (queueFamily.supportsPresent) + { + supportsPresent = true; + } + } + } + } + + /** + Creates a logical device with one queue from the requested queue family. + If no queue family is provided, Lime selects a graphics-capable family + that can present to the current surface when that data is available. + **/ + public function createDevice(queueFamily:VKQueueFamilyInfo = null, extensions:Array = null):VKDevice + { + if (queueFamily == null) + { + queueFamily = getQueueFamily(true, supportsPresent); + } + + if (extensions == null) + { + extensions = [VK.KHR_SWAPCHAIN_EXTENSION_NAME]; + } + + if (queueFamily == null || instance == null || instance.context == null || !instance.isValid()) + { + return null; + } + + #if (!macro && lime_cffi && lime_vulkan) + var data:Dynamic = NativeCFFI.lime_vk_create_device(instance.context.__windowHandle, instance.handle.high, instance.handle.low, handle.high, + handle.low, queueFamily.index, extensions); + if (data != null) + { + return new VKDevice(this, queueFamily, extensions, data); + } + #end + + return null; + } + + /** + Returns the first queue family that matches the requested capabilities. + **/ + public function getQueueFamily(requireGraphics:Bool = true, requirePresent:Bool = false, requireCompute:Bool = false, + requireTransfer:Bool = false):VKQueueFamilyInfo + { + for (queueFamily in queueFamilies) + { + if (queueFamily.matches(requireGraphics, requirePresent, requireCompute, requireTransfer)) + { + return queueFamily; + } + } + + return null; + } + + public inline function hasQueueFamily(requireGraphics:Bool = true, requirePresent:Bool = false, requireCompute:Bool = false, + requireTransfer:Bool = false):Bool + { + return getQueueFamily(requireGraphics, requirePresent, requireCompute, requireTransfer) != null; + } + + public function getMaxUsableSampleCount(requireDepth:Bool = false, requireStencil:Bool = false):Int + { + var counts = framebufferColorSampleCounts; + if (requireDepth) + { + counts &= framebufferDepthSampleCounts; + } + if (requireStencil) + { + counts &= framebufferStencilSampleCounts; + } + + for (sampleCount in [VK.SAMPLE_COUNT_64_BIT, VK.SAMPLE_COUNT_32_BIT, VK.SAMPLE_COUNT_16_BIT, VK.SAMPLE_COUNT_8_BIT, + VK.SAMPLE_COUNT_4_BIT, VK.SAMPLE_COUNT_2_BIT]) + { + if ((counts & sampleCount) != 0) + { + return sampleCount; + } + } + + return VK.SAMPLE_COUNT_1_BIT; + } + + public function supportsSampleCount(samples:Int, requireDepth:Bool = false, requireStencil:Bool = false):Bool + { + var counts = framebufferColorSampleCounts; + if (requireDepth) + { + counts &= framebufferDepthSampleCounts; + } + if (requireStencil) + { + counts &= framebufferStencilSampleCounts; + } + return (counts & samples) != 0; + } +} diff --git a/src/lime/graphics/vulkan/VKPipeline.hx b/src/lime/graphics/vulkan/VKPipeline.hx new file mode 100644 index 0000000000..20b377ec44 --- /dev/null +++ b/src/lime/graphics/vulkan/VKPipeline.hx @@ -0,0 +1,46 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKPipeline +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var layout(default, null):VKPipelineLayout; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, layout:VKPipelineLayout, handle:Int64) + { + this.device = device; + this.layout = layout; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_pipeline(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKPipelineCache.hx b/src/lime/graphics/vulkan/VKPipelineCache.hx new file mode 100644 index 0000000000..e690940e26 --- /dev/null +++ b/src/lime/graphics/vulkan/VKPipelineCache.hx @@ -0,0 +1,62 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import haxe.io.Bytes; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKPipelineCache +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_pipeline_cache(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function getData():Bytes + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var bytes = Bytes.alloc(0); + if (NativeCFFI.lime_vk_get_pipeline_cache_data(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, bytes)) + { + return bytes; + } + } + #end + + return null; + } +} diff --git a/src/lime/graphics/vulkan/VKPipelineLayout.hx b/src/lime/graphics/vulkan/VKPipelineLayout.hx new file mode 100644 index 0000000000..83c3b77ed2 --- /dev/null +++ b/src/lime/graphics/vulkan/VKPipelineLayout.hx @@ -0,0 +1,44 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKPipelineLayout +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_pipeline_layout(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKQueue.hx b/src/lime/graphics/vulkan/VKQueue.hx new file mode 100644 index 0000000000..a372e78d26 --- /dev/null +++ b/src/lime/graphics/vulkan/VKQueue.hx @@ -0,0 +1,117 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan queue retrieved from a `VKDevice`. +**/ +class VKQueue +{ + public var device(default, null):VKDevice; + public var familyIndex(default, null):Int; + public var handle(default, null):Int64; + public var index(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64, familyIndex:Int, index:Int) + { + this.device = device; + this.handle = handle; + this.familyIndex = familyIndex; + this.index = index; + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + /** + Presents an acquired swapchain image on this queue. + **/ + public function present(swapchain:VKSwapchain, imageIndex:Int, waitSemaphore:VKSemaphore = null):Int + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && swapchain != null && swapchain.isValid()) + { + var waitSemaphoreHandle = (waitSemaphore != null && waitSemaphore.isValid()) ? waitSemaphore.handle : Int64.ofInt(0); + return NativeCFFI.lime_vk_queue_present(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, swapchain.handle.high, swapchain.handle.low, imageIndex, + waitSemaphoreHandle.high, waitSemaphoreHandle.low); + } + #end + + return VK.ERROR_INITIALIZATION_FAILED; + } + + /** + Submits one command buffer to this queue. A fence may be provided to track + completion from the CPU. + **/ + public function submit(commandBuffer:VKCommandBuffer, fence:VKFence = null):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && commandBuffer != null && commandBuffer.isValid()) + { + var fenceHigh = (fence != null && fence.isValid()) ? fence.handle.high : 0; + var fenceLow = (fence != null && fence.isValid()) ? fence.handle.low : 0; + + return NativeCFFI.lime_vk_queue_submit(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, commandBuffer.handle.high, commandBuffer.handle.low, fenceHigh, fenceLow); + } + #end + + return false; + } + + /** + Submits one command buffer with optional acquire/render/present sync. + This preserves the simple `submit(commandBuffer, fence)` path while + exposing the explicit wait/signal pieces renderers need per frame. + **/ + public function submitSynced(commandBuffer:VKCommandBuffer, waitSemaphore:VKSemaphore = null, signalSemaphore:VKSemaphore = null, + fence:VKFence = null, waitStageMask:Int = VK.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT):Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid() && commandBuffer != null && commandBuffer.isValid()) + { + var waitHandle = waitSemaphore != null && waitSemaphore.isValid() ? waitSemaphore.handle : Int64.ofInt(0); + var signalHandle = signalSemaphore != null && signalSemaphore.isValid() ? signalSemaphore.handle : Int64.ofInt(0); + var fenceHandle = fence != null && fence.isValid() ? fence.handle : Int64.ofInt(0); + var state = [waitHandle.high, waitHandle.low, waitStageMask, signalHandle.high, signalHandle.low, fenceHandle.high, fenceHandle.low]; + + return NativeCFFI.lime_vk_queue_submit_synced(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low, commandBuffer.handle.high, commandBuffer.handle.low, state); + } + #end + + return false; + } + + /** + Blocks until this queue has completed all submitted work. + **/ + public function waitIdle():Bool + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + return NativeCFFI.lime_vk_queue_wait_idle(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + } + #end + + return false; + } +} diff --git a/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx b/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx new file mode 100644 index 0000000000..d8df278384 --- /dev/null +++ b/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx @@ -0,0 +1,42 @@ +package lime.graphics.vulkan; + +/** + Describes one queue family on a Vulkan physical device. +**/ +class VKQueueFamilyInfo +{ + public var index(default, null):Int; + public var flags(default, null):Int; + public var queueCount(default, null):Int; + public var timestampValidBits(default, null):Int; + public var supportsGraphics(default, null):Bool; + public var supportsCompute(default, null):Bool; + public var supportsTransfer(default, null):Bool; + public var supportsPresent(default, null):Bool; + + @:allow(lime.graphics.vulkan.VKPhysicalDevice) + private function new(data:Dynamic) + { + index = data.index; + flags = data.flags; + queueCount = data.queueCount; + timestampValidBits = data.timestampValidBits; + supportsGraphics = data.supportsGraphics; + supportsCompute = data.supportsCompute; + supportsTransfer = data.supportsTransfer; + supportsPresent = data.supportsPresent; + } + + /** + Checks whether this queue family satisfies a requested capability set. + **/ + public inline function matches(requireGraphics:Bool = false, requirePresent:Bool = false, requireCompute:Bool = false, + requireTransfer:Bool = false):Bool + { + if (requireGraphics && !supportsGraphics) return false; + if (requirePresent && !supportsPresent) return false; + if (requireCompute && !supportsCompute) return false; + if (requireTransfer && !supportsTransfer) return false; + return true; + } +} diff --git a/src/lime/graphics/vulkan/VKRenderPass.hx b/src/lime/graphics/vulkan/VKRenderPass.hx new file mode 100644 index 0000000000..8a7ddfe95c --- /dev/null +++ b/src/lime/graphics/vulkan/VKRenderPass.hx @@ -0,0 +1,54 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKRenderPass +{ + public var colorFormat(default, null):Int; + public var depthStencilFormat(default, null):Int; + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + public var hasResolve(default, null):Bool; + public var resolveFormat(default, null):Int; + public var samples(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64, colorFormat:Int, depthStencilFormat:Int, samples:Int, resolveFormat:Int) + { + this.device = device; + this.handle = handle; + this.colorFormat = colorFormat; + this.depthStencilFormat = depthStencilFormat; + this.samples = samples; + this.resolveFormat = resolveFormat; + this.hasResolve = resolveFormat != VK.FORMAT_UNDEFINED; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_render_pass(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKRenderer.hx b/src/lime/graphics/vulkan/VKRenderer.hx new file mode 100644 index 0000000000..d3b70e3023 --- /dev/null +++ b/src/lime/graphics/vulkan/VKRenderer.hx @@ -0,0 +1,153 @@ +package lime.graphics.vulkan; + +import lime.graphics.Image; +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFI; +#end +#if (!lime_doc_gen || lime_cffi) +import lime.system.CFFIPointer; +#end + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + Lime's managed Vulkan validation renderer. + + This is useful for smoke tests and samples, but application renderers should + build on `VK` handles such as `VKInstance`, `VKDevice`, and `VKQueue`. +**/ +class VKRenderer +{ + public var info(get, never):String; + public var isValid(get, never):Bool; + public var lastError(get, never):String; + + private var __handle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end; + private var __info:String; + + @:allow(lime.graphics.VulkanRenderContext) + private function new(handle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end) + { + __handle = handle; + __info = ""; + + #if (!macro && lime_cffi) + if (__handle != null) + { + refreshInfo(); + } + #end + } + + public function dispose():Void + { + #if (!macro && lime_cffi) + if (__handle != null) + { + NativeCFFI.lime_vulkan_renderer_destroy(__handle); + __handle = null; + } + #end + } + + public function render(red:Float, green:Float, blue:Float, alpha:Float = 1.0):Bool + { + #if (!macro && lime_cffi) + if (__handle != null) + { + return NativeCFFI.lime_vulkan_renderer_render(__handle, red, green, blue, alpha); + } + #end + + return false; + } + + public function refreshInfo():String + { + #if (!macro && lime_cffi) + if (__handle != null) + { + var value:Dynamic = NativeCFFI.lime_vulkan_renderer_get_info(__handle); + __info = (value != null) ? CFFI.stringValue(value) : ""; + } + #end + + return __info; + } + + public function setOverlayImage(image:Image, x:Int, y:Int):Bool + { + #if (!macro && lime_cffi) + if (__handle != null) + { + if (image == null) + { + return NativeCFFI.lime_vulkan_renderer_clear_overlay(__handle); + } + + if (image.buffer != null && image.width > 0 && image.height > 0) + { + return NativeCFFI.lime_vulkan_renderer_set_overlay(__handle, image.data.toBytes(), image.width, image.height, x, y); + } + } + #end + + return false; + } + + public function clearOverlay():Bool + { + #if (!macro && lime_cffi) + if (__handle != null) + { + return NativeCFFI.lime_vulkan_renderer_clear_overlay(__handle); + } + #end + + return false; + } + + public function resize():Bool + { + #if (!macro && lime_cffi) + if (__handle != null) + { + return NativeCFFI.lime_vulkan_renderer_resize(__handle); + } + #end + + return false; + } + + public static function getLastError():String + { + #if (!macro && lime_cffi) + var value:Dynamic = NativeCFFI.lime_vulkan_renderer_get_last_error(); + if (value != null) + { + return CFFI.stringValue(value); + } + #end + + return ""; + } + + private inline function get_info():String + { + return __info; + } + + private inline function get_isValid():Bool + { + return __handle != null; + } + + private inline function get_lastError():String + { + return getLastError(); + } +} diff --git a/src/lime/graphics/vulkan/VKSampler.hx b/src/lime/graphics/vulkan/VKSampler.hx new file mode 100644 index 0000000000..69504203a1 --- /dev/null +++ b/src/lime/graphics/vulkan/VKSampler.hx @@ -0,0 +1,44 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKSampler +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_sampler(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKSemaphore.hx b/src/lime/graphics/vulkan/VKSemaphore.hx new file mode 100644 index 0000000000..4128be555b --- /dev/null +++ b/src/lime/graphics/vulkan/VKSemaphore.hx @@ -0,0 +1,47 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan semaphore used for GPU/GPU synchronization. +**/ +class VKSemaphore +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_semaphore(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKShaderModule.hx b/src/lime/graphics/vulkan/VKShaderModule.hx new file mode 100644 index 0000000000..4204a32c3a --- /dev/null +++ b/src/lime/graphics/vulkan/VKShaderModule.hx @@ -0,0 +1,44 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +class VKShaderModule +{ + public var device(default, null):VKDevice; + public var handle(default, null):Int64; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64) + { + this.device = device; + this.handle = handle; + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_shader_module(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } +} diff --git a/src/lime/graphics/vulkan/VKSurface.hx b/src/lime/graphics/vulkan/VKSurface.hx new file mode 100644 index 0000000000..6abd8988fb --- /dev/null +++ b/src/lime/graphics/vulkan/VKSurface.hx @@ -0,0 +1,52 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.graphics.VulkanRenderContext; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A lightweight managed `VkSurfaceKHR` wrapper for the current Lime window. +**/ +class VKSurface +{ + public var context(default, null):VulkanRenderContext; + public var instance(default, null):VKInstance; + public var high(default, null):Int; + public var low(default, null):Int; + + @:allow(lime.graphics.vulkan.VKInstance) + private function new(context:VulkanRenderContext, instance:VKInstance, high:Int, low:Int) + { + this.context = context; + this.instance = instance; + this.high = high; + this.low = low; + } + + public function dispose():Void + { + #if (!macro && lime_cffi) + if (context != null && instance != null && instance.isValid() && (high != 0 || low != 0)) + { + NativeCFFI.lime_vk_destroy_surface(context.__windowHandle, instance.handle.high, instance.handle.low, high, low); + high = 0; + low = 0; + } + #end + } + + public inline function isValid():Bool + { + return high != 0 || low != 0; + } + + public inline function toInt64():Int64 + { + return Int64.make(high, low); + } +} diff --git a/src/lime/graphics/vulkan/VKSwapchain.hx b/src/lime/graphics/vulkan/VKSwapchain.hx new file mode 100644 index 0000000000..389c36e58e --- /dev/null +++ b/src/lime/graphics/vulkan/VKSwapchain.hx @@ -0,0 +1,140 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A Vulkan swapchain created for a Lime window surface. +**/ +class VKSwapchain +{ + public var colorSpace(default, null):Int; + public var device(default, null):VKDevice; + public var format(default, null):Int; + public var handle(default, null):Int64; + public var height(default, null):Int; + public var imageCount(default, null):Int; + public var images(default, null):Array; + public var presentMode(default, null):Int; + public var surface(default, null):VKSurface; + public var width(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, surface:VKSurface, data:Dynamic) + { + this.device = device; + this.surface = surface; + handle = VK.__makeHandle(data.handle); + format = data.format; + colorSpace = data.colorSpace; + width = data.width; + height = data.height; + imageCount = data.imageCount; + presentMode = data.presentMode; + images = []; + refreshImages(); + } + + /** + Acquires the next presentable image from the swapchain. + **/ + public function acquireNextImage(semaphore:VKSemaphore = null, fence:VKFence = null, timeout:Int64 = null):VKAcquireResult + { + if (timeout == null) + { + timeout = Int64.make(-1, -1); + } + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var semaphoreHandle = (semaphore != null && semaphore.isValid()) ? semaphore.handle : Int64.ofInt(0); + var fenceHandle = (fence != null && fence.isValid()) ? fence.handle : Int64.ofInt(0); + var data:Dynamic = NativeCFFI.lime_vk_acquire_next_image(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, timeout.high, timeout.low, + semaphoreHandle.high, semaphoreHandle.low, fenceHandle.high, fenceHandle.low); + + if (data != null) + { + return new VKAcquireResult(data.result, data.imageIndex); + } + } + #end + + return new VKAcquireResult(VK.ERROR_INITIALIZATION_FAILED, -1); + } + + public function dispose():Void + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + NativeCFFI.lime_vk_destroy_swapchain(device.instance.context.__windowHandle, device.instance.handle.high, device.instance.handle.low, + device.handle.high, device.handle.low, handle.high, handle.low); + handle = Int64.ofInt(0); + images = []; + imageCount = 0; + } + #end + } + + public inline function get():Int64 + { + return handle; + } + + public inline function isValid():Bool + { + return !VK.__isZero(handle); + } + + public function refreshImages():Array + { + images = []; + imageCount = 0; + + #if (!macro && lime_cffi && lime_vulkan) + if (isValid() && device != null && device.isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_get_swapchain_images(device.instance.context.__windowHandle, device.instance.handle.high, + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low); + + if (data != null) + { + var length:Int = untyped data.length; + for (i in 0...length) + { + images.push(new VKImage(this, VK.__makeHandle(untyped data[i]), i)); + } + imageCount = images.length; + } + } + #end + + return images; + } + + /** + Creates a replacement swapchain using this swapchain as the old handle. + Dispose the old swapchain after any in-flight work has finished. + **/ + public function recreate(width:Int = 0, height:Int = 0, presentMode:Int = -1):VKSwapchain + { + if (presentMode < 0) + { + presentMode = this.presentMode; + } + + if (device == null) + { + return null; + } + + return device.createSwapchain(surface, width, height, presentMode, this); + } +} diff --git a/src/lime/graphics/vulkan/VKUploadRing.hx b/src/lime/graphics/vulkan/VKUploadRing.hx new file mode 100644 index 0000000000..772c7f6933 --- /dev/null +++ b/src/lime/graphics/vulkan/VKUploadRing.hx @@ -0,0 +1,106 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import haxe.io.Bytes; + +/** + A persistently mapped host-visible ring buffer for staging dynamic uploads. +**/ +class VKUploadRing +{ + public var buffer(default, null):VKBuffer; + public var byteCapacity(default, null):Int; + public var device(default, null):VKDevice; + public var frameIndex(default, null):Int = 0; + public var head(default, null):Int = 0; + + public function new(device:VKDevice, byteCapacity:Int, usage:Int = VK.BUFFER_USAGE_TRANSFER_SRC_BIT, + properties:Int = VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT) + { + this.device = device; + this.byteCapacity = byteCapacity; + + if (device != null && byteCapacity > 0) + { + buffer = device.createBufferWithMemory(Int64.ofInt(byteCapacity), usage | VK.BUFFER_USAGE_TRANSFER_SRC_BIT, properties); + if (buffer != null && !buffer.map(Int64.ofInt(0), Int64.ofInt(byteCapacity))) + { + buffer.dispose(true); + buffer = null; + } + } + } + + public function beginFrame(frameIndex:Int):Void + { + this.frameIndex = frameIndex; + head = 0; + } + + public function reserve(byteCount:Int, alignment:Int):VKUploadSlice + { + if (!isValid() || byteCount <= 0) + { + return null; + } + if (alignment <= 0) + { + alignment = 1; + } + + var aligned = __align(head, alignment); + if (aligned + byteCount > byteCapacity) + { + return null; + } + + head = aligned + byteCount; + return new VKUploadSlice(buffer, Int64.ofInt(aligned), byteCount, frameIndex); + } + + public function writeBytes(slice:VKUploadSlice, bytes:Bytes, srcOffset:Int = 0, length:Int = -1):Bool + { + if (slice == null || slice.buffer != buffer || bytes == null) + { + return false; + } + if (length < 0) + { + length = bytes.length - srcOffset; + } + if (length < 0 || length > slice.size) + { + return false; + } + return buffer.writeBytes(bytes, srcOffset, length, slice.offset); + } + + public function flush():Bool + { + return isValid() ? buffer.flush(Int64.ofInt(0), Int64.ofInt(0)) : false; + } + + public function invalidate():Bool + { + return isValid() ? buffer.invalidate(Int64.ofInt(0), Int64.ofInt(0)) : false; + } + + public function dispose():Void + { + if (buffer != null) + { + buffer.dispose(true); + buffer = null; + } + } + + public inline function isValid():Bool + { + return buffer != null && buffer.isValid(); + } + + private inline function __align(value:Int, alignment:Int):Int + { + return Std.int((value + alignment - 1) / alignment) * alignment; + } +} diff --git a/src/lime/graphics/vulkan/VKUploadSlice.hx b/src/lime/graphics/vulkan/VKUploadSlice.hx new file mode 100644 index 0000000000..b0d9b0d8c9 --- /dev/null +++ b/src/lime/graphics/vulkan/VKUploadSlice.hx @@ -0,0 +1,23 @@ +package lime.graphics.vulkan; + +import haxe.Int64; + +/** + A reserved range in a `VKUploadRing`. +**/ +class VKUploadSlice +{ + public var buffer(default, null):VKBuffer; + public var frameIndex(default, null):Int; + public var offset(default, null):Int64; + public var size(default, null):Int; + + @:allow(lime.graphics.vulkan.VKUploadRing) + private function new(buffer:VKBuffer, offset:Int64, size:Int, frameIndex:Int) + { + this.buffer = buffer; + this.offset = offset; + this.size = size; + this.frameIndex = frameIndex; + } +} diff --git a/src/lime/graphics/vulkan/VKVertexAttribute.hx b/src/lime/graphics/vulkan/VKVertexAttribute.hx new file mode 100644 index 0000000000..4a1641c077 --- /dev/null +++ b/src/lime/graphics/vulkan/VKVertexAttribute.hx @@ -0,0 +1,17 @@ +package lime.graphics.vulkan; + +class VKVertexAttribute +{ + public var binding:Int; + public var format:Int; + public var location:Int; + public var offset:Int; + + public function new(location:Int, binding:Int, format:Int, offset:Int) + { + this.location = location; + this.binding = binding; + this.format = format; + this.offset = offset; + } +} diff --git a/src/lime/graphics/vulkan/VKVertexBinding.hx b/src/lime/graphics/vulkan/VKVertexBinding.hx new file mode 100644 index 0000000000..071a35139e --- /dev/null +++ b/src/lime/graphics/vulkan/VKVertexBinding.hx @@ -0,0 +1,15 @@ +package lime.graphics.vulkan; + +class VKVertexBinding +{ + public var binding:Int; + public var inputRate:Int; + public var stride:Int; + + public function new(binding:Int, stride:Int, inputRate:Int = VK.VERTEX_INPUT_RATE_VERTEX) + { + this.binding = binding; + this.stride = stride; + this.inputRate = inputRate; + } +} diff --git a/src/lime/math/Matrix4.hx b/src/lime/math/Matrix4.hx index 4c70f38066..ee479fbb78 100644 --- a/src/lime/math/Matrix4.hx +++ b/src/lime/math/Matrix4.hx @@ -416,7 +416,7 @@ abstract Matrix4(Float32Array) from Float32Array to Float32Array this[12] = 0; this[13] = 0; this[14] = -2 * zFar * zNear / (zFar - zNear); - this[15] = 1; + this[15] = 0; } /** diff --git a/src/lime/media/AudioBuffer.hx b/src/lime/media/AudioBuffer.hx index 8d3756d268..1cf584c5d8 100644 --- a/src/lime/media/AudioBuffer.hx +++ b/src/lime/media/AudioBuffer.hx @@ -70,6 +70,7 @@ class AudioBuffer @:noCompletion private var __srcAudio:#if (js && html5) Audio #else Dynamic #end; @:noCompletion private var __srcBuffer:#if lime_cffi ALBuffer #else Dynamic #end; + @:noCompletion private var __srcBufferContext:Int; @:noCompletion private var __srcCustom:Dynamic; @:noCompletion private var __srcHowl:#if lime_howlerjs Howl #else Dynamic #end; @:noCompletion private var __isDisposed:Bool; @@ -135,7 +136,13 @@ class AudioBuffer } var audioBuffer = new AudioBuffer(); - audioBuffer.src = new Howl({src: [base64String], html5: true, preload: false}); + + #if force_html5_audio + audioBuffer.src = new Howl({src: [base64String], html5: true, preload: true}); + #else + audioBuffer.src = new Howl({src: [base64String], preload: true}); + #end + return audioBuffer; #elseif (lime_cffi && !macro) #if !cs @@ -181,7 +188,12 @@ class AudioBuffer #if (js && html5 && lime_howlerjs) var audioBuffer = new AudioBuffer(); - audioBuffer.src = new Howl({src: ["data:" + __getCodec(bytes) + ";base64," + Base64.encode(bytes)], html5: true, preload: false}); + + #if force_html5_audio + audioBuffer.src = new Howl({src: ["data:" + __getCodec(bytes) + ";base64," + Base64.encode(bytes)], html5: true, preload: true}); + #else + audioBuffer.src = new Howl({src: ["data:" + __getCodec(bytes) + ";base64," + Base64.encode(bytes)], preload: true}); + #end return audioBuffer; #elseif (lime_cffi && !macro) diff --git a/src/lime/media/AudioInput.hx b/src/lime/media/AudioInput.hx new file mode 100644 index 0000000000..17446ff888 --- /dev/null +++ b/src/lime/media/AudioInput.hx @@ -0,0 +1,198 @@ +package lime.media; + +import haxe.io.Bytes; +import lime.app.Event; + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +/** + The `AudioInput` class provides polling-based access to microphone or other + audio capture input. + + `AudioInput` reads raw PCM sample frames into a `Bytes` buffer. Use + `samplesAvailable` to determine how many sample frames can be read without + blocking, then call `read`. + + @see lime.media.AudioInputDevice + @see lime.media.AudioBuffer +**/ +class AudioInput +{ + /** + The backend's default audio input device, or `null` if capture is not + available. + **/ + public static var defaultDevice(get, never):AudioInputDevice; + + /** + The available audio input devices reported by the backend. + **/ + public static var devices(get, never):Array; + + /** + Whether audio input capture is supported by the current backend. + **/ + public static var isSupported(get, never):Bool; + + /** + The number of bits per sample used by this input. + **/ + public var bitsPerSample(default, null):Int; + + /** + The capture buffer size, in sample frames. + **/ + public var bufferSize(default, null):Int; + + /** + The number of capture channels. + **/ + public var channels(default, null):Int; + + /** + The audio input device used by this input. + **/ + public var device(default, null):AudioInputDevice; + + /** + An event that is dispatched if the backend reports that the input device + has disconnected. + **/ + public var onDisconnect = new EventVoid>(); + + /** + Whether this input is currently capturing. + **/ + public var running(default, null):Bool; + + /** + The capture sample rate, in Hz. + **/ + public var sampleRate(default, null):Int; + + /** + The number of sample frames currently available to read. + **/ + public var samplesAvailable(get, never):Int; + + @:noCompletion private var __backend:AudioInputBackend; + @:noCompletion private var __disposed:Bool; + + /** + Creates a new `AudioInput` instance. + + @param device The input device to use. If `null`, the backend default is used. + @param sampleRate The requested capture sample rate, in Hz. + @param channels The requested channel count. + @param bitsPerSample The requested bits per sample. + @param bufferSize The capture buffer size, in sample frames. + **/ + public function new(device:AudioInputDevice = null, sampleRate:Int = 44100, channels:Int = 1, bitsPerSample:Int = 16, bufferSize:Int = 4096) + { + this.device = device != null ? device : defaultDevice; + this.sampleRate = sampleRate > 0 ? sampleRate : 44100; + this.channels = channels; + this.bitsPerSample = bitsPerSample; + this.bufferSize = bufferSize > 0 ? bufferSize : 4096; + running = false; + + __backend = new AudioInputBackend(this); + } + + /** + Releases any resources used by this `AudioInput`. + **/ + public function dispose():Void + { + if (__disposed) + { + return; + } + + stop(); + __backend.dispose(); + __disposed = true; + } + + /** + Reads captured PCM sample frames into `buffer`. + + @param buffer The destination buffer. + @param samples The maximum number of sample frames to read. + @return The number of sample frames actually read. + **/ + public function read(buffer:Bytes, samples:Int):Int + { + if (__disposed) + { + return 0; + } + + return __backend.read(buffer, samples); + } + + /** + Starts audio capture. + + On backends that require asynchronous permission, such as HTML5, + `running` may become true after this method returns. + **/ + public function start():Void + { + if (__disposed || running) + { + return; + } + + running = __backend.start(); + } + + /** + Stops audio capture. + **/ + public function stop():Void + { + if (__disposed) + { + return; + } + + __backend.stop(); + running = false; + } + + @:noCompletion private static function get_defaultDevice():AudioInputDevice + { + return AudioInputBackend.getDefaultDevice(); + } + + @:noCompletion private static function get_devices():Array + { + return AudioInputBackend.getDevices(); + } + + @:noCompletion private static function get_isSupported():Bool + { + return AudioInputBackend.isSupported(); + } + + @:noCompletion private function get_samplesAvailable():Int + { + if (__disposed) + { + return 0; + } + + return __backend.getSamplesAvailable(); + } +} + +#if flash +@:noCompletion private typedef AudioInputBackend = lime._internal.backend.flash.FlashAudioInput; +#elseif (js && html5) +@:noCompletion private typedef AudioInputBackend = lime._internal.backend.html5.HTML5AudioInput; +#else +@:noCompletion private typedef AudioInputBackend = lime._internal.backend.native.NativeAudioInput; +#end diff --git a/src/lime/media/AudioInputDevice.hx b/src/lime/media/AudioInputDevice.hx new file mode 100644 index 0000000000..948fe799a9 --- /dev/null +++ b/src/lime/media/AudioInputDevice.hx @@ -0,0 +1,39 @@ +package lime.media; + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +/** + The `AudioInputDevice` class describes an audio capture device that can be + used with `AudioInput`. + + @see lime.media.AudioInput +**/ +class AudioInputDevice +{ + /** + The backend identifier for this device, when one is available. + **/ + public var id(default, null):String; + + /** + Whether this device is the backend's default audio input device. + **/ + public var isDefault(default, null):Bool; + + /** + The user-visible name of this audio input device. + **/ + public var name(default, null):String; + + /** + Creates a new `AudioInputDevice` instance. + **/ + public function new(name:String = null, id:String = null, isDefault:Bool = false) + { + this.name = name; + this.id = id != null ? id : name; + this.isDefault = isDefault; + } +} diff --git a/src/lime/media/AudioManager.hx b/src/lime/media/AudioManager.hx index 8a085f253d..5001f7ab72 100644 --- a/src/lime/media/AudioManager.hx +++ b/src/lime/media/AudioManager.hx @@ -1,11 +1,16 @@ package lime.media; import haxe.Timer; +#if (lime_cffi && !macro && lime_openal) import lime._internal.backend.native.NativeCFFI; +import lime._internal.backend.native.NativeAudioSource; +#end +#if (!lime_doc_gen || lime_openal) import lime.media.openal.AL; import lime.media.openal.ALC; import lime.media.openal.ALContext; import lime.media.openal.ALDevice; +#end #if (js && html5) import js.Browser; #end @@ -18,6 +23,18 @@ import js.Browser; class AudioManager { public static var context:AudioContext; + @:noCompletion public static var __contextGeneration(default, null):Int = 0; + private static inline var OUTPUT_DEVICE_POLL_TIME:Int = 1000; + #if (!lime_doc_gen || lime_openal) + private static var outputDevice:ALDevice; + #else + private static var outputDevice:Dynamic; + #end + private static var outputDeviceHasDisconnectExt:Bool; + private static var outputDeviceName:String; + private static var outputDevicePreferredName:String; + private static var outputDeviceRecovering:Bool; + private static var outputDeviceTimer:Timer; public static function init(context:AudioContext = null) { @@ -39,12 +56,14 @@ class AudioManager var ctx = alc.createContext(device); alc.makeContextCurrent(ctx); alc.processContext(ctx); + __contextGeneration++; } } #end } AudioManager.context = context; + setupOutputDeviceRecovery(); #if (lime_cffi && !macro && lime_openal && (ios || tvos || mac)) var timer = new Timer(100); @@ -77,6 +96,8 @@ class AudioManager public static function shutdown():Void { #if !lime_doc_gen + stopOutputDeviceRecovery(); + if (context != null && context.type == OPENAL) { var alc = context.openal; @@ -120,4 +141,208 @@ class AudioManager } #end } + + private static function closeOpenALContext():Void + { + #if !lime_doc_gen + if (context == null || context.type != OPENAL) + { + return; + } + + var alc = context.openal; + var currentContext = alc.getCurrentContext(); + + if (currentContext != null) + { + var device = alc.getContextsDevice(currentContext); + alc.makeContextCurrent(null); + alc.destroyContext(currentContext); + + if (device != null) + { + alc.closeDevice(device); + } + } + #end + } + + private static function getCurrentOutputDeviceName():String + { + #if (lime_cffi && !macro && lime_openal) + var name = ALC.getString(null, ALC.DEFAULT_ALL_DEVICES_SPECIFIER); + + if (name == null || name.length == 0) + { + name = ALC.getString(null, ALC.DEFAULT_DEVICE_SPECIFIER); + } + + return name; + #else + return null; + #end + } + + private static function isOutputDeviceConnected():Bool + { + #if (lime_cffi && !macro && lime_openal) + if (outputDevice == null || !outputDeviceHasDisconnectExt) + { + return true; + } + + var connected = ALC.getIntegerv(outputDevice, ALC.CONNECTED, 1); + return connected == null || connected.length == 0 || connected[0] == ALC.TRUE; + #else + return true; + #end + } + + private static function openOpenALContext(deviceName:String = null):Bool + { + #if !lime_doc_gen + if (context == null || context.type != OPENAL) + { + return false; + } + + var alc = context.openal; + var device = alc.openDevice(deviceName); + + if (device == null && deviceName != null) + { + device = alc.openDevice(); + } + + if (device == null) + { + return false; + } + + var currentContext = alc.createContext(device); + + if (currentContext == null) + { + alc.closeDevice(device); + return false; + } + + alc.makeContextCurrent(currentContext); + alc.processContext(currentContext); + __contextGeneration++; + return true; + #else + return false; + #end + } + + private static function recoverOutputDevice(deviceName:String = null):Void + { + #if (lime_cffi && !macro && lime_openal) + if (outputDeviceRecovering || context == null || context.type != OPENAL) + { + return; + } + + outputDeviceRecovering = true; + NativeAudioSource.prepareAudioContextRecovery(); + closeOpenALContext(); + + if (openOpenALContext(deviceName)) + { + refreshOutputDeviceRecovery(); + NativeAudioSource.restoreAudioContextRecovery(); + } + + outputDeviceRecovering = false; + #end + } + + private static function refreshOutputDeviceRecovery():Void + { + #if (lime_cffi && !macro && lime_openal) + if (context == null || context.type != OPENAL) + { + outputDevice = null; + outputDeviceHasDisconnectExt = false; + outputDeviceName = null; + return; + } + + var alc = context.openal; + var currentContext = alc.getCurrentContext(); + outputDevice = currentContext != null ? alc.getContextsDevice(currentContext) : null; + outputDeviceHasDisconnectExt = outputDevice != null && ALC.isExtensionPresent(outputDevice, "ALC_EXT_disconnect"); + outputDeviceName = getCurrentOutputDeviceName(); + #end + } + + private static function setupOutputDeviceRecovery():Void + { + #if (lime_cffi && !macro && lime_openal) + stopOutputDeviceRecovery(); + + if (context == null || context.type != OPENAL) + { + return; + } + + refreshOutputDeviceRecovery(); + + if (!outputDeviceHasDisconnectExt) + { + return; + } + + outputDevicePreferredName = outputDeviceName; + // ALC_EXT_disconnect exposes disconnect state, but not device-change events. + // Polling is kept as the compatibility fallback for that older API. + outputDeviceTimer = new Timer(OUTPUT_DEVICE_POLL_TIME); + outputDeviceTimer.run = updateOutputDeviceRecovery; + #end + } + + private static function stopOutputDeviceRecovery():Void + { + if (outputDeviceTimer != null) + { + outputDeviceTimer.stop(); + outputDeviceTimer = null; + } + + outputDevice = null; + outputDeviceHasDisconnectExt = false; + outputDeviceName = null; + outputDevicePreferredName = null; + outputDeviceRecovering = false; + } + + private static function updateOutputDeviceRecovery():Void + { + #if (lime_cffi && !macro && lime_openal) + if (outputDeviceRecovering || context == null || context.type != OPENAL) + { + return; + } + + if (!isOutputDeviceConnected()) + { + recoverOutputDevice(); + return; + } + + if (outputDevicePreferredName != null && outputDeviceName != outputDevicePreferredName) + { + var currentName = getCurrentOutputDeviceName(); + + if (currentName == outputDevicePreferredName) + { + recoverOutputDevice(outputDevicePreferredName); + return; + } + + outputDeviceName = currentName; + } + #end + } } diff --git a/src/lime/media/OpenALAudioContext.hx b/src/lime/media/OpenALAudioContext.hx index d731f72397..9d7b7d21a7 100644 --- a/src/lime/media/OpenALAudioContext.hx +++ b/src/lime/media/OpenALAudioContext.hx @@ -8,6 +8,7 @@ import lime.media.openal.ALContext; import lime.media.openal.ALDevice; import lime.media.openal.ALSource; import lime.utils.ArrayBufferView; +import haxe.io.Bytes; #if !lime_debug @:fileXml('tags="haxe,release"') @@ -90,6 +91,9 @@ class OpenALAudioContext public var ENUMERATE_ALL_EXT:Int = 1; public var DEFAULT_ALL_DEVICES_SPECIFIER:Int = 0x1012; public var ALL_DEVICES_SPECIFIER:Int = 0x1013; + public var CAPTURE_DEVICE_SPECIFIER:Int = 0x310; + public var CAPTURE_DEFAULT_DEVICE_SPECIFIER:Int = 0x311; + public var CAPTURE_SAMPLES:Int = 0x312; @:noCompletion private function new() {} @@ -403,14 +407,18 @@ class OpenALAudioContext public function getString(param:Int, device:ALDevice = null):String { - if (device == null) + if (device != null) { - return AL.getString(param); + return ALC.getString(device, param); } - else + + if (param == DEFAULT_DEVICE_SPECIFIER || param == DEVICE_SPECIFIER || param == ALC.EXTENSIONS || param == DEFAULT_ALL_DEVICES_SPECIFIER + || param == ALL_DEVICES_SPECIFIER || param == CAPTURE_DEVICE_SPECIFIER || param == CAPTURE_DEFAULT_DEVICE_SPECIFIER) { - return ALC.getString(device, param); + return ALC.getString(cast null, param); } + + return AL.getString(param); } public function isBuffer(buffer:ALBuffer):Bool @@ -423,9 +431,14 @@ class OpenALAudioContext return AL.isEnabled(capability); } - public function isExtensionPresent(extname:String):Bool + public function isExtensionPresent(extname:String, device:ALDevice = null):Bool { - return AL.isExtensionPresent(extname); + if (extname == null) + { + return false; + } + + return device != null ? ALC.isExtensionPresent(device, extname) : AL.isExtensionPresent(extname); } public function isSource(source:ALSource):Bool @@ -587,5 +600,30 @@ class OpenALAudioContext { ALC.suspendContext(context); } + + public function captureOpenDevice(deviceName:String = null, frequency:Int, format:Int, bufferSize:Int):ALDevice + { + return ALC.captureOpenDevice(deviceName, frequency, format, bufferSize); + } + + public function captureCloseDevice(device:ALDevice):Bool + { + return ALC.captureCloseDevice(device); + } + + public function captureStart(device:ALDevice):Void + { + ALC.captureStart(device); + } + + public function captureStop(device:ALDevice):Void + { + ALC.captureStop(device); + } + + public function captureSamples(device:ALDevice, buffer:Bytes, samples:Int):Void + { + ALC.captureSamples(device, buffer, samples); + } } #end diff --git a/src/lime/media/openal/ALC.hx b/src/lime/media/openal/ALC.hx index 4cd4379d21..a897a232a8 100644 --- a/src/lime/media/openal/ALC.hx +++ b/src/lime/media/openal/ALC.hx @@ -4,6 +4,7 @@ package lime.media.openal; import lime._internal.backend.native.NativeCFFI; import lime.system.CFFI; import lime.system.CFFIPointer; +import haxe.io.Bytes; #if !lime_debug @:fileXml('tags="haxe,release"') @@ -33,6 +34,10 @@ class ALC public static inline var ENUMERATE_ALL_EXT:Int = 1; public static inline var DEFAULT_ALL_DEVICES_SPECIFIER:Int = 0x1012; public static inline var ALL_DEVICES_SPECIFIER:Int = 0x1013; + public static inline var CAPTURE_DEVICE_SPECIFIER:Int = 0x310; + public static inline var CAPTURE_DEFAULT_DEVICE_SPECIFIER:Int = 0x311; + public static inline var CAPTURE_SAMPLES:Int = 0x312; + public static inline var CONNECTED:Int = 0x313; public static function closeDevice(device:ALDevice):Bool { @@ -202,5 +207,63 @@ class ALC NativeCFFI.lime_alc_suspend_context(context); #end } + + public static function isExtensionPresent(device:ALDevice, extname:String):Bool + { + if (extname == null) + { + return false; + } + + #if (lime_cffi && lime_openal && !macro) + return NativeCFFI.lime_alc_is_extension_present(device, extname); + #else + return false; + #end + } + + public static function captureOpenDevice(deviceName:String = null, frequency:Int, format:Int, bufferSize:Int):ALDevice + { + #if (lime_cffi && lime_openal && !macro) + var handle = NativeCFFI.lime_alc_capture_open_device(deviceName, frequency, format, bufferSize); + + if (handle != null) + { + return new ALDevice(handle); + } + #end + + return null; + } + + public static function captureCloseDevice(device:ALDevice):Bool + { + #if (lime_cffi && lime_openal && !macro) + return NativeCFFI.lime_alc_capture_close_device(device); + #end + + return false; + } + + public static function captureStart(device:ALDevice):Void + { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_alc_capture_start(device); + #end + } + + public static function captureStop(device:ALDevice):Void + { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_alc_capture_stop(device); + #end + } + + public static function captureSamples(device:ALDevice, buffer:Bytes, samples:Int):Void + { + #if (lime_cffi && lime_openal && !macro) + NativeCFFI.lime_alc_capture_samples(device, buffer, samples); + #end + } } #end diff --git a/src/lime/system/System.hx b/src/lime/system/System.hx index e3a5f7c15a..64dc264dc4 100644 --- a/src/lime/system/System.hx +++ b/src/lime/system/System.hx @@ -627,6 +627,8 @@ class System attributes.resizable = __parseBool(argValue); case "stencil", "stencil-buffer": attributes.context.stencil = __parseBool(argValue); + case "transparent": + attributes.transparent = __parseBool(argValue); // case "title": windowConfig.title = argValue; case "vsync", "vsync-mode": var vsyncMode = __parseVSyncMode(argValue); diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index d616a2e352..49e5b17a95 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -201,6 +201,33 @@ class PlatformTarget // Common functionality used by subclasses + /** + Copies all embedded assets into a temporary directory and sets their + `sourcePath`. This must happen before generating template contexts. + **/ + private function prepareEmbeddedAssets():Void + { + var embedDirectory = Path.combine(targetDirectory, "obj/tmp"); + + for (asset in project.assets) + { + if (asset.type != AssetType.TEMPLATE && asset.embed == true && asset.sourcePath == "") + { + var path = Path.combine(embedDirectory, asset.targetPath); + System.mkdir(Path.directory(path)); + AssetHelper.copyAsset(asset, path); + asset.sourcePath = path; + } + } + } + + /** + Copies all non-embedded assets into the given directories. + @param outputDirectory The root directory for template assets. + @param assetDirectory The root directory for non-template assets. If not + an absolute path, interpreted relative to `outputDirectory`. If null, + defaults to `outputDirectory`. + **/ private function copyProjectAssets(outputDirectory:String, assetDirectory:String = null) { if (assetDirectory == null) @@ -212,29 +239,25 @@ class PlatformTarget assetDirectory = Path.combine(outputDirectory, assetDirectory); } - var embedDirectory = Path.combine(targetDirectory, "obj/tmp"); - for (asset in project.assets) { + var path = Path.combine(assetDirectory, asset.targetPath); + if (asset.type == AssetType.TEMPLATE) { - var path = Path.combine(outputDirectory, asset.targetPath); + path = Path.combine(outputDirectory, asset.targetPath); System.mkdir(Path.directory(path)); AssetHelper.copyAsset(asset, path, project.templateContext); } else if (asset.embed == true) { - if (asset.sourcePath == "") + if (FileSystem.exists(path) && !FileSystem.isDirectory(path)) { - var path = Path.combine(embedDirectory, asset.targetPath); - System.mkdir(Path.directory(path)); - AssetHelper.copyAsset(asset, path); - asset.sourcePath = path; + System.deleteFile(path); } } else { - var path = Path.combine(assetDirectory, asset.targetPath); System.mkdir(Path.directory(path)); AssetHelper.copyAssetIfNewer(asset, path); } diff --git a/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index 876d59d1c3..e535b37f5e 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1984,6 +1984,15 @@ class ProjectXMLParser extends HXProject case "parameters", "title": Reflect.setField(windows[id], name, Std.string(value)); + case "renderer": + var renderType = Std.string(value).toLowerCase(); + Reflect.setField(windows[id], "renderType", renderType); + if (renderType == "vulkan") + { + defines.set("lime-vulkan", ""); + haxedefs.set("lime-vulkan", ""); + } + case "allow-high-dpi": Reflect.setField(windows[id], "allowHighDPI", value == "true"); diff --git a/src/lime/tools/WindowData.hx b/src/lime/tools/WindowData.hx index df74318d29..1f74f090ad 100644 --- a/src/lime/tools/WindowData.hx +++ b/src/lime/tools/WindowData.hx @@ -19,12 +19,14 @@ abstract WindowData({ @:optional var allowHighDPI:Bool; @:optional var alwaysOnTop:Bool; @:optional var antialiasing:Int; + @:optional var renderType:String; @:optional var orientation:Orientation; @:optional var allowShaders:Bool; @:optional var requireShaders:Bool; @:optional var depthBuffer:Bool; @:optional var stencilBuffer:Bool; @:optional var title:String; + @:optional var transparent:Bool; #if (js && html5) @:optional var element:js.html.Element; #end @@ -53,12 +55,14 @@ abstract WindowData({ allowHighDPI: false, alwaysOnTop: false, antialiasing: 0, + renderType: null, orientation: Orientation.AUTO, allowShaders: false, requireShaders: false, depthBuffer: false, stencilBuffer: false, title: "", + transparent: false, #if (js && html5) element: null, #end diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index 4a25da753c..37e5f870b2 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -149,6 +149,7 @@ class Window #end public var textInputEnabled(get, set):Bool; public var title(get, set):String; + public var transparent(default, null):Bool; public var alwaysOnTop(get, set):Bool; public var visible(get, set):Bool; public var width(get, set):Int; @@ -236,207 +237,2257 @@ class Window __resizable = Reflect.hasField(__attributes, "resizable") ? __attributes.resizable : false; __maximized = Reflect.hasField(__attributes, "maximized") ? __attributes.maximized : false; __minimized = Reflect.hasField(__attributes, "minimized") ? __attributes.minimized : false; + transparent = Reflect.hasField(__attributes, "transparent") ? __attributes.transparent : false; id = -1; __backend = new WindowBackend(this); + if (id != -1 && application != null) application.__seedFrameConfiguration(__attributes); #if windows var mappings = [ - "8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2", - "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", - "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", - "6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", - "0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows", - "6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", - "88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows", - "4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows", - "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows", - "4c05c405000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows", - "4c05cc09000000000000504944564944,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows", - "4c05a00b000000000000504944564944,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Windows", - "6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13", - "4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows", - "00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows", - "00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows", - "28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7", - "ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9", - "8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2", - "8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7", - "10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5", - "79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows", - "4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows", - "d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows", - "a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows", - "4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2", - "83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows", - - "10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2", - "49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows", - - "4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows", - "0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows", - "79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2", - "79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows", - - "2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows", - "300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows", - "10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows", - "63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8", - "02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8", - "ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11", - "341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows", - "c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1", - "100801e5000000000000504944564944,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Windows", - "79000600000000000000504944564944,NGS Phantom,a:b2,b:b3,y:b1,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows" + "03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows", + "03000000fa190000918d000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows", + "03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows", + "03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows", + "03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows", + "03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows", + "03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows", + "03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows", + "03000000c82d00001930000000000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows", + "03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows", + "03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows", + "03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows", + "03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows", + "03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows", + "03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows", + "03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows", + "03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows", + "03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000960000000000000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows", + "03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00001130000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001330000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001260000000000000,8BitDo Ultimate 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001b30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001c30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001d30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows", + "03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows", + "03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows", + "030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows", + "030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows", + "03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows", + "0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000020500000913000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000373500000710000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000373500004610000000000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000190e00000110000000000000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Windows", + "03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows", + "03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000006a0e00001140000000000000,Atari CX Controller,a:b0,leftx:a0,lefty:a1,platform:Windows", + "03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows", + "03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows", + "03000000380800001889000000000000,AtGames Legends Gamer Pro,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b14,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows", + "030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows", + "030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows", + "030000008a3500000402000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows", + "03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows", + "030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows", + "030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "030000000d0500000308000000000000,Belkin Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows", + "03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000790000000700000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows", + "03000000808300000300000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows", + "03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows", + "03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows", + "030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows", + "03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows", + "030000005a1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows", + "030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows", + "030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows", + "030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows", + "030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows", + "030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows", + "030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000151a00006222000000000000,Dual Plus PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows", + "030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows", + "03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows", + "030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows", + "03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows", + "03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows", + "03000095090000010000000000000000,Elecom JC-U609,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows", + "0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows", + "03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,platform:Windows", + "030000006e0500000520000000000000,Elecom P301U PlayStation Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows", + "03000000250900000218000000000000,Elecom PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows", + "030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows", + "030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows", + "030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows", + "030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows", + "030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows", + "030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows", + "03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000062000001801000000000000,EMS TrioLinker Plus II,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Windows", + "03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows", + "03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows", + "03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows", + "0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows", + "03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows", + "03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows", + "03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows", + "03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows", + "03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows", + "03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows", + "0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows", + "03000000790000004618000000000000,GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows", + "03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows", + "03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows", + "03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000373500002210000000000000,GameSir G7 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000ac0500001a06000000000000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000373500000410000000000000,GameSir T4 Kaleid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000373500009410000000000000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows", + "030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows", + "030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows", + "030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows", + "03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000008a2e0000dd10000000000000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Windows", + "030000008a2e0000df10000000000000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Windows", + "030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows", + "030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows", + "03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00008800000000000000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows", + "030000000d0f00008700000000000000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows", + "030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows", + "030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows", + "030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows", + "030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows", + "030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000000d0f00000202000000000000,Horipad O Nintendo Switch 2 Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows", + "030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows", + "03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows", + "03000000790000004e95000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows", + "03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows", + "03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows", + "03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows", + "03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows", + "03000000f00300008d04000000000000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:-a2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:+a5,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows", + "03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows", + "03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,platform:Windows", + "03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows", + "03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows", + "03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows", + "03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows", + "03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows", + "03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows", + "03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows", + "03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows", + "030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows", + "030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows", + "03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows", + "03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000008b0100002301000000000000,Joytech JS-112,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a2,lefty:a3,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a0,righty:a1,start:b9,x:b0,y:b1,platform:Windows", + "03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows", + "03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows", + "03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows", + "03000000c4ac00001c80000000000000,KidzPlay Adventure PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows", + "03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows", + "030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows", + "030000006d04000011c2000000000000,Logitech WingMan Cordless,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows", + "030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows", + "03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows", + "030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "030000008f0e00001330000000000000,Mayflash Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows", + "03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000004318000000000000,Mayflash GameCube Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows", + "0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000242f0000f400000000000000,Mayflash N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows", + "03000000242f0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows", + "03000000790000007918000000000000,Mayflash N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows", + "030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows", + "03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows", + "03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows", + "0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows", + "030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows", + "030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows", + "030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows", + "030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows", + "03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows", + "03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows", + "03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows", + "03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows", + "03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows", + "03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows", + "03000000c9110000f055000000000000,Nacon GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000c21100000791000000000000,Nacon GC101 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000006b140000010c000000000000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows", + "0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows", + "03000000921200004b46000000000000,NES Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows", + "03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows", + "03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows", + "03000000790000004518000000000000,NEXiLUX GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows", + "03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows", + "03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows", + "03000000ec110000e1a7000000000000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows", + "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000007e0500007320000000000000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Windows", + "030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows", + "030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows", + "03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows", + "03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows", + "030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000004b120000014d000000000000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c00000288000000000000,Nyko Airflo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows", + "030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows", + "0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows", + "03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows", + "03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000d62000002640000000000000,PowerA OPS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000d62000003340000000000000,PowerA OPS Pro Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows", + "030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows", + "030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows", + "03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows", + "030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows", + "03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows", + "03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows", + "03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows", + "03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows", + "03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows", + "03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows", + "03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows", + "030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows", + "030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows", + "030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows", + "030000009b280000d000000000000000,Raphnet Dreamcast Adapter,a:b1,b:b0,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,lefttrigger:+a5,leftx:a0,lefty:a1,righttrigger:+a2,start:b3,x:b5,y:b4,platform:Windows", + "030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows", + "030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows", + "030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows", + "030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows", + "030000009b2800003c00000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows", + "030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows", + "030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows", + "030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows", + "030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows", + "030000009b2800004400000000000000,Raphnet PlayStation Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows", + "030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows", + "030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows", + "030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows", + "030000009b2800002600000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800002e00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800002f00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows", + "030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows", + "030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows", + "03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "0300000032150000a602000000000000,Razer Huntsman V3 Pro,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows", + "03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000921200004547000000000000,Retro Bit Sega Genesis Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows", + "03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows", + "03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows", + "03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows", + "03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows", + "03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows", + "0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows", + "0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows", + "03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows", + "030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000830500000052000000000000,Rockfire CosmoVoyager,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b10,leftshoulder:b6,lefttrigger:b7,misc1:b11,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,platform:Windows", + "03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows", + "030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows", + "030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows", + "03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows", + "03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows", + "03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows", + "03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows", + "03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows", + "03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows", + "03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,x:b2,y:b3,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Windows", + "03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows", + "03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows", + "03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows", + "03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows", + "030000009d0d00001130000000000000,Sanwa PlayStation Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows", + "03000000630600000201000000000000,Sanwa Virtua Grip,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,x:b0,y:b1,platform:Windows", + "03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows", + "03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,leftshoulder:b6,lefttrigger:b7,back:b8,start:b9,x:b3,y:b0,platform:Windows", + "03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows", + "0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows", + "0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows", + "03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows", + "03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows", + "030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows", + "03000000632500002705000000000000,ShanWan Q36,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows", + "03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows", + "03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows", + "030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows", + "03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows", + "030000008f0e00000910000000000000,Sony DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows", + "03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows", + "03000000d9040000160f000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000fe1400002a23000000000000,Sony PlayStation Adapter,a:b0,b:b1,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,x:b2,y:b3,platform:Windows", + "030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows", + "03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "030000004c0500003713000000000000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows", + "03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows", + "03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows", + "030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows", + "03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows", + "03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows", + "030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows", + "03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows", + "03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows", + "030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows", + "03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows", + "03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows", + "03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows", + "03000000790000001c18000000000000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000790000002601000000000000,TGZ Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows", + "030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000004f0400000ed0000000000000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows", + "030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows", + "030000004f04000003d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:-a3,leftx:a0,lefty:a1,paddle1:b6,paddle2:b7,rightshoulder:b5,rightstick:b11,righttrigger:-a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000004f04000008d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000004f04000009d0000000000000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000011000000200000000000000,ThundeRobot G30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000571d00002100000000000000,Tomee NES Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows", + "03000000571d00002000000000000000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000d60600002a00000000000000,Trust 850F,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows", + "030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000005f1400002a01000000000000,Trust Predator GM1200,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows", + "03000000580400000a10000000000000,Trust Sight Fighter,a:b0,b:b1,x:b3,y:b4,back:b5,start:b2,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b8,righttrigger:b9,platform:Windows", + "030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows", + "03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows", + "03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows", + "03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows", + "030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows", + "03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows", + "03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows", + "03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows", + "03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows", + "03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows", + "03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows", + "03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows", + "0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows", + "03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows", + "0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", + "03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,platform:Windows", + "03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000a102000000000000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows", + "03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows", + "030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows", + "030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows", + "03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows", + "03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows", + "03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows", + "03000000c0160000e105000000000000,XinMo Dual Arcade,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows", + "030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows", + "030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows", + "03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows", + "03000000073500000400000000000000,Zenaim Arcade Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows", + "03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows", + "03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows", ]; Gamepad.addMappings(mappings); #elseif mac var mappings = [ - "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", - "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", - "6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", - "6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", - "6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", - "4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X", - "4c05000000000000c405000000000000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X", - "4c05000000000000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X", - "5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", - "891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X", - "4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X", - "8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2", - "0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7", - "79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X", - "4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - - "AD1B00000000000001F9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", - "050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X", - - "83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X", - "bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X", - "79000000000000001100000000000000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a3,lefty:a4,platform:Mac OS X", - "5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4", - - "5e04000000000000ea02000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "5e04000000000000e002000000000000,Xbox Wireless Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b10,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X", - "79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X", - "2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X", - "351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X", - "b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X", - "81170000000000007e05000000000000,Sega Saturn,x:b0,a:b2,b:b4,y:b6,start:b13,dpleft:b15,dpdown:b16,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,lefttrigger:b10,rightshoulder:b9,righttrigger:a4,righttrigger:b11,leftx:a0,lefty:a2,platform:Mac OS X", - "10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X", - "d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7", - "0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4" + "030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000c82d00001930000000000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00001930000000020000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00001930000001000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Mac OS X", + "03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X", + "03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X", + "03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00002690000000010000,8BitDo NEOGEO,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000960000000000000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00003028000000010000,8Bitdo SFC30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001d30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001330000000020000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X", + "0300000008100000e501000019040000,Anbernic Handheld,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X", + "03000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X", + "03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X", + "030000006a0e00001140000001000000,Atari CX Wireless Controller,a:b0,leftx:a0,lefty:a1,platform:Mac OS X", + "03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X", + "03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X", + "03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X", + "030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X", + "030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X", + "03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X", + "03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000501d00009e61000001000000,CoreOrbits GamerPad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X", + "030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Mac OS X", + "03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000790000004618000000010000,GameCube Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X", + "03000000ac0500001a06000002020000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000373500000411000023000000,GameSir X4A Xbox Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X", + "03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X", + "030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X", + "030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00008800000000010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00008700000000010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X", + "030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000000d0f0000f600000000010000,Horipad Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X", + "03000000790000004e95000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X", + "03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X", + "03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X", + "03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X", + "030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000006d0400001ac2000004000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000008f0e00001330000011010000,Mayflash Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X", + "03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X", + "03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X", + "0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X", + "0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X", + "03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X", + "03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X", + "03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X", + "030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X", + "030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X", + "030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X", + "030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X", + "030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X", + "03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000853200008906000000010000,Nacon Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000921200004b46000003020000,NES Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X", + "030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000ec110000e1a7000001010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "030000007e0500006920000001010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Mac OS X", + "030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X", + "050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X", + "030000007e0500007320000001010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Mac OS X", + "030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X", + "030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X", + "030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X", + "0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000100800000300000006010000,PlayStation Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X", + "03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X", + "030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X", + "030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X", + "030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000222c00000225000000010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X", + "030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X", + "030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X", + "030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X", + "0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000632500002305000000010000,Redragon Saturn,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000921200004547000000020000,Retro Bit Sega Genesis Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X", + "03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X", + "0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X", + "03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X", + "030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X", + "030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X", + "03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X", + "03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X", + "03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X", + "03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X", + "030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X", + "0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X", + "030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X", + "030000004c050000da0c000000010000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000004c0500003713000000010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X", + "03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X", + "03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X", + "05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X", + "050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X", + "03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X", + "03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X", + "03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X", + "03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X", + "03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X", + "030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X", + "030000004f0400000ed0000000020000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X", + "03000000571d00002100000021000000,Tomee NES Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X", + "03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000571d00002000000021000000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X", + "03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X", + "030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X", + "03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X", + "03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000c0160000e105000000040000,Ultimate Atari Fight Stick,a:b2,b:b4,back:b18,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b8,righttrigger:b10,start:b16,x:b0,y:b6,platform:Mac OS X", + "03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X", + "030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X", + "050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X", + "050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X", + "030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4~,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X", + "030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X", + "030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X", + "03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X", + "030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "030000005e040000220b000021050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X", + "03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", + "03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X", ]; Gamepad.addMappings(mappings); #elseif linux var mappings = [ - "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", - "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", - "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", - "030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "030000006d04000016c2000011010000,Logitech F310 Gamepad (DInput),x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux", - "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", - "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00001930000011010000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux", + "05000000c82d00001930000001000000,8BitDo 64,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux", + "03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux", + "03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Linux", + "03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000a20000000020000,8BitDo M30 Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux", + "03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00006928000011010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux", + "05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux", + "05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux", + "03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00000960000011010000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux", + "03000000c82d00000060000011010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux", + "030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00000631000010010000,8BitDo Ultimate,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00000631000014010000,8BitDo Ultimate,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00000760000011010000,8BitDo Ultimate,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c82d00001130000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001230000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001330000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000a31000014010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux", + "05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux", + "03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux", + "05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux", + "03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux", + "05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux", + "05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux", + "0300000008100000e501000001010000,Anbernic Handheld,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux", + "03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux", + "03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux", + "03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux", + "05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux", + "05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux", + "03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000006a0e00001140000010010000,Atari CX Controller,a:b0,leftx:a0,lefty:a1,platform:Linux", + "03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux", + "03000000503200000110000011010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux", + "05000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux", + "05000000503200000110000044010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux", + "05000000503200000110000046010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux", + "03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux", + "03000000503200000210000011010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux", + "05000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux", + "05000000503200000210000045010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux", + "05000000503200000210000046010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux", + "05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux", + "030000008a3500000201000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000008a3500000202000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000000d0500000308000010010000,Belkin Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux", + "05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000d81d00000b00000010010000,Buffalo BSGP1601,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Linux", + "03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux", + "030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux", + "03000000632500007a05000001020000,Cosmic Byte Ares Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux", + "03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux", + "03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux", + "030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux", + "030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux", + "03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000defa000001c0000000000000,Flydigi Vader 5 Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,misc2:b12,misc3:b13,misc4:b14,misc5:b19,paddle1:b15,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux", + "19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "03000000373500000b10000019010000,GameSir Cyclone 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000373500000410000044010000,GameSir T4 Kaleid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000373500009410000010010000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000f025000021c1000010010000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000f0250000c283000010010000,Gioteck VX2 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux", + "190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux", + "190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,platform:Linux", + "03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000001010000,GPD Win Max 2 6800U Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux", + "030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux", + "030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux", + "06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux", + "03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000000d0f00005001000009040000,Hori Fighting Commander Octa Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux", + "030000000d0f00008800000011010000,Hori Fighting Stick mini 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00008700000011010000,Hori Fighting Stick mini 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux", + "030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux", + "030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux", + "030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f0000ab01000011010000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000000d0f00009601000091000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000000d0f0000f600000001000000,Horipad Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000341a000005f7000010010000,HuiJia GameCube Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux", + "05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux", + "03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux", + "03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux", + "03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000f00300008d04000000010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux", + "03000000d80400004aea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux", + "03000000d80400004bea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux", + "030000008a2e0000d910000011010000,icedragon.io STAC2 Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux", + "030000008a2e0000e910000011010000,icedragon.io STAC2 Dance Pad,a:b8,b:b9,back:b12,x:b10,y:b11,platform:Linux", + "030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux", + "050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux", + "03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux", + "03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux", + "03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux", + "03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Linux", + "03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux", + "0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000300f00001101000010010000,Jess Tech Colour Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux", + "03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux", + "03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux", + "050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux", + "030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux", + "050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux", + "03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux", + "03000000314100001935000000010000,LeadJoy Xeno Plus,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a4,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d04000019c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux", + "030000006d04000011c2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux", + "05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux", + "03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000120c00000500000000010000,Manta DualShock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "030000008f0e00001330000010010000,Mayflash Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux", + "03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux", + "0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux", + "0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux", + "03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux", + "03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux", + "03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux", + "03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux", + "030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux", + "030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux", + "030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux", + "030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux", + "030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux", + "030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux", + "030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux", + "030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b000014050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000017050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux", + "03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux", + "05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux", + "05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux", + "03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux", + "030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux", + "030000006b1400000906000014010000,Nacon Asymmetric PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "0300000085320000030c000011010000,Nacon GC100,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000853200000706000012010000,Nacon GC100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006b140000010c000010010000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "05000000853200000503000000010000,Nacon MGX Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "0300000085320000160d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux", + "03000000790000004518000010010000,NEXiLUX GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux", + "060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux", + "03000000790000004618000010010000,Nintendo GameCube Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux", + "03000000ec110000e1a7000010010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000007e0500006920000011010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Linux", + "060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux", + "060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux", + "060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux", + "050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux", + "030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux", + "030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux", + "050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux", + "050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux", + "05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux", + "050000005a1d00000218000003000000,Nokia GC 5000,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux", + "030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux", + "050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux", + "050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux", + "030000007e0500001e20000011810000,NSO Sega Genesis Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,platform:Linux", + "030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux", + "050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux", + "050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux", + "03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux", + "05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux", + "030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "03000000451300000830000010010000,Nyko CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux", + "19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux", + "05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux", + "05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux", + "05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux", + "03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux", + "03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux", + "03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000250900000017000010010000,PS SS N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux", + "03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux", + "03000000120c0000160e000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", + "030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", - "030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux", - "050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", - "030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux", - "050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux", - "030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux", - "030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7", - "03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", - "03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux", - "03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux", - "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux", - "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5", - "030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2", - "030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2", - "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", - "030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux", - "030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux", - "030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4", - "030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7", - "030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7", - "0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux", - "0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux", - "030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1", - "030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2", - "03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5", - "030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", - "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux", - "03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", - "060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux", - "050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux", - "03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a3,rightx:a1,righty:a4", - "03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13", - "05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2", - "05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2", - "030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux", - "03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1", - "050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16", - "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2", - "030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1", - "030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7", - "03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux", - "030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux", - "03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux", - "03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux", - "03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux", - "03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux", - "03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux", - "030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3", - "030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux", - "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7", - "05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1", - - "03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1", - "030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5", - - "03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5", - "03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7", - "03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5", - "05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7", - - "030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux", - "030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3", - - "030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4", - "03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:a2,righttrigger:a5", - - "05000000a00500003232000001000000,8Bitdo Zero GamePad,platform:Linux,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1", - "030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,platform:Linux", - "03000000100800000300000010010000,USB Gamepad,platform:Linux,a:b2,b:b1,x:b3,y:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5", - "05000000ac0500003232000001000000,VR-BOX,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5", - - "03000000780000000600000010010000,Microntek USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1" + "030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", + "050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", + "050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", + "060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux", + "030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "030000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000004c050000f20d000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "050000004c050000f20d000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux", + "03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux", + "03000000222c00000225000011010000,Qanba Dragon Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000222c00000025000011010000,Qanba Dragon Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick PS5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux", + "03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux", + "030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux", + "030000009b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux", + "030000009b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux", + "03000000401700007f05000001010000,Raphnet GC and N64 Adapter,a:b5,b:b3,back:b8,dpdown:b10,dpleft:b12,dpright:b11,dpup:b9,leftshoulder:b6,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:-a5,rightx:a2,righty:a3,start:b1,x:b4,y:b2,platform:Linux", + "030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux", + "030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux", + "030000009b2800003c00000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux", + "030000009b2800006100000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux", + "030000009b2800006300000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux", + "030000009b2800006400000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux", + "030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux", + "030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux", + "03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux", + "03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux", + "0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux", + "190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux", + "0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux", + "00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux", + "03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux", + "030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Linux", + "03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux", + "03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux", + "03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux", + "03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux", + "03000000a30600000d5f000010010000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux", + "03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux", + "03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux", + "03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux", + "03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux", + "03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux", + "03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux", + "05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux", + "03000000952e00004b43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux", + "03000000952e00004d43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux", + "03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux", + "03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux", + "03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux", + "03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux", + "03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000632500002605000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000632500007505000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000bc2000000055000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "03000000250900000500000000010000,SmartJoy PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux", + "030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000790000002601000011010000,SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux", + "050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "03000000666600006706000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux", + "03000000d9040000160f000000010000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "030000004c050000da0c000011010000,Sony PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux", + "03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux", + "030000004c0500003713000011010000,Sony PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux", + "030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a2,righttrigger:a3,platform:Linux", + "050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux", + "03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux", + "030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux", + "03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux", + "0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux", + "030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux", + "03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux", + "03000000ba2200000701000001010000,Technology Innovation PlayStation Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux", + "03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux", + "03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux", + "030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux", + "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux", + "030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux", + "030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux", + "030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux", + "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux", + "030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux", + "030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux", + "03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux", + "03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux", + "03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux", + "030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux", + "03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux", + "03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux", + "03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux", + "030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux", + "06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", + "03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux", + "03000000100800000100000010010000,Twin PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux", + "03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux", + "03000000790000000600000007010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux", + "03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux", + "03000000de2800000112000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "03000000de2800000112000011010000,Valve Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux", + "03000000de2800000211000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "03000000de2800000211000011010000,Valve Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux", + "03000000de2800004211000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "03000000de2800004211000011010000,Valve Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux", + "03000000de280000fc11000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "05000000de2800000212000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "05000000de2800000511000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "05000000de2800000611000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux", + "03000000de2800000512000010010000,Valve Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux", + "03000000de2800000512000011010000,Valve Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux", + "03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux", + "03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux", + "05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux", + "05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux", + "030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000002010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000047010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400008e02000072050000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux", + "030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux", + "030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux", + "030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux", + "030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "050000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000200b000017050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000200b000023050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000220b000017050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000dd02000003020000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000ea02000017050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux", + "060000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + "05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux", + "03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux", + "030000005e0400008e02000020010000,XInput Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux", + "03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000120c0000182e000011010000,Zeroplus PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux", + "03000000790000002201000011010000,ZhiXu GuliKit D,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux", + ]; + Gamepad.addMappings(mappings); + #elseif android + var mappings = [ + "38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android", + "64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android", + "64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android", + "33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android", + "34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android", + "38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android", + "38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android", + "32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android", + "38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android", + "64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android", + "66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android", + "66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android", + "38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android", + "61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android", + "62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android", + "33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android", + "38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android", + "05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android", + "38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android", + "32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android", + "38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "61333362366131643730353063616330,8BitDo Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android", + "38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android", + "61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android", + "05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android", + "38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android", + "38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android", + "33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android", + "38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android", + "05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android", + "63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android", + "32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android", + "4c696e757820342e31392e3137322077,Anbernic Handheld,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android", + "35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,platform:Android", + "32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4f64696e20436f6e74726f6c6c657200,AYN Odin,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b14,dpright:b13,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:+a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android", + "4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android", + "30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android", + "05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "476f6f676c65204c4c43205374616469,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "5374616469614e3848532d6532633400,Google Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android", + "05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android", + "66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android", + "65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b18,platform:Android", + "31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "30306539356238653637313730656134,Horipad Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android", + "48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android", + "62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android", + "31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android", + "5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android", + "0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android", + "5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android", + "64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android", + "532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android", + "65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android", + "33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android", + "35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android", + "4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android", + "38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "39373064396565646338333134303131,Joy-Con (R),a:b1,b:b2,back:b5,leftstick:b8,leftx:a1~,lefty:a0,start:b6,x:b0,y:b3,platform:Android", + "4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android", + "64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "33373336396634316434323337666361,Logitech RumblePad 2,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android", + "416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android", + "6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android", + "436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android", + "65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android", + "37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android", + "4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android", + "535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android", + "30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android", + "39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android", + "31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android", + "37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android", + "64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b9,x:b2,y:b3,platform:Android", + "33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android", + "30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android", + "32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android", + "050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android", + "31316661666466633938376335383661,Nintendo Switch Pro Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,start:b6,x:b3,y:b2,platform:Android", + "34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android", + "36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android", + "4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android", + "534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android", + "050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android", + "050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android", + "37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android", + "4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android", + "506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android", + "61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android", + "32666633663735353234363064386132,PS2 Controller,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android", + "050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android", + "050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android", + "050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android", + "31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android", + "31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android", + "37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android", + "050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android", + "050000004c050000e60c0000fffe3f80,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b2,y:b17,platform:Android", + "050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android", + "37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android", + "61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android", + "64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android", + "36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android", + "5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android", + "32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android", + "36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android", + "526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android", + "61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android", + "526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "64633735616665613536653363336132,Retroid Pocket,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b19,paddle2:b20,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,platform:Android", + "37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android", + "5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android", + "526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android", + "64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android", + "37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android", + "36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android", + "32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android", + "38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android", + "61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android", + "30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android", + "66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android", + "66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android", + "62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android", + "38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android", + "5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android", + "5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android", + "62653335326261303663356263626339,Sony PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android", + "536f6e7920496e746572616374697665,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "576972656c65737320436f6e74726f6c,Sony PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android", + "63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android", + "0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android", + "35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android", + "33313930373536613937326534303931,Taito Egret II Mini Control Panel,a:b25,b:b23,back:b27,guide:b30,leftx:a0,lefty:a1,rightshoulder:b21,righttrigger:b22,start:b28,x:b29,y:b24,platform:Android", + "54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android", + "38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android", + "050000004f0400000ed00000fffe3f00,Thrustmaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android", + "05000000de2800000511000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android", + "05000000de2800000611000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android", + "30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android", + "33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android", + "050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android", + "050000005e040000e00200000ffe3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android", + "050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android", + "050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android", + "050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android", + "35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "65316262316265373335666131623538,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android", + "050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android", ]; Gamepad.addMappings(mappings); #elseif (ios || tvos) var mappings = [ + "05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", + "05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", + "05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", + "05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,", + "05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,", + "05000000ac05000004000000a8986d04,8BitDo Micro,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,", + "05000000ac05000004000000fd216d04,8BitDo Pro 2,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,", + "05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,", + "05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,", + "050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", "4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,", "4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,", + "050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,", + "050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,", + "050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,", + "050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,", + "050000007e050000072000000f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,", + "050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,", + "050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,", + "050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,", + "05000000ac050000040000008e586d04,PlayStation VR2 Sense Controller (L),+leftx:+a3,+lefty:+a1,-leftx:+a2,-lefty:+a4,back:b2,leftstick:b4,lefttrigger:+a7,paddle2:b3,x:b0,y:b1,", + "05000000ac050000040000000eb86d04,PlayStation VR2 Sense Controller (R),+rightx:+a3,+righty:+a1,-rightx:+a2,-righty:+a4,a:b0,b:b1,paddle1:b3,rightstick:b4,righttrigger:+a7,start:b2,", + "050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,", + "050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,", + "050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,", + "05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,", + "05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,", + "05000000de2800000511000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,", + "05000000de2800000611000001000000,Valve Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,", + "050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", + "050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", + "050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,", "4d466947616d65706164030000000000,MFi Apple TV Remote,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,", ]; diff --git a/src/lime/ui/WindowAttributes.hx b/src/lime/ui/WindowAttributes.hx index 5568cd6448..fbf59dffe1 100644 --- a/src/lime/ui/WindowAttributes.hx +++ b/src/lime/ui/WindowAttributes.hx @@ -40,6 +40,7 @@ typedef WindowAttributes = @:optional public var parameters:Dynamic; @:optional public var resizable:Bool; @:optional public var skipTaskbar:Bool; + @:optional public var transparent:Bool; @:optional public var utility:Bool; @:optional public var popupMenu:Bool; @:optional public var tooltip:Bool; diff --git a/templates/android/template/app/src/main/AndroidManifest.xml b/templates/android/template/app/src/main/AndroidManifest.xml index ed3640a1f5..c435998b5d 100644 --- a/templates/android/template/app/src/main/AndroidManifest.xml +++ b/templates/android/template/app/src/main/AndroidManifest.xml @@ -1,7 +1,11 @@ + ::if ANDROID_VULKAN:: + + ::else:: + ::end:: ::foreach ANDROID_PERMISSIONS:: diff --git a/templates/cpp/static/BuildMain.xml b/templates/cpp/static/BuildMain.xml index dd135172ce..33c486449b 100644 --- a/templates/cpp/static/BuildMain.xml +++ b/templates/cpp/static/BuildMain.xml @@ -17,6 +17,7 @@ + ::foreach ndlls:: diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index 422fbcb030..66c445d16f 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -49,6 +49,7 @@ import ::APP_MAIN::; parameters: ::parameters::, resizable: ::resizable::, title: "::title::", + transparent: ::transparent::, width: ::width::, x: ::x::, y: ::y::, @@ -62,7 +63,7 @@ import ::APP_MAIN::; depth: ::depthBuffer::, hardware: ::hardware::, stencil: ::stencilBuffer::, - type: null, + type: ::if renderType::"::renderType::"::else::null::end::, vsync: ::vsync:: }; diff --git a/templates/html5/output.js b/templates/html5/output.js index e04a257441..21ba89df30 100644 --- a/templates/html5/output.js +++ b/templates/html5/output.js @@ -48,3 +48,18 @@ if (typeof define === "function" && define.__amd) { define.amd = define.__amd; delete define.__amd; } + +if (typeof self !== "undefined" && !self.constructor.name.includes("Worker")) { + window.addEventListener ("touchmove", function (event) { event.preventDefault (); }, { capture: false, passive: false }); + if (typeof window.devicePixelRatio != 'undefined' && window.devicePixelRatio > 2) { + var meta = document.getElementById ("viewport"); + meta.setAttribute ('content', 'width=device-width, initial-scale=' + (2 / window.devicePixelRatio) + ', user-scalable=no'); + } + + window.addEventListener ("load", function () { + const content = document.getElementById(::if LIB_OPENFL::"openfl-content"::else::"content"::end::); + if (content && content.childElementCount === 0) { + lime.embed ("::APP_FILE::", content, ::WIN_WIDTH::, ::WIN_HEIGHT::); + } + }); +} diff --git a/templates/html5/template/index.html b/templates/html5/template/index.html index daac92480a..3719de96f3 100755 --- a/templates/html5/template/index.html +++ b/templates/html5/template/index.html @@ -16,14 +16,6 @@ ::end::::end:: - -
- - - \ No newline at end of file + diff --git a/templates/ios/template/{{app.file}}.xcodeproj/project.pbxproj b/templates/ios/template/{{app.file}}.xcodeproj/project.pbxproj index 001a200690..58b6be5022 100644 --- a/templates/ios/template/{{app.file}}.xcodeproj/project.pbxproj +++ b/templates/ios/template/{{app.file}}.xcodeproj/project.pbxproj @@ -214,6 +214,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 0920; TargetAttributes = { 1D6058900D05DD3D006BFB54 = { @@ -272,23 +273,39 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = ::CURRENT_ARCHS::; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ::if (OBJC_ARC):: CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ::end:: + CURRENT_PROJECT_VERSION = "::APP_BUILD_NUMBER::"; + INFOPLIST_KEY_CFBundleDisplayName = "::APP_TITLE::"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; + MARKETING_VERSION = "::APP_VERSION::"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "::config.ios.identity::"; ::if (IOS_PROVISIONING_PROFILE)::PROVISIONING_PROFILE = "::IOS_PROVISIONING_PROFILE::";::end:: COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -306,6 +323,7 @@ IPHONEOS_DEPLOYMENT_TARGET = ::DEPLOYMENT::; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; TARGETED_DEVICE_FAMILY = "::TARGET_DEVICES::"; ::THUMB_SUPPORT:: VALID_ARCHS = "::VALID_ARCHS::"; @@ -317,23 +335,39 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = ::CURRENT_ARCHS::; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ::if (OBJC_ARC):: CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ::end:: + CURRENT_PROJECT_VERSION = "::APP_BUILD_NUMBER::"; + INFOPLIST_KEY_CFBundleDisplayName = "::APP_TITLE::"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; + MARKETING_VERSION = "::APP_VERSION::"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "::config.ios.identity::"; ::if (IOS_PROVISIONING_PROFILE)::PROVISIONING_PROFILE = "::IOS_PROVISIONING_PROFILE::";::end:: /* COMPRESS_PNG_FILES = NO; */ COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -346,6 +380,8 @@ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; /* PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES; */ SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "::TARGET_DEVICES::"; ::THUMB_SUPPORT:: VALID_ARCHS = "::VALID_ARCHS::"; @@ -356,6 +392,7 @@ 1D6058940D05DD3E006BFB54 /* Debug */ = {/* Build configuration list for PBXNativeTarget "::APP_TITLE::" */ isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ::if (IOS_LAUNCH_STORYBOARD == null)::ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;::end:: CODE_SIGN_ENTITLEMENTS = "::APP_FILE::/::APP_FILE::.entitlements"; @@ -407,6 +444,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "::APP_PACKAGE::"; PRODUCT_NAME = "$(TARGET_NAME)"; + INFOPLIST_KEY_CFBundleDisplayName = "::APP_TITLE::"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -460,6 +498,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "::APP_PACKAGE::"; PRODUCT_NAME = "$(TARGET_NAME)"; + INFOPLIST_KEY_CFBundleDisplayName = "::APP_TITLE::"; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/templates/windows/resource/ApplicationMain.rc b/templates/windows/resource/ApplicationMain.rc index 2d12ca8ef6..2b36d4781f 100644 --- a/templates/windows/resource/ApplicationMain.rc +++ b/templates/windows/resource/ApplicationMain.rc @@ -1,5 +1,7 @@ #include "winres.h" +::if (HAS_ICON)::IDI_ICON1 ICON "ApplicationMain.ico"::end:: + LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK VS_VERSION_INFO VERSIONINFO diff --git a/tests/unit/src/TestMain.hx b/tests/unit/src/TestMain.hx index 6978eb8d6c..e5f15d054e 100644 --- a/tests/unit/src/TestMain.hx +++ b/tests/unit/src/TestMain.hx @@ -7,6 +7,7 @@ class TestMain extends Application { super(); var runner = new Runner(); + runner.addCase(new app.EventTest()); runner.addCase(new utils.ArrayBufferTest()); runner.addCase(new utils.UInt8ArrayTest()); runner.addCase(new utils.UInt16ArrayTest()); @@ -15,4 +16,4 @@ class TestMain extends Application { Report.create(runner); runner.run(); } -} \ No newline at end of file +} diff --git a/tests/unit/src/app/EventTest.hx b/tests/unit/src/app/EventTest.hx new file mode 100644 index 0000000000..87d7c07f0c --- /dev/null +++ b/tests/unit/src/app/EventTest.hx @@ -0,0 +1,68 @@ +package app; + +import lime.app.Event; +import lime.system.System; +import utest.Assert; +import utest.Test; + +class EventTest extends Test +{ + public function new() + { + super(); + } + + public function testTimestampUsesDispatchTime():Void + { + var event = new EventVoid>(); + var observed = -1; + var before = System.getTimer(); + + event.add(function(_) + { + observed = event.timestamp; + }); + + event.dispatch(1); + var after = System.getTimer(); + + Assert.isTrue(observed >= before); + Assert.isTrue(observed <= after); + } + + public function testExplicitTimestampIsVisible():Void + { + var event = new EventVoid>(); + var observed = -1; + + event.add(function(_) + { + observed = event.timestamp; + }); + + @:privateAccess event.__dispatchWithTimestamp(1234, 1); + Assert.equals(1234, observed); + } + + public function testNestedDispatchRestoresTimestamp():Void + { + var event = new EventVoid>(); + var timestamps:Array = []; + var nested = false; + + event.add(function(_) + { + timestamps.push(event.timestamp); + + if (!nested) + { + nested = true; + @:privateAccess event.__dispatchWithTimestamp(200, 2); + Assert.equals(100, event.timestamp); + } + }); + + @:privateAccess event.__dispatchWithTimestamp(100, 1); + Assert.same([100, 200], timestamps); + } +} diff --git a/tests/vulkan-smoke/Assets/shaders/cube.frag.spv b/tests/vulkan-smoke/Assets/shaders/cube.frag.spv new file mode 100644 index 0000000000..f55655e156 Binary files /dev/null and b/tests/vulkan-smoke/Assets/shaders/cube.frag.spv differ diff --git a/tests/vulkan-smoke/Assets/shaders/cube.vert.spv b/tests/vulkan-smoke/Assets/shaders/cube.vert.spv new file mode 100644 index 0000000000..6021a00526 Binary files /dev/null and b/tests/vulkan-smoke/Assets/shaders/cube.vert.spv differ diff --git a/tests/vulkan-smoke/Assets/shaders/quad.frag.spv b/tests/vulkan-smoke/Assets/shaders/quad.frag.spv new file mode 100644 index 0000000000..5d26e006e4 Binary files /dev/null and b/tests/vulkan-smoke/Assets/shaders/quad.frag.spv differ diff --git a/tests/vulkan-smoke/Assets/shaders/quad.vert.spv b/tests/vulkan-smoke/Assets/shaders/quad.vert.spv new file mode 100644 index 0000000000..50c4bd2594 Binary files /dev/null and b/tests/vulkan-smoke/Assets/shaders/quad.vert.spv differ diff --git a/tests/vulkan-smoke/Source/Main.hx b/tests/vulkan-smoke/Source/Main.hx new file mode 100644 index 0000000000..fd63e61ba6 --- /dev/null +++ b/tests/vulkan-smoke/Source/Main.hx @@ -0,0 +1,976 @@ +package; + +import haxe.Int64; +import haxe.Timer; +import haxe.io.Bytes; +import lime.app.Application; +import lime.graphics.RenderContext; +import lime.graphics.RenderContextType; +import lime.graphics.VulkanRenderContext; +import lime.graphics.vulkan.VK; +import lime.graphics.vulkan.VKBuffer; +import lime.graphics.vulkan.VKCommandBuffer; +import lime.graphics.vulkan.VKCommandPool; +import lime.graphics.vulkan.VKDescriptorPool; +import lime.graphics.vulkan.VKDescriptorPoolSize; +import lime.graphics.vulkan.VKDescriptorSet; +import lime.graphics.vulkan.VKDescriptorSetLayout; +import lime.graphics.vulkan.VKDescriptorSetLayoutBinding; +import lime.graphics.vulkan.VKDevice; +import lime.graphics.vulkan.VKFence; +import lime.graphics.vulkan.VKFramebuffer; +import lime.graphics.vulkan.VKGraphicsPipelineInfo; +import lime.graphics.vulkan.VKImage; +import lime.graphics.vulkan.VKImageView; +import lime.graphics.vulkan.VKInstance; +import lime.graphics.vulkan.VKPhysicalDevice; +import lime.graphics.vulkan.VKPipeline; +import lime.graphics.vulkan.VKPipelineLayout; +import lime.graphics.vulkan.VKQueueFamilyInfo; +import lime.graphics.vulkan.VKRenderPass; +import lime.graphics.vulkan.VKSampler; +import lime.graphics.vulkan.VKSemaphore; +import lime.graphics.vulkan.VKShaderModule; +import lime.graphics.vulkan.VKSurface; +import lime.graphics.vulkan.VKSwapchain; +import lime.graphics.vulkan.VKVertexAttribute; +import lime.graphics.vulkan.VKVertexBinding; +import lime.system.System; +import lime.utils.Assets; + +class Main extends Application +{ + private static inline var DEPTH_FORMAT = VK.FORMAT_D32_SFLOAT; + private static inline var OFFSCREEN_FORMAT = VK.FORMAT_R8G8B8A8_UNORM; + private static inline var OFFSCREEN_SIZE = 256; + private static inline var REQUESTED_MSAA_SAMPLES = VK.SAMPLE_COUNT_4_BIT; + + private var colorImage:VKImage; + private var colorView:VKImageView; + private var commandBuffer:VKCommandBuffer; + private var commandPool:VKCommandPool; + private var cubeDescriptorSet:VKDescriptorSet; + private var cubeDescriptorSetLayout:VKDescriptorSetLayout; + private var cubeFragmentShader:VKShaderModule; + private var cubeIndexBuffer:VKBuffer; + private var cubePipeline:VKPipeline; + private var cubePipelineLayout:VKPipelineLayout; + private var cubeVertexBuffer:VKBuffer; + private var cubeVertexShader:VKShaderModule; + private var depthImage:VKImage; + private var depthView:VKImageView; + private var descriptorPool:VKDescriptorPool; + private var device:VKDevice; + private var fence:VKFence; + private var finished:Bool; + private var framebuffers:Array = []; + private var imageAvailable:VKSemaphore; + private var imageViews:Array = []; + private var instance:VKInstance; + private var offscreenDescriptorSet:VKDescriptorSet; + private var offscreenDescriptorSetLayout:VKDescriptorSetLayout; + private var offscreenFramebuffer:VKFramebuffer; + private var offscreenImage:VKImage; + private var offscreenPipeline:VKPipeline; + private var offscreenPipelineLayout:VKPipelineLayout; + private var offscreenRenderPass:VKRenderPass; + private var offscreenSampler:VKSampler; + private var offscreenView:VKImageView; + private var physicalDevice:VKPhysicalDevice; + private var preloadComplete:Bool; + private var quadFragmentShader:VKShaderModule; + private var quadIndexBuffer:VKBuffer; + private var quadVertexBuffer:VKBuffer; + private var quadVertexShader:VKShaderModule; + private var queueFamily:VKQueueFamilyInfo; + private var renderFinished:VKSemaphore; + private var renderPass:VKRenderPass; + private var msaaSamples:Int = VK.SAMPLE_COUNT_1_BIT; + private var sourceTextureImage:VKImage; + private var sourceTextureSampler:VKSampler; + private var sourceTextureView:VKImageView; + private var surface:VKSurface; + private var swapchain:VKSwapchain; + private var uniformBuffer:VKBuffer; + private var windowCreated:Bool; + + public function new() + { + super(); + } + + override public function onWindowCreate():Void + { + super.onWindowCreate(); + + if (window == null) + { + fail("Missing primary window"); + return; + } + + if (window.context == null || window.context.type != RenderContextType.VULKAN || window.context.vulkan == null) + { + fail("Primary window was not created with a Vulkan context"); + return; + } + + windowCreated = true; + tryCreateRenderer(); + } + + override public function onPreloadComplete():Void + { + super.onPreloadComplete(); + + preloadComplete = true; + tryCreateRenderer(); + } + + override public function onWindowResize(width:Int, height:Int):Void + { + super.onWindowResize(width, height); + + if (!finished && device != null && device.isValid() && width > 0 && height > 0) + { + recreateSwapchain(width, height); + } + } + + override public function render(context:RenderContext):Void + { + super.render(context); + + if (finished || device == null) + { + return; + } + + if (!drawFrame()) + { + return; + } + + finished = true; + Timer.delay(complete, 50); + } + + private function createRenderer(context:VulkanRenderContext):Void + { + var extensions = context.getInstanceExtensions(); + if (extensions == null || extensions.length == 0) + { + fail("No Vulkan instance extensions were reported"); + return; + } + + var procAddr = context.getInstanceProcAddr(); + if (!isNonZero(procAddr)) + { + fail("vkGetInstanceProcAddr was not available"); + return; + } + + instance = VK.createInstance(context, "LimeVulkanSmoke"); + if (instance == null || !instance.isValid()) + { + fail("Failed to create Vulkan instance: " + VK.getLastError()); + return; + } + + surface = instance.createSurface(); + if (surface == null || !surface.isValid()) + { + fail("Failed to create Vulkan surface"); + return; + } + + physicalDevice = instance.pickPhysicalDevice(surface); + if (physicalDevice == null || !physicalDevice.hasQueueFamily(true, true)) + { + fail("No present-capable graphics queue family was found"); + return; + } + msaaSamples = physicalDevice.supportsSampleCount(REQUESTED_MSAA_SAMPLES, true) ? REQUESTED_MSAA_SAMPLES : VK.SAMPLE_COUNT_1_BIT; + + queueFamily = physicalDevice.getQueueFamily(true, true); + device = physicalDevice.createDevice(queueFamily); + if (device == null || !device.isValid() || device.graphicsQueue == null || !device.graphicsQueue.isValid()) + { + fail("Failed to create Vulkan logical device: " + VK.getLastError()); + return; + } + + commandPool = device.createCommandPool(queueFamily); + commandBuffer = commandPool != null ? commandPool.allocateCommandBuffer() : null; + imageAvailable = device.createSemaphore(); + renderFinished = device.createSemaphore(); + fence = device.createFence(true); + + if (commandPool == null || commandBuffer == null || imageAvailable == null || renderFinished == null || fence == null) + { + fail("Failed to create Vulkan frame synchronization resources: " + VK.getLastError()); + return; + } + + swapchain = device.createSwapchain(surface, window.width, window.height); + if (swapchain == null || !swapchain.isValid() || swapchain.images.length == 0) + { + fail("Failed to create Vulkan swapchain: " + VK.getLastError()); + return; + } + + if (!createSourceTexture() || !createGeometry() || !createDescriptorLayouts() || !createOffscreenPass() || !createOnscreenPass()) + { + return; + } + } + + private function tryCreateRenderer():Void + { + if (device != null || !windowCreated || !preloadComplete || window == null || window.context == null || window.context.vulkan == null) + { + return; + } + + createRenderer(window.context.vulkan); + } + + private function createSourceTexture():Bool + { + sourceTextureImage = device.createImage(2, 2, OFFSCREEN_FORMAT, VK.IMAGE_USAGE_TRANSFER_DST_BIT | VK.IMAGE_USAGE_SAMPLED_BIT); + if (sourceTextureImage == null || sourceTextureImage.allocateMemory(VK.MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == null) + { + fail("Failed to create Vulkan texture image: " + VK.getLastError()); + return false; + } + + var pixels = Bytes.alloc(16); + var values = [ + 0xFF, 0x90, 0x20, 0xFF, + 0x10, 0xD8, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x20, 0x40, 0xFF, 0xFF + ]; + for (i in 0...values.length) + { + pixels.set(i, values[i]); + } + + var staging = device.createStagingBuffer(Int64.ofInt(pixels.length), pixels); + if (staging == null) + { + fail("Failed to create Vulkan texture staging buffer: " + VK.getLastError()); + return false; + } + + if (!commandBuffer.reset() || !commandBuffer.begin(VK.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + || !commandBuffer.pipelineBarrierImage(sourceTextureImage, VK.IMAGE_LAYOUT_UNDEFINED, VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK.PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK.PIPELINE_STAGE_TRANSFER_BIT, 0, VK.ACCESS_TRANSFER_WRITE_BIT, VK.IMAGE_ASPECT_COLOR_BIT) + || !commandBuffer.copyBufferToImage(staging, sourceTextureImage, 2, 2) + || !commandBuffer.pipelineBarrierImage(sourceTextureImage, VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK.PIPELINE_STAGE_TRANSFER_BIT, VK.PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK.ACCESS_TRANSFER_WRITE_BIT, VK.ACCESS_SHADER_READ_BIT, + VK.IMAGE_ASPECT_COLOR_BIT) + || !commandBuffer.end()) + { + staging.dispose(true); + fail("Failed to record Vulkan texture upload commands: " + VK.getLastError()); + return false; + } + + if (!fence.waitForever() || !fence.reset() || !device.graphicsQueue.submit(commandBuffer, fence) || !fence.waitForever()) + { + staging.dispose(true); + fail("Failed to submit Vulkan texture upload: " + VK.getLastError()); + return false; + } + + staging.dispose(true); + + sourceTextureView = sourceTextureImage.createView(OFFSCREEN_FORMAT); + sourceTextureSampler = device.createSampler(VK.FILTER_NEAREST, VK.SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK.SAMPLER_MIPMAP_MODE_NEAREST); + + if (sourceTextureView == null || sourceTextureSampler == null) + { + fail("Failed to create Vulkan texture view/sampler: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createGeometry():Bool + { + if (!createQuadGeometry() || !createCubeGeometry()) + { + return false; + } + + uniformBuffer = device.createUniformBuffer(Int64.ofInt(64), + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (uniformBuffer == null) + { + fail("Failed to create Vulkan uniform buffer: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createQuadGeometry():Bool + { + var vertices = Bytes.alloc(4 * 32); + var data = [ + -0.72, -0.72, 0.0, 1.0, 1.0, 1.0, 1.0, 0.86, + 0.72, -0.72, 1.0, 1.0, 1.0, 1.0, 1.0, 0.86, + 0.72, 0.72, 1.0, 0.0, 1.0, 1.0, 1.0, 0.86, + -0.72, 0.72, 0.0, 0.0, 1.0, 1.0, 1.0, 0.86 + ]; + for (i in 0...data.length) + { + vertices.setFloat(i * 4, data[i]); + } + + var indices = Bytes.alloc(6 * 2); + var indexData = [0, 1, 2, 2, 3, 0]; + for (i in 0...indexData.length) + { + indices.setUInt16(i * 2, indexData[i]); + } + + quadVertexBuffer = device.createVertexBuffer(Int64.ofInt(vertices.length), + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT, vertices); + quadIndexBuffer = device.createIndexBuffer(Int64.ofInt(indices.length), + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT, indices); + + if (quadVertexBuffer == null || quadIndexBuffer == null) + { + fail("Failed to create Vulkan quad buffers: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createCubeGeometry():Bool + { + var vertexData = [ + -1.0, -1.0, 1.0, 0.0, 1.0, 1.0, 0.85, 0.55, 1.0, + 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.85, 0.55, 1.0, + 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.85, 0.55, 1.0, + -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.85, 0.55, 1.0, + 1.0, -1.0, -1.0, 0.0, 1.0, 0.55, 0.8, 1.0, 1.0, + -1.0, -1.0, -1.0, 1.0, 1.0, 0.55, 0.8, 1.0, 1.0, + -1.0, 1.0, -1.0, 1.0, 0.0, 0.55, 0.8, 1.0, 1.0, + 1.0, 1.0, -1.0, 0.0, 0.0, 0.55, 0.8, 1.0, 1.0, + -1.0, -1.0, -1.0, 0.0, 1.0, 0.75, 1.0, 0.65, 1.0, + -1.0, -1.0, 1.0, 1.0, 1.0, 0.75, 1.0, 0.65, 1.0, + -1.0, 1.0, 1.0, 1.0, 0.0, 0.75, 1.0, 0.65, 1.0, + -1.0, 1.0, -1.0, 0.0, 0.0, 0.75, 1.0, 0.65, 1.0, + 1.0, -1.0, 1.0, 0.0, 1.0, 1.0, 0.75, 0.6, 1.0, + 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.75, 0.6, 1.0, + 1.0, 1.0, -1.0, 1.0, 0.0, 1.0, 0.75, 0.6, 1.0, + 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.75, 0.6, 1.0, + -1.0, 1.0, 1.0, 0.0, 1.0, 0.65, 0.95, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 0.65, 0.95, 1.0, 1.0, + 1.0, 1.0, -1.0, 1.0, 0.0, 0.65, 0.95, 1.0, 1.0, + -1.0, 1.0, -1.0, 0.0, 0.0, 0.65, 0.95, 1.0, 1.0, + -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.65, 0.75, 1.0, + 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.65, 0.75, 1.0, + 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, 0.65, 0.75, 1.0, + -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.65, 0.75, 1.0 + ]; + + var indexData = [ + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4, + 8, 9, 10, 10, 11, 8, + 12, 13, 14, 14, 15, 12, + 16, 17, 18, 18, 19, 16, + 20, 21, 22, 22, 23, 20 + ]; + + var vertices = Bytes.alloc(vertexData.length * 4); + for (i in 0...vertexData.length) + { + vertices.setFloat(i * 4, vertexData[i]); + } + + var indices = Bytes.alloc(indexData.length * 2); + for (i in 0...indexData.length) + { + indices.setUInt16(i * 2, indexData[i]); + } + + cubeVertexBuffer = device.createVertexBuffer(Int64.ofInt(vertices.length), + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT, vertices); + cubeIndexBuffer = device.createIndexBuffer(Int64.ofInt(indices.length), + VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT, indices); + + if (cubeVertexBuffer == null || cubeIndexBuffer == null) + { + fail("Failed to create Vulkan cube buffers: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createDescriptorLayouts():Bool + { + offscreenDescriptorSetLayout = device.createDescriptorSetLayout([ + new VKDescriptorSetLayoutBinding(0, VK.DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK.SHADER_STAGE_FRAGMENT_BIT) + ]); + cubeDescriptorSetLayout = device.createDescriptorSetLayout([ + new VKDescriptorSetLayoutBinding(0, VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK.SHADER_STAGE_VERTEX_BIT), + new VKDescriptorSetLayoutBinding(1, VK.DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK.SHADER_STAGE_FRAGMENT_BIT) + ]); + descriptorPool = device.createDescriptorPool(2, [ + new VKDescriptorPoolSize(VK.DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2), + new VKDescriptorPoolSize(VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) + ]); + + if (offscreenDescriptorSetLayout == null || cubeDescriptorSetLayout == null || descriptorPool == null) + { + fail("Failed to create Vulkan descriptor layouts: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createOffscreenPass():Bool + { + offscreenRenderPass = device.createRenderPass(OFFSCREEN_FORMAT, VK.FORMAT_UNDEFINED, VK.SAMPLE_COUNT_1_BIT, + VK.ATTACHMENT_LOAD_OP_CLEAR, VK.ATTACHMENT_STORE_OP_STORE, VK.IMAGE_LAYOUT_UNDEFINED, + VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + offscreenImage = device.createImage(OFFSCREEN_SIZE, OFFSCREEN_SIZE, OFFSCREEN_FORMAT, + VK.IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK.IMAGE_USAGE_SAMPLED_BIT | VK.IMAGE_USAGE_TRANSFER_SRC_BIT); + + if (offscreenRenderPass == null || offscreenImage == null || offscreenImage.allocateMemory(VK.MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == null) + { + fail("Failed to create Vulkan offscreen render target: " + VK.getLastError()); + return false; + } + + offscreenView = offscreenImage.createView(OFFSCREEN_FORMAT); + offscreenSampler = device.createSampler(VK.FILTER_LINEAR, VK.SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK.SAMPLER_MIPMAP_MODE_LINEAR); + offscreenFramebuffer = offscreenView != null ? device.createFramebuffer(offscreenRenderPass, [offscreenView], OFFSCREEN_SIZE, OFFSCREEN_SIZE) : null; + + offscreenDescriptorSet = descriptorPool.allocate(offscreenDescriptorSetLayout); + offscreenPipelineLayout = device.createPipelineLayout([offscreenDescriptorSetLayout]); + quadVertexShader = device.createShaderModule(Assets.getBytes("Assets/shaders/quad.vert.spv")); + quadFragmentShader = device.createShaderModule(Assets.getBytes("Assets/shaders/quad.frag.spv")); + + if (offscreenView == null || offscreenSampler == null || offscreenFramebuffer == null || offscreenDescriptorSet == null + || offscreenPipelineLayout == null || quadVertexShader == null || quadFragmentShader == null + || !offscreenDescriptorSet.updateImage(0, sourceTextureView, sourceTextureSampler)) + { + fail("Failed to create Vulkan offscreen pipeline resources: " + VK.getLastError()); + return false; + } + + var info = new VKGraphicsPipelineInfo(); + info.blend = true; + info.cullMode = VK.CULL_MODE_NONE; + info.vertexBindings.push(new VKVertexBinding(0, 32, VK.VERTEX_INPUT_RATE_VERTEX)); + info.vertexAttributes.push(new VKVertexAttribute(0, 0, VK.FORMAT_R32G32_SFLOAT, 0)); + info.vertexAttributes.push(new VKVertexAttribute(1, 0, VK.FORMAT_R32G32_SFLOAT, 8)); + info.vertexAttributes.push(new VKVertexAttribute(2, 0, VK.FORMAT_R32G32B32A32_SFLOAT, 16)); + + offscreenPipeline = device.createGraphicsPipeline(offscreenRenderPass, offscreenPipelineLayout, quadVertexShader, quadFragmentShader, info); + if (offscreenPipeline == null) + { + fail("Failed to create Vulkan offscreen graphics pipeline: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createOnscreenPass():Bool + { + if (msaaSamples != VK.SAMPLE_COUNT_1_BIT) + { + renderPass = device.createRenderPass(swapchain.format, DEPTH_FORMAT, msaaSamples, + VK.ATTACHMENT_LOAD_OP_CLEAR, VK.ATTACHMENT_STORE_OP_DONT_CARE, VK.IMAGE_LAYOUT_UNDEFINED, + VK.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK.IMAGE_LAYOUT_UNDEFINED, + VK.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK.ATTACHMENT_LOAD_OP_CLEAR, + VK.ATTACHMENT_STORE_OP_DONT_CARE, swapchain.format, VK.ATTACHMENT_LOAD_OP_DONT_CARE, + VK.ATTACHMENT_STORE_OP_STORE, VK.IMAGE_LAYOUT_UNDEFINED, VK.IMAGE_LAYOUT_PRESENT_SRC_KHR); + } + else + { + renderPass = device.createRenderPass(swapchain.format, DEPTH_FORMAT, VK.SAMPLE_COUNT_1_BIT, + VK.ATTACHMENT_LOAD_OP_CLEAR, VK.ATTACHMENT_STORE_OP_STORE, VK.IMAGE_LAYOUT_UNDEFINED, VK.IMAGE_LAYOUT_PRESENT_SRC_KHR); + } + + if (renderPass == null || !createColorResources() || !createDepthResources() || !createFramebuffers()) + { + fail("Failed to create Vulkan onscreen render pass resources: " + VK.getLastError()); + return false; + } + + cubeDescriptorSet = descriptorPool.allocate(cubeDescriptorSetLayout); + cubePipelineLayout = device.createPipelineLayout([cubeDescriptorSetLayout]); + cubeVertexShader = device.createShaderModule(Assets.getBytes("Assets/shaders/cube.vert.spv")); + cubeFragmentShader = device.createShaderModule(Assets.getBytes("Assets/shaders/cube.frag.spv")); + + if (cubeDescriptorSet == null || cubePipelineLayout == null || cubeVertexShader == null || cubeFragmentShader == null + || !cubeDescriptorSet.updateBuffer(0, uniformBuffer, 64) || !cubeDescriptorSet.updateImage(1, offscreenView, offscreenSampler)) + { + fail("Failed to create Vulkan cube descriptor resources: " + VK.getLastError()); + return false; + } + + var info = new VKGraphicsPipelineInfo(); + info.depthTest = true; + info.depthWrite = true; + info.depthCompareOp = VK.COMPARE_OP_LESS; + info.cullMode = VK.CULL_MODE_BACK_BIT; + info.frontFace = VK.FRONT_FACE_CLOCKWISE; + info.rasterizationSamples = msaaSamples; + info.vertexBindings.push(new VKVertexBinding(0, 36, VK.VERTEX_INPUT_RATE_VERTEX)); + info.vertexAttributes.push(new VKVertexAttribute(0, 0, VK.FORMAT_R32G32B32_SFLOAT, 0)); + info.vertexAttributes.push(new VKVertexAttribute(1, 0, VK.FORMAT_R32G32_SFLOAT, 12)); + info.vertexAttributes.push(new VKVertexAttribute(2, 0, VK.FORMAT_R32G32B32A32_SFLOAT, 20)); + + cubePipeline = device.createGraphicsPipeline(renderPass, cubePipelineLayout, cubeVertexShader, cubeFragmentShader, info); + if (cubePipeline == null) + { + fail("Failed to create Vulkan cube graphics pipeline: " + VK.getLastError()); + return false; + } + + return true; + } + + private function createColorResources():Bool + { + disposeColorResources(); + + if (msaaSamples == VK.SAMPLE_COUNT_1_BIT) + { + return true; + } + + colorImage = device.createImage(swapchain.width, swapchain.height, swapchain.format, + VK.IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK.IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, 1, 1, 1, VK.IMAGE_TYPE_2D, + VK.IMAGE_TILING_OPTIMAL, msaaSamples); + if (colorImage == null || colorImage.allocateMemory(VK.MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == null) + { + return false; + } + + colorView = colorImage.createView(swapchain.format); + return colorView != null; + } + + private function createDepthResources():Bool + { + disposeDepthResources(); + + depthImage = device.createImage(swapchain.width, swapchain.height, DEPTH_FORMAT, VK.IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + 1, 1, 1, VK.IMAGE_TYPE_2D, VK.IMAGE_TILING_OPTIMAL, msaaSamples); + if (depthImage == null || depthImage.allocateMemory(VK.MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == null) + { + return false; + } + + depthView = depthImage.createView(DEPTH_FORMAT, VK.IMAGE_ASPECT_DEPTH_BIT); + return depthView != null; + } + + private function createFramebuffers():Bool + { + disposeSwapchainFramebuffers(); + + for (image in swapchain.images) + { + var imageView = image.createView(swapchain.format); + if (imageView == null) + { + fail("Failed to create Vulkan swapchain image view: " + VK.getLastError()); + return false; + } + + var attachments = msaaSamples != VK.SAMPLE_COUNT_1_BIT ? [colorView, depthView, imageView] : [imageView, depthView]; + var framebuffer = device.createFramebuffer(renderPass, attachments, swapchain.width, swapchain.height); + if (framebuffer == null) + { + imageView.dispose(); + fail("Failed to create Vulkan framebuffer: " + VK.getLastError()); + return false; + } + + imageViews.push(imageView); + framebuffers.push(framebuffer); + } + + return true; + } + + private function drawFrame():Bool + { + if (!fence.waitForever()) + { + fail("Failed to wait for Vulkan frame fence: " + VK.getLastError()); + return false; + } + + var acquired = swapchain.acquireNextImage(imageAvailable); + if (acquired.result == VK.ERROR_OUT_OF_DATE_KHR) + { + return recreateSwapchain(window.width, window.height); + } + if (!acquired.isSuccess()) + { + fail("Failed to acquire Vulkan swapchain image: " + VK.getLastError()); + return false; + } + + var framebuffer = framebuffers[acquired.imageIndex]; + if (framebuffer == null) + { + fail("Swapchain image did not have a framebuffer"); + return false; + } + + if (!updateCubeUniform()) + { + fail("Failed to update Vulkan uniform buffer: " + VK.getLastError()); + return false; + } + + if (!commandBuffer.reset() + || !commandBuffer.begin(VK.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + || !commandBuffer.beginRenderPass(offscreenRenderPass, offscreenFramebuffer, OFFSCREEN_SIZE, OFFSCREEN_SIZE, 0.02, 0.04, 0.07, 1.0) + || !commandBuffer.setViewport(0, 0, OFFSCREEN_SIZE, OFFSCREEN_SIZE) + || !commandBuffer.setScissor(0, 0, OFFSCREEN_SIZE, OFFSCREEN_SIZE) + || !commandBuffer.bindPipeline(offscreenPipeline) + || !commandBuffer.bindDescriptorSet(offscreenPipelineLayout, offscreenDescriptorSet) + || !commandBuffer.bindVertexBuffer(quadVertexBuffer) + || !commandBuffer.bindIndexBuffer(quadIndexBuffer) + || !commandBuffer.drawIndexed(6) + || !commandBuffer.endRenderPass() + || !commandBuffer.pipelineBarrierImage(offscreenImage, VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK.PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK.ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK.ACCESS_SHADER_READ_BIT, VK.IMAGE_ASPECT_COLOR_BIT) + || !commandBuffer.beginRenderPass(renderPass, framebuffer, swapchain.width, swapchain.height, 0.07, 0.08, 0.09, 1.0, 1.0) + || !commandBuffer.setViewport(0, 0, swapchain.width, swapchain.height) + || !commandBuffer.setScissor(0, 0, swapchain.width, swapchain.height) + || !commandBuffer.bindPipeline(cubePipeline) + || !commandBuffer.bindDescriptorSet(cubePipelineLayout, cubeDescriptorSet) + || !commandBuffer.bindVertexBuffer(cubeVertexBuffer) + || !commandBuffer.bindIndexBuffer(cubeIndexBuffer) + || !commandBuffer.drawIndexed(36) + || !commandBuffer.endRenderPass() + || !commandBuffer.end()) + { + fail("Failed to record Vulkan draw commands: " + VK.getLastError()); + return false; + } + + if (!fence.reset() || !device.graphicsQueue.submitSynced(commandBuffer, imageAvailable, renderFinished, fence) + || !fence.waitForever()) + { + fail("Failed to submit Vulkan draw commands: " + VK.getLastError()); + return false; + } + + var presentResult = device.graphicsQueue.present(swapchain, acquired.imageIndex, renderFinished); + if (presentResult == VK.ERROR_OUT_OF_DATE_KHR) + { + return recreateSwapchain(window.width, window.height); + } + if (presentResult != VK.SUCCESS && presentResult != VK.SUBOPTIMAL_KHR) + { + fail("Failed to present Vulkan swapchain image: " + VK.getLastError()); + return false; + } + + return true; + } + + private function updateCubeUniform():Bool + { + var aspect = swapchain.height > 0 ? swapchain.width / swapchain.height : 1.0; + var angle = Timer.stamp(); + var model = multiply(rotationY(angle), rotationX(angle * 0.61)); + var view = translation(0, 0, -4.25); + var projection = perspective(Math.PI / 3, aspect, 0.1, 100); + var mvp = multiply(projection, multiply(view, model)); + var bytes = Bytes.alloc(64); + + for (i in 0...16) + { + bytes.setFloat(i * 4, mvp[i]); + } + + return uniformBuffer.upload(bytes); + } + + private function recreateSwapchain(width:Int, height:Int):Bool + { + if (width <= 0 || height <= 0 || swapchain == null) + { + return false; + } + + if (!device.waitIdle()) + { + fail("Failed to idle Vulkan device before swapchain recreation: " + VK.getLastError()); + return false; + } + + disposeSwapchainResources(); + var oldSwapchain = swapchain; + swapchain = oldSwapchain.recreate(width, height); + oldSwapchain.dispose(); + + if (swapchain == null || !swapchain.isValid() || swapchain.images.length == 0) + { + fail("Failed to recreate Vulkan swapchain: " + VK.getLastError()); + return false; + } + + return createColorResources() && createDepthResources() && createFramebuffers(); + } + + private function disposeSwapchainResources():Void + { + disposeSwapchainFramebuffers(); + disposeColorResources(); + disposeDepthResources(); + } + + private function disposeSwapchainFramebuffers():Void + { + for (framebuffer in framebuffers) + { + if (framebuffer != null) + { + framebuffer.dispose(); + } + } + framebuffers = []; + + for (imageView in imageViews) + { + if (imageView != null) + { + imageView.dispose(); + } + } + imageViews = []; + } + + private function disposeColorResources():Void + { + if (colorView != null) + { + colorView.dispose(); + colorView = null; + } + if (colorImage != null) + { + colorImage.dispose(true); + colorImage = null; + } + } + + private function disposeDepthResources():Void + { + if (depthView != null) + { + depthView.dispose(); + depthView = null; + } + if (depthImage != null) + { + depthImage.dispose(true); + depthImage = null; + } + } + + private function complete():Void + { + disposeRenderer(); + + if (window != null) + { + window.close(); + } + System.exit(0); + } + + private function disposeRenderer():Void + { + if (device != null && device.isValid()) + { + device.waitIdle(); + } + + disposeSwapchainResources(); + if (offscreenFramebuffer != null) offscreenFramebuffer.dispose(); + if (offscreenView != null) offscreenView.dispose(); + if (offscreenImage != null) offscreenImage.dispose(true); + if (offscreenSampler != null) offscreenSampler.dispose(); + if (cubeIndexBuffer != null) cubeIndexBuffer.dispose(true); + if (cubeVertexBuffer != null) cubeVertexBuffer.dispose(true); + if (quadIndexBuffer != null) quadIndexBuffer.dispose(true); + if (quadVertexBuffer != null) quadVertexBuffer.dispose(true); + if (uniformBuffer != null) uniformBuffer.dispose(true); + if (cubePipeline != null) cubePipeline.dispose(); + if (cubePipelineLayout != null) cubePipelineLayout.dispose(); + if (offscreenPipeline != null) offscreenPipeline.dispose(); + if (offscreenPipelineLayout != null) offscreenPipelineLayout.dispose(); + if (descriptorPool != null) descriptorPool.dispose(); + if (cubeDescriptorSetLayout != null) cubeDescriptorSetLayout.dispose(); + if (offscreenDescriptorSetLayout != null) offscreenDescriptorSetLayout.dispose(); + if (sourceTextureSampler != null) sourceTextureSampler.dispose(); + if (sourceTextureView != null) sourceTextureView.dispose(); + if (sourceTextureImage != null) sourceTextureImage.dispose(true); + if (cubeFragmentShader != null) cubeFragmentShader.dispose(); + if (cubeVertexShader != null) cubeVertexShader.dispose(); + if (quadFragmentShader != null) quadFragmentShader.dispose(); + if (quadVertexShader != null) quadVertexShader.dispose(); + if (renderPass != null) renderPass.dispose(); + if (offscreenRenderPass != null) offscreenRenderPass.dispose(); + if (fence != null) fence.dispose(); + if (renderFinished != null) renderFinished.dispose(); + if (imageAvailable != null) imageAvailable.dispose(); + if (commandBuffer != null) commandBuffer.dispose(); + if (commandPool != null) commandPool.dispose(); + if (swapchain != null) swapchain.dispose(); + if (device != null) device.dispose(); + if (surface != null) surface.dispose(); + if (instance != null) instance.dispose(); + + commandBuffer = null; + commandPool = null; + colorImage = null; + colorView = null; + cubeDescriptorSet = null; + cubeDescriptorSetLayout = null; + cubeFragmentShader = null; + cubeIndexBuffer = null; + cubePipeline = null; + cubePipelineLayout = null; + cubeVertexBuffer = null; + cubeVertexShader = null; + descriptorPool = null; + device = null; + fence = null; + imageAvailable = null; + instance = null; + offscreenDescriptorSet = null; + offscreenDescriptorSetLayout = null; + offscreenFramebuffer = null; + offscreenImage = null; + offscreenPipeline = null; + offscreenPipelineLayout = null; + offscreenRenderPass = null; + offscreenSampler = null; + offscreenView = null; + quadFragmentShader = null; + quadIndexBuffer = null; + quadVertexBuffer = null; + quadVertexShader = null; + renderFinished = null; + renderPass = null; + sourceTextureImage = null; + sourceTextureSampler = null; + sourceTextureView = null; + surface = null; + swapchain = null; + uniformBuffer = null; + } + + private function fail(message:String):Void + { + trace("Vulkan smoke failed: " + message); + disposeRenderer(); + System.exit(1); + } + + private static function identity():Array + { + return [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ]; + } + + private static inline function isNonZero(value:Int64):Bool + { + return value.high != 0 || value.low != 0; + } + + private static function multiply(a:Array, b:Array):Array + { + var result = []; + + for (column in 0...4) + { + for (row in 0...4) + { + var value = 0.0; + for (i in 0...4) + { + value += a[i * 4 + row] * b[column * 4 + i]; + } + result[column * 4 + row] = value; + } + } + + return result; + } + + private static function perspective(fovY:Float, aspect:Float, near:Float, far:Float):Array + { + var f = 1.0 / Math.tan(fovY * 0.5); + var result = [ + f / aspect, 0.0, 0.0, 0.0, + 0.0, -f, 0.0, 0.0, + 0.0, 0.0, far / (near - far), -1.0, + 0.0, 0.0, (far * near) / (near - far), 0.0 + ]; + return result; + } + + private static function rotationX(angle:Float):Array + { + var c = Math.cos(angle); + var s = Math.sin(angle); + var result = identity(); + result[5] = c; + result[6] = s; + result[9] = -s; + result[10] = c; + return result; + } + + private static function rotationY(angle:Float):Array + { + var c = Math.cos(angle); + var s = Math.sin(angle); + var result = identity(); + result[0] = c; + result[2] = -s; + result[8] = s; + result[10] = c; + return result; + } + + private static function translation(x:Float, y:Float, z:Float):Array + { + var result = identity(); + result[12] = x; + result[13] = y; + result[14] = z; + return result; + } +} diff --git a/tests/vulkan-smoke/project.xml b/tests/vulkan-smoke/project.xml new file mode 100644 index 0000000000..ef66f4b29a --- /dev/null +++ b/tests/vulkan-smoke/project.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/tools/platforms/AndroidPlatform.hx b/tools/platforms/AndroidPlatform.hx index ebdad5f110..5adcb94ceb 100644 --- a/tools/platforms/AndroidPlatform.hx +++ b/tools/platforms/AndroidPlatform.hx @@ -403,6 +403,8 @@ class AndroidPlatform extends PlatformTarget // initialize (project); + prepareEmbeddedAssets(); + var destination = targetDirectory + "/bin"; var sourceSet = destination + "/app/src/main"; System.mkdir(sourceSet); @@ -441,6 +443,9 @@ class AndroidPlatform extends PlatformTarget context.ANDROID_ENABLE_JETIFIER = project.config.getString("android.enableJetifier", "false"); context.ANDROID_GRADLE_PROPERTIES = project.config.getKeyValueArray("android.gradle-properties"); context.ANDROID_DISPLAY_CUTOUT = project.config.getString("android.layoutInDisplayCutoutMode", "default"); + context.ANDROID_VULKAN = project.window.renderType != null && project.window.renderType.toLowerCase() == "vulkan"; + context.ANDROID_VULKAN_REQUIRED = project.config.getBool("android.vulkan-required", true); + context.ANDROID_VULKAN_VERSION = project.config.getString("android.vulkan-version", "0x400003"); context.ANDROID_MANIFEST = project.config.getKeyValueArray("android.manifest", { "android:versionCode": project.meta.buildNumber, diff --git a/tools/platforms/IOSPlatform.hx b/tools/platforms/IOSPlatform.hx index dc9170417c..915463819f 100644 --- a/tools/platforms/IOSPlatform.hx +++ b/tools/platforms/IOSPlatform.hx @@ -523,6 +523,8 @@ class IOSPlatform extends PlatformTarget // manifest.type = AssetType.TEXT; // project.assets.push (manifest); + prepareEmbeddedAssets(); + var context = generateContext(); context.OUTPUT_DIR = targetDirectory; diff --git a/tools/platforms/LinuxPlatform.hx b/tools/platforms/LinuxPlatform.hx index b23644f544..094b0a9022 100644 --- a/tools/platforms/LinuxPlatform.hx +++ b/tools/platforms/LinuxPlatform.hx @@ -567,6 +567,8 @@ class LinuxPlatform extends PlatformTarget // project = project.clone (); // initialize (project); + prepareEmbeddedAssets(); + if (project.targetFlags.exists("xml")) { project.haxeflags.push("-xml " + targetDirectory + "/types.xml"); diff --git a/tools/platforms/MacPlatform.hx b/tools/platforms/MacPlatform.hx index a90383a147..f2c0b3b6bd 100644 --- a/tools/platforms/MacPlatform.hx +++ b/tools/platforms/MacPlatform.hx @@ -520,6 +520,8 @@ class MacPlatform extends PlatformTarget // project = project.clone (); + prepareEmbeddedAssets(); + if (project.targetFlags.exists("xml")) { project.haxeflags.push("-xml " + targetDirectory + "/types.xml"); diff --git a/tools/platforms/TVOSPlatform.hx b/tools/platforms/TVOSPlatform.hx index 159c531ebe..331805dd94 100644 --- a/tools/platforms/TVOSPlatform.hx +++ b/tools/platforms/TVOSPlatform.hx @@ -433,6 +433,8 @@ class TVOSPlatform extends PlatformTarget // manifest.type = AssetType.TEXT; // project.assets.push (manifest); + prepareEmbeddedAssets(); + var context = generateContext(); context.OUTPUT_DIR = targetDirectory; diff --git a/tools/platforms/TizenPlatform.hx b/tools/platforms/TizenPlatform.hx index 8ecb2d082f..5aff46f681 100644 --- a/tools/platforms/TizenPlatform.hx +++ b/tools/platforms/TizenPlatform.hx @@ -203,6 +203,8 @@ class TizenPlatform extends PlatformTarget asset.resourceName = "../res/" + asset.resourceName; } + prepareEmbeddedAssets(); + if (project.targetFlags.exists("xml")) { project.haxeflags.push("-xml " + targetDirectory + "/types.xml"); diff --git a/tools/platforms/WebAssemblyPlatform.hx b/tools/platforms/WebAssemblyPlatform.hx index dbf8ad19f4..11281fb8de 100644 --- a/tools/platforms/WebAssemblyPlatform.hx +++ b/tools/platforms/WebAssemblyPlatform.hx @@ -375,6 +375,8 @@ class WebAssemblyPlatform extends PlatformTarget var destination = targetDirectory + "/bin/"; System.mkdir(destination); + prepareEmbeddedAssets(); + // for (asset in project.assets) { // // if (asset.type == AssetType.FONT) { @@ -447,21 +449,7 @@ class WebAssemblyPlatform extends PlatformTarget // ProjectHelper.recursiveSmartCopyTemplate(project, "webassembly/cpp", targetDirectory + "/obj", context); ProjectHelper.recursiveSmartCopyTemplate(project, "cpp/static", targetDirectory + "/obj", context); - for (asset in project.assets) - { - var path = Path.combine(destination, asset.targetPath); - - if (asset.type == AssetType.TEMPLATE) - { - System.mkdir(Path.directory(path)); - AssetHelper.copyAsset(asset, path, context); - } - else - { - System.mkdir(Path.directory(path)); - AssetHelper.copyAsset(asset, path, context); - } - } + copyProjectAssets(destination); } @ignore public override function install():Void {} diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index f9f9aa58fd..de9f8ec17b 100644 --- a/tools/platforms/WindowsPlatform.hx +++ b/tools/platforms/WindowsPlatform.hx @@ -602,6 +602,8 @@ class WindowsPlatform extends PlatformTarget if (noOutput) return; + IconHelper.createWindowsIcon(icons, Path.combine(targetDirectory + "/obj", "ApplicationMain.ico")); + CPPHelper.compile(project, targetDirectory + "/obj", flags); System.copyFile(targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : "") + ".exe", executablePath); @@ -630,19 +632,14 @@ class WindowsPlatform extends PlatformTarget if (noOutput) return; + IconHelper.createWindowsIcon(icons, Path.combine(targetDirectory + "/obj", "ApplicationMain.ico")); + CPPHelper.compile(project, targetDirectory + "/obj", flags.concat(["-Dstatic_link"])); + CPPHelper.compile(project, targetDirectory + "/obj", flags, "BuildMain.xml"); System.copyFile(targetDirectory + "/obj/Main" + (project.debug ? "-debug" : "") + ".exe", executablePath); } - - var iconPath = Path.combine(applicationDirectory, "icon.ico"); - - if (IconHelper.createWindowsIcon(icons, iconPath) && System.hostPlatform == WINDOWS) - { - var templates = [Haxelib.getPath(new Haxelib(#if lime "lime" #else "hxp" #end)) + "/templates"].concat(project.templatePaths); - System.runCommand("", System.findTemplate(templates, "bin/ReplaceVistaIcon.exe"), [executablePath, iconPath, "1"], true, true); - } } } } @@ -957,6 +954,8 @@ class WindowsPlatform extends PlatformTarget // project = project.clone (); + prepareEmbeddedAssets(); + if (project.targetFlags.exists("xml")) { project.haxeflags.push("-xml " + targetDirectory + "/types.xml"); @@ -1019,6 +1018,12 @@ class WindowsPlatform extends PlatformTarget } else if (targetType == "cpp") { + var windowsIcons = project.icons; + if (windowsIcons.length == 0) + { + windowsIcons = [new Icon(System.findTemplate(project.templatePaths, "default/icon.svg"))]; + } + context.HAS_ICON = IconHelper.createWindowsIcon(windowsIcons, Path.combine(targetDirectory + "/obj", "ApplicationMain.ico")); ProjectHelper.recursiveSmartCopyTemplate(project, "windows/resource", targetDirectory + "/obj", context); if (project.targetFlags.exists("static"))