From 56087c6cbae641dbbf83188e44adc899cd79b285 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Thu, 28 Aug 2025 00:50:15 +0100 Subject: [PATCH 001/251] Remove redundant file dialog string conversions No need to iterate through the whole string to find the length, just to see if it is empty. --- project/include/ui/FileDialog.h | 30 +++- project/src/ExternalInterface.cpp | 222 ++++++------------------- project/src/ui/FileDialog.cpp | 266 +++++++----------------------- 3 files changed, 133 insertions(+), 385 deletions(-) diff --git a/project/include/ui/FileDialog.h b/project/include/ui/FileDialog.h index 4a310b3198..cb96863ee4 100644 --- a/project/include/ui/FileDialog.h +++ b/project/include/ui/FileDialog.h @@ -13,10 +13,30 @@ namespace lime { 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; } + const 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 +44,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 1718f4aa00..c5f7e2d36c 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -203,66 +203,51 @@ namespace lime { } - std::wstring* hxstring_to_wstring (HxString val) { - - if (val.c_str ()) { - - #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 { - - return 0; - - } - - } - - - std::wstring* hxstring_to_wstring (hl_vstring* val) { + #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) + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { if (val) { - - 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 - - } else { - - return 0; - + 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); + } - value wstring_to_value (std::wstring* val) { + #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) + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { if (val) { - - #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 ()); - #endif - - } else { - - return 0; - + 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 value lime_application_create () { @@ -764,25 +749,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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; + const FileDialog::char_t* path = FileDialog::OpenDirectory (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -797,25 +768,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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; + 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) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes(path); } @@ -830,25 +787,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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::OpenFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::OpenFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -863,25 +806,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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::OpenFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + 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) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes (path); } @@ -896,24 +825,15 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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); + 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 ()); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - for (int i = 0; i < files.size (); i++) { - value _file = wstring_to_value (files[i]); - val_array_set_i (result, i, _file); - delete files[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); } @@ -930,24 +850,14 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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); + 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*); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - for (int i = 0; i < files.size (); i++) { - *resultData++ = hl_wstring_to_utf8_bytes (*files[i]); - delete files[i]; + auto file_str = files[i]; + *resultData++ = hl_fd_str_to_utf8_bytes (file_str.data(), file_str.size()); } @@ -964,25 +874,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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; + const FileDialog::char_t* path = FileDialog::SaveFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -997,25 +893,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - 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; + 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) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes (path); } 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; } From 4613c72d2172f9fbb0cd505c6c1c81b7047a23e2 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Sat, 20 Dec 2025 02:06:21 +0000 Subject: [PATCH 002/251] Add comment about file dialog string ownership --- project/include/ui/FileDialog.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/include/ui/FileDialog.h b/project/include/ui/FileDialog.h index cb96863ee4..aa087a0b67 100644 --- a/project/include/ui/FileDialog.h +++ b/project/include/ui/FileDialog.h @@ -9,6 +9,8 @@ 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: From 918ca9f5676db25f2792ee728837baefbd91cf8b Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Mon, 12 Jan 2026 13:45:35 +0000 Subject: [PATCH 003/251] Remove unneeded const --- project/include/ui/FileDialog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/include/ui/FileDialog.h b/project/include/ui/FileDialog.h index aa087a0b67..1adf918f7b 100644 --- a/project/include/ui/FileDialog.h +++ b/project/include/ui/FileDialog.h @@ -30,7 +30,7 @@ namespace lime { string_view(const char_t* c_str, size_t length) : c_str(c_str), length(length) {} const char_t* data() const { return c_str; } - const size_t size() const { return length; } + size_t size() const { return length; } private: const char_t* c_str; From 20b47866c3c19ccd105634b8681dc54dfd7544b0 Mon Sep 17 00:00:00 2001 From: Joseph Cloutier Date: Thu, 14 May 2026 16:37:43 -0400 Subject: [PATCH 004/251] Fix asset embedding regression. Originally, this check happened _in addition to_ copying the asset to `targetPath`. I incorrectly made it run instead, which would mean the asset never got copied. The copy seems to be mostly redundant, but having a valid `sourcePath` means `getAssetData()` and `getPackedAssetData()` can return more information. --- src/lime/tools/PlatformTarget.hx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index d616a2e352..fc5dc2a20f 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -222,18 +222,16 @@ class PlatformTarget System.mkdir(Path.directory(path)); AssetHelper.copyAsset(asset, path, project.templateContext); } - else if (asset.embed == true) + else { - if (asset.sourcePath == "") + if (asset.embed == true && asset.sourcePath == "") { var path = Path.combine(embedDirectory, asset.targetPath); System.mkdir(Path.directory(path)); AssetHelper.copyAsset(asset, path); asset.sourcePath = path; } - } - else - { + var path = Path.combine(assetDirectory, asset.targetPath); System.mkdir(Path.directory(path)); AssetHelper.copyAssetIfNewer(asset, path); From c2ed6a0b9d36b5ba5351404601f42bfac205a9b8 Mon Sep 17 00:00:00 2001 From: Joseph Cloutier Date: Thu, 14 May 2026 16:46:47 -0400 Subject: [PATCH 005/251] Use `copyProjectAssets()` in `WebAssemblyPlatform`. Now copying directly into the application directory rather than _obj/assets_. Everything else here is the same. --- tools/platforms/WebAssemblyPlatform.hx | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tools/platforms/WebAssemblyPlatform.hx b/tools/platforms/WebAssemblyPlatform.hx index dbf8ad19f4..420594e8bc 100644 --- a/tools/platforms/WebAssemblyPlatform.hx +++ b/tools/platforms/WebAssemblyPlatform.hx @@ -447,21 +447,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 {} From 919232a237870e4c7a7db5bb6190a4eaf7de967b Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 19 May 2026 22:07:19 -0400 Subject: [PATCH 006/251] Add an experimental Vulkan backend This adds a native Vulkan context, wires it through the SDL backend, and exposes the bootstrap pieces needed to create an instance and surface from Lime. --- docs/ImportAll.hx | 7 + project/Build.xml | 10 + project/include/graphics/vulkan/VKRenderer.h | 160 ++ project/include/ui/Window.h | 18 +- project/src/ExternalInterface.cpp | 1093 +++++++++++ project/src/backend/sdl/SDLWindow.cpp | 225 ++- project/src/backend/sdl/SDLWindow.h | 7 + project/src/graphics/vulkan/VKRenderer.cpp | 1739 +++++++++++++++++ .../_internal/backend/native/NativeCFFI.hx | 169 ++ .../_internal/backend/native/NativeWindow.hx | 15 +- src/lime/graphics/RenderContext.hx | 7 + src/lime/graphics/RenderContextType.hx | 5 + src/lime/graphics/VulkanRenderContext.hx | 190 ++ src/lime/graphics/vulkan/VK.hx | 154 ++ src/lime/graphics/vulkan/VKInstance.hx | 112 ++ src/lime/graphics/vulkan/VKPhysicalDevice.hx | 87 + src/lime/graphics/vulkan/VKQueueFamilyInfo.hx | 42 + src/lime/graphics/vulkan/VKRenderer.hx | 147 ++ src/lime/graphics/vulkan/VKSurface.hx | 52 + 19 files changed, 4194 insertions(+), 45 deletions(-) create mode 100644 project/include/graphics/vulkan/VKRenderer.h create mode 100644 project/src/graphics/vulkan/VKRenderer.cpp create mode 100644 src/lime/graphics/VulkanRenderContext.hx create mode 100644 src/lime/graphics/vulkan/VK.hx create mode 100644 src/lime/graphics/vulkan/VKInstance.hx create mode 100644 src/lime/graphics/vulkan/VKPhysicalDevice.hx create mode 100644 src/lime/graphics/vulkan/VKQueueFamilyInfo.hx create mode 100644 src/lime/graphics/vulkan/VKRenderer.hx create mode 100644 src/lime/graphics/vulkan/VKSurface.hx diff --git a/docs/ImportAll.hx b/docs/ImportAll.hx index e0039724f6..ba022480ee 100644 --- a/docs/ImportAll.hx +++ b/docs/ImportAll.hx @@ -58,6 +58,13 @@ 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.VKRenderer; +import lime.graphics.vulkan.VKInstance; +import lime.graphics.vulkan.VKPhysicalDevice; +import lime.graphics.vulkan.VKQueueFamilyInfo; +import lime.graphics.vulkan.VKSurface; import lime.graphics.WebGL2RenderContext; import lime.graphics.WebGLRenderContext; import lime.math.ARGB; diff --git a/project/Build.xml b/project/Build.xml index ef9bc7458d..a1a5b48d2c 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -35,10 +35,14 @@ + + + + @@ -59,6 +63,10 @@ + + + + @@ -236,6 +244,7 @@ + @@ -270,6 +279,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/ui/Window.h b/project/include/ui/Window.h index 04321be0b2..8af2651c4a 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,8 @@ 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 }; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 0fcb20e6e7..4fc72f7cc3 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 @@ -57,6 +60,7 @@ #include #include +#include #ifdef LIME_SDL_SOUND #include @@ -67,6 +71,178 @@ DEFINE_KIND (k_finalizer); namespace lime { + static std::string lastVulkanRendererError; + static std::string lastVKError; + + + static uint64_t CombineVulkanHandle (int high, int low) { + + return ((uint64_t)(uint32_t)high << 32) | (uint32_t)low; + + } + + + static value CreateVulkanHandleValue (uint64_t handleValue) { + + 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; + + } + + + static vdynamic* HLCreateVulkanHandleValue (uint64_t handleValue) { + + 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; + + } + + +#ifdef LIME_VULKAN + static VkSurfaceKHR UInt64ToVulkanSurface (uint64_t value) { + + return (VkSurfaceKHR)value; + + } + + + static bool CreateManagedVulkanInstance (Window* targetWindow, const char* applicationName, VkInstance* outInstance) { + + if (!targetWindow || !outInstance) { + + lastVKError = "Missing Vulkan window or output instance"; + return false; + + } + + *outInstance = VK_NULL_HANDLE; + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; + + } + + 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; + + } + + unsigned int requiredExtensionCount = 0; + if (!targetWindow->GetVulkanInstanceExtensions (&requiredExtensionCount, 0)) { + + lastVKError = "Failed to query required Vulkan window extensions"; + return false; + + } + + std::vector requiredExtensions (requiredExtensionCount); + if (requiredExtensionCount > 0 && !targetWindow->GetVulkanInstanceExtensions (&requiredExtensionCount, requiredExtensions.data ())) { + + lastVKError = "Failed to fetch required Vulkan window extensions"; + return false; + + } + + std::vector instanceExtensions; + for (size_t i = 0; i < requiredExtensions.size (); ++i) { + + instanceExtensions.push_back (requiredExtensions[i]); + + } + + bool portabilityEnumerationSupported = false; + uint32_t availableExtensionCount = 0; + if (vkEnumerateInstanceExtensionProperties (0, &availableExtensionCount, 0) == VK_SUCCESS && availableExtensionCount > 0) { + + std::vector availableExtensions (availableExtensionCount); + if (vkEnumerateInstanceExtensionProperties (0, &availableExtensionCount, 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"; + 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, outInstance); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateInstance failed"; + return false; + + } + + lastVKError.clear (); + return true; + + } +#endif + void gc_application (value handle) { @@ -3533,6 +3709,889 @@ namespace lime { } + 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_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_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_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_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_get_last_error () { + + return alloc_string (lastVKError.c_str ()); + + } + + + HL_PRIM vbyte* HL_NAME(hl_vk_get_last_error) () { + + return hl_copy_bytes ((const vbyte*)lastVKError.c_str (), (int)lastVKError.size () + 1); + + } + + +#ifdef LIME_VULKAN + value lime_vulkan_renderer_create (value window, HxString applicationName) { + + 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 (); + + } + + lastVulkanRendererError.clear (); + return CFFIPointer (renderer); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { + + Window* targetWindow = (Window*)window->ptr; + VulkanRenderer* renderer = new VulkanRenderer (targetWindow); + const char* applicationNameUTF8 = applicationName ? (const char*)hl_to_utf8 ((const uchar*)applicationName->bytes) : 0; + + if (!renderer->Create (applicationNameUTF8)) { + + lastVulkanRendererError = renderer->GetLastError (); + delete renderer; + return 0; + + } + + lastVulkanRendererError.clear (); + return HLCFFIPointer (renderer); + + } + + + void lime_vulkan_renderer_destroy (value handle) { + + if (val_is_null (handle)) return; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + delete renderer; + + } + + + HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) { + + if (!handle || !handle->ptr) return; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + handle->ptr = 0; + delete renderer; + + } + + + value lime_vulkan_renderer_get_info (value handle) { + + if (val_is_null (handle)) return alloc_string (""); + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + return alloc_string (renderer->GetInfo ().c_str ()); + + } + + + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { + + 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_vulkan_renderer_get_last_error () { + + return alloc_string (lastVulkanRendererError.c_str ()); + + } + + + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { + + return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); + + } + + + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { + + 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 bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { + + 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; + + } + + + bool lime_vulkan_renderer_clear_overlay (value handle) { + + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { + + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + + + bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { + + 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; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { + + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Render (red, green, blue, alpha); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + + + bool lime_vulkan_renderer_resize (value handle) { + + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { + + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } +#else + value lime_vulkan_renderer_create (value window, HxString applicationName) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return alloc_null (); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return 0; + + } + + + void lime_vulkan_renderer_destroy (value handle) {} + + + HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) {} + + + value lime_vulkan_renderer_get_info (value handle) { + + return alloc_string (""); + + } + + + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { + + return hl_copy_bytes ((const vbyte*)"", 1); + + } + + + value lime_vulkan_renderer_get_last_error () { + + return alloc_string (lastVulkanRendererError.c_str ()); + + } + + + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { + + return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); + + } + + + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + bool lime_vulkan_renderer_clear_overlay (value handle) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + bool lime_vulkan_renderer_resize (value handle) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { + + lastVulkanRendererError = "Lime was built without lime-vulkan support"; + return false; + + } +#endif + + int lime_window_get_display (value window) { Window* targetWindow = (Window*)val_data (window); @@ -4297,6 +5356,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 +5364,22 @@ 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_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); @@ -4496,6 +5572,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 +5580,22 @@ 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 (_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/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index 07cd39693b..9686ae6894 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -199,6 +199,7 @@ namespace lime { sdlTexture = 0; sdlRenderer = 0; context = 0; + useVulkan = (flags & WINDOW_FLAG_VULKAN) != 0; contextWidth = 0; contextHeight = 0; @@ -242,7 +243,15 @@ namespace lime { 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 +259,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 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 (flags & WINDOW_FLAG_DEPTH_BUFFER) { + if (flags & WINDOW_FLAG_DEPTH_BUFFER) { - SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 32 - (flags & WINDOW_FLAG_STENCIL_BUFFER) ? 8 : 0); + SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 32 - (flags & WINDOW_FLAG_STENCIL_BUFFER) ? 8 : 0); - } + } - if (flags & WINDOW_FLAG_STENCIL_BUFFER) { + if (flags & WINDOW_FLAG_STENCIL_BUFFER) { - SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); - } + } - if (flags & WINDOW_FLAG_HW_AA_HIRES) { + if (flags & WINDOW_FLAG_HW_AA_HIRES) { - 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, 4); - } else if (flags & WINDOW_FLAG_HW_AA) { + } else if (flags & WINDOW_FLAG_HW_AA) { - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); - SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 2); + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, true); + SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, 2); - } + } - if (flags & WINDOW_FLAG_COLOR_DEPTH_32_BIT) { + 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); + 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 { + } 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 +326,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); @@ -362,7 +375,7 @@ namespace lime { int sdlRendererFlags = 0; - if (flags & WINDOW_FLAG_HARDWARE) { + if ((flags & WINDOW_FLAG_HARDWARE) && !useVulkan) { sdlRendererFlags |= SDL_RENDERER_ACCELERATED; @@ -430,7 +443,7 @@ namespace lime { } - if (!context) { + if (!context && !useVulkan) { sdlRendererFlags &= ~SDL_RENDERER_ACCELERATED; sdlRendererFlags &= ~SDL_RENDERER_PRESENTVSYNC; @@ -441,7 +454,7 @@ namespace lime { } - if (context || sdlRenderer) { + if (context || sdlRenderer || useVulkan) { ((SDLApplication*)currentApplication)->RegisterWindow (this); @@ -558,6 +571,12 @@ namespace lime { void SDLWindow::ContextFlip () { + if (useVulkan) { + + return; + + } + if (context && !sdlRenderer) { SDL_GL_SwapWindow (sdlWindow); @@ -578,6 +597,13 @@ namespace lime { } + int SDLWindow::GetRequestedVSyncMode () const { + + return requestedVSyncMode; + + } + + double SDLWindow::GetRefreshRate () const { if (!sdlWindow) { @@ -605,6 +631,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 +784,12 @@ namespace lime { void SDLWindow::ContextMakeCurrent () { + if (useVulkan) { + + return; + + } + if (sdlWindow && context) { SDL_GL_MakeCurrent (sdlWindow, context); @@ -723,6 +821,12 @@ namespace lime { void* SDLWindow::GetContext () { + if (useVulkan) { + + return sdlWindow; + + } + return context; } @@ -730,6 +834,12 @@ namespace lime { const char* SDLWindow::GetContextType () { + if (useVulkan) { + + return "vulkan"; + + } + if (context) { return "opengl"; @@ -1333,6 +1443,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; 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/vulkan/VKRenderer.cpp b/project/src/graphics/vulkan/VKRenderer.cpp new file mode 100644 index 0000000000..dfe41d9553 --- /dev/null +++ b/project/src/graphics/vulkan/VKRenderer.cpp @@ -0,0 +1,1739 @@ +#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 VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = { + 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 + }; + + for (size_t i = 0; i < sizeof (compositeAlphaFlags) / sizeof (compositeAlphaFlags[0]); ++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/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index fe8bb2cb41..7db7353e27 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,38 @@ 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; + + @: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 +667,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 +680,38 @@ 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)); + 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 +899,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 +908,22 @@ 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); + 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", 6); + 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 +1516,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 +1554,84 @@ 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):Dynamic + { + return null; + } + + @: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:hl.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; diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index 0f6028a296..3da3ec90e2 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; @@ -79,9 +80,13 @@ 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; @@ -106,6 +111,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; @@ -156,6 +162,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 +754,5 @@ 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; } 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..a33494aa6a --- /dev/null +++ b/src/lime/graphics/VulkanRenderContext.hx @@ -0,0 +1,190 @@ +package lime.graphics; + +import haxe.Int64; +import lime.graphics.vulkan.VKRenderer; +import lime.math.Vector2; +import lime.system.CFFI; +import lime.system.CFFIPointer; + +#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`. + + Lime does not provide Vulkan API bindings or manage swapchains for you. + Instead, this context focuses on the window-specific pieces an external + Vulkan layer needs: + + - required instance extensions for the current window + - the current drawable size in pixels + - Vulkan surface creation for an existing `VkInstance` + - access to `vkGetInstanceProcAddr` +**/ +@:access(lime._internal.backend.native.NativeCFFI) +class VulkanRenderContext +{ + public var type(default, null):RenderContextType; + public var version(default, null):String; + + private var __windowHandle:CFFIPointer; + + @:allow(lime._internal.backend.native.NativeWindow) + private function new(windowHandle:CFFIPointer) + { + __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 a minimal Vulkan swapchain renderer for the current window. + + This is intentionally narrow and currently only exposes clear-and-present + rendering so we can validate Lime's Vulkan window path end-to-end. + 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..54e9b17032 --- /dev/null +++ b/src/lime/graphics/vulkan/VK.hx @@ -0,0 +1,154 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.graphics.VulkanRenderContext; +import lime.system.CFFI; + +#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 lightweight Vulkan bootstrap helpers. + + This API is intentionally smaller than `lime.graphics.opengl.GL`. It focuses + on the native window/bootstrap work needed to get a Vulkan app started while + Lime's wider Vulkan surface continues to grow. +**/ +class VK +{ + /** + 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.VKInstance) + @:allow(lime.graphics.vulkan.VKPhysicalDevice) + 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.VKInstance) + 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 2: + score += preferDiscrete ? 400 : 250; + case 1: + score += preferDiscrete ? 300 : 400; + case 3: + score += 150; + case 4: + 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/VKInstance.hx b/src/lime/graphics/vulkan/VKInstance.hx new file mode 100644 index 0000000000..de6a9af7c5 --- /dev/null +++ b/src/lime/graphics/vulkan/VKInstance.hx @@ -0,0 +1,112 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.graphics.VulkanRenderContext; +import lime.system.CFFI; + +#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/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx new file mode 100644 index 0000000000..47d1b5b214 --- /dev/null +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -0,0 +1,87 @@ +package lime.graphics.vulkan; + +import haxe.Int64; +import lime.system.CFFI; + +/** + 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 isDiscrete(default, null):Bool; + 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) ? CFFI.stringValue(data.name) : ""; + apiVersion = data.apiVersion; + apiVersionString = VK.versionString(apiVersion); + driverVersion = data.driverVersion; + vendorID = data.vendorID; + deviceID = data.deviceID; + deviceType = data.deviceType; + 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; + } + } + } + } + + /** + 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; + } +} 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/VKRenderer.hx b/src/lime/graphics/vulkan/VKRenderer.hx new file mode 100644 index 0000000000..374c7c53d4 --- /dev/null +++ b/src/lime/graphics/vulkan/VKRenderer.hx @@ -0,0 +1,147 @@ +package lime.graphics.vulkan; + +import lime.graphics.Image; +import lime.system.CFFI; +import lime.system.CFFIPointer; + +#if (!lime_doc_gen || lime_cffi) +import lime._internal.backend.native.NativeCFFI; +#end + +@:access(lime.graphics.VulkanRenderContext) +@:access(lime._internal.backend.native.NativeCFFI) +/** + A minimal managed Vulkan swapchain renderer exposed by Lime for validation + and sample work. This is intentionally narrower than Lime's GL API surface. +**/ +class VKRenderer +{ + public var info(get, never):String; + public var isValid(get, never):Bool; + public var lastError(get, never):String; + + private var __handle:CFFIPointer; + private var __info:String; + + @:allow(lime.graphics.VulkanRenderContext) + private function new(handle:CFFIPointer) + { + __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/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); + } +} From df371a3a08b04bce533eaad452b7e6c828e4a575 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 19 May 2026 22:08:03 -0400 Subject: [PATCH 007/251] Hook the Vulkan backend into project config and CI This makes Vulkan selectable from project.xml and adds a small smoke test in CI so the new backend stays covered. --- .github/workflows/main.yml | 63 +++++++++++- README.md | 5 + src/lime/tools/ProjectXMLParser.hx | 3 + src/lime/tools/WindowData.hx | 2 + templates/haxe/ApplicationMain.hx | 2 +- tests/vulkan-smoke/Source/Main.hx | 152 +++++++++++++++++++++++++++++ tests/vulkan-smoke/project.xml | 14 +++ 7 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 tests/vulkan-smoke/Source/Main.hx create mode 100644 tests/vulkan-smoke/project.xml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 857907b35e..e7c87e1f36 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -182,6 +182,65 @@ 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 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 Vulkan) + run: | + lime rebuild linux -64 -release -nocolor -verbose -nocffi -D lime-vulkan + + - 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: | + xvfb-run -a Export/linux/bin/LimeVulkanSmoke + + - name: Install samples + run: | + haxelib git lime-samples https://github.com/openfl/lime-samples --quiet + + - name: Build HelloWorld Vulkan sample + run: | + lime create HelloWorld -verbose -nocolor + lime build HelloWorld linux -release -verbose -nocolor -D lime-vulkan --window-render-type=vulkan + macos: runs-on: macos-14 steps: @@ -536,7 +595,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: @@ -996,7 +1055,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/README.md b/README.md index c6803fb1a5..a703f9140a 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 currently focuses on window/bootstrap helpers and a minimal validation renderer for backend verification, not a full high-level renderer. +The native Vulkan bootstrap and validation renderer are currently opt-in and require building Lime with the `lime-vulkan` define plus Vulkan headers available to the native toolchain. +To request a Vulkan window, use the standard `RenderContextType.VULKAN` context selection, set `` in project XML, or use `--window-render-type=vulkan`. +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/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index 876d59d1c3..63ca4d5bb6 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1984,6 +1984,9 @@ class ProjectXMLParser extends HXProject case "parameters", "title": Reflect.setField(windows[id], name, Std.string(value)); + case "render-type", "context-type": + Reflect.setField(windows[id], "renderType", Std.string(value).toLowerCase()); + 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..92f101feb1 100644 --- a/src/lime/tools/WindowData.hx +++ b/src/lime/tools/WindowData.hx @@ -19,6 +19,7 @@ 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; @@ -53,6 +54,7 @@ abstract WindowData({ allowHighDPI: false, alwaysOnTop: false, antialiasing: 0, + renderType: null, orientation: Orientation.AUTO, allowShaders: false, requireShaders: false, diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index 422fbcb030..2fadafabb0 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -62,7 +62,7 @@ import ::APP_MAIN::; depth: ::depthBuffer::, hardware: ::hardware::, stencil: ::stencilBuffer::, - type: null, + type: ::if renderType::"::renderType::"::else::null::end::, vsync: ::vsync:: }; diff --git a/tests/vulkan-smoke/Source/Main.hx b/tests/vulkan-smoke/Source/Main.hx new file mode 100644 index 0000000000..ff2e2a7fe8 --- /dev/null +++ b/tests/vulkan-smoke/Source/Main.hx @@ -0,0 +1,152 @@ +package; + +import haxe.Int64; +import haxe.Timer; +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.VKRenderer; +import lime.system.System; + +class Main extends Application +{ + private var renderer:VKRenderer; + private var finished: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; + } + + var context = window.context.vulkan; + validateBootstrap(context); + + renderer = context.createRenderer("LimeVulkanSmoke"); + if (renderer == null || !renderer.isValid) + { + fail("Failed to create Vulkan renderer: " + VKRenderer.getLastError()); + } + } + + override public function render(context:RenderContext):Void + { + super.render(context); + + if (finished || renderer == null) + { + return; + } + + if (!renderer.render(0.125, 0.25, 0.5, 1.0)) + { + fail("Failed to render Vulkan frame: " + renderer.lastError); + return; + } + + finished = true; + Timer.delay(complete, 50); + } + + private function validateBootstrap(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; + } + + var instance = VK.createInstance(context, "LimeVulkanSmoke"); + if (instance == null || !instance.isValid()) + { + fail("Failed to create Vulkan instance: " + VK.getLastError()); + return; + } + + var surface = instance.createSurface(); + if (surface == null || !surface.isValid()) + { + instance.dispose(); + fail("Failed to create Vulkan surface"); + return; + } + + var devices = instance.enumeratePhysicalDevices(surface); + if (devices.length == 0) + { + surface.dispose(); + instance.dispose(); + fail("No Vulkan physical devices were enumerated"); + return; + } + + var device = instance.pickPhysicalDevice(surface); + if (device == null || !device.hasQueueFamily(true, true)) + { + surface.dispose(); + instance.dispose(); + fail("No present-capable graphics queue family was found"); + return; + } + + surface.dispose(); + instance.dispose(); + } + + private function complete():Void + { + if (renderer != null) + { + renderer.dispose(); + renderer = null; + } + + if (window != null) + { + window.close(); + } + } + + private function fail(message:String):Void + { + trace("Vulkan smoke failed: " + message); + + if (renderer != null) + { + renderer.dispose(); + renderer = null; + } + + System.exit(1); + } + + private static inline function isNonZero(value:Int64):Bool + { + return value.high != 0 || value.low != 0; + } +} diff --git a/tests/vulkan-smoke/project.xml b/tests/vulkan-smoke/project.xml new file mode 100644 index 0000000000..4752ae8640 --- /dev/null +++ b/tests/vulkan-smoke/project.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From aec24419f4a44e458ed9fe0c8c0c5b8b1aed8a8f Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 19 May 2026 22:16:02 -0400 Subject: [PATCH 008/251] Fix Vulkan docs on non-CFFI targets Guard the Vulkan helper imports so the doc builds can compile these types on flash and html5 as well as native targets. --- src/lime/graphics/VulkanRenderContext.hx | 8 ++++++-- src/lime/graphics/vulkan/VK.hx | 2 ++ src/lime/graphics/vulkan/VKInstance.hx | 1 - src/lime/graphics/vulkan/VKPhysicalDevice.hx | 4 +++- src/lime/graphics/vulkan/VKRenderer.hx | 8 ++++++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/lime/graphics/VulkanRenderContext.hx b/src/lime/graphics/VulkanRenderContext.hx index a33494aa6a..f56636b8b4 100644 --- a/src/lime/graphics/VulkanRenderContext.hx +++ b/src/lime/graphics/VulkanRenderContext.hx @@ -3,8 +3,12 @@ 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; @@ -33,10 +37,10 @@ class VulkanRenderContext public var type(default, null):RenderContextType; public var version(default, null):String; - private var __windowHandle:CFFIPointer; + private var __windowHandle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end; @:allow(lime._internal.backend.native.NativeWindow) - private function new(windowHandle:CFFIPointer) + private function new(windowHandle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end) { __windowHandle = windowHandle; type = VULKAN; diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx index 54e9b17032..4f5359eecc 100644 --- a/src/lime/graphics/vulkan/VK.hx +++ b/src/lime/graphics/vulkan/VK.hx @@ -2,7 +2,9 @@ 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; diff --git a/src/lime/graphics/vulkan/VKInstance.hx b/src/lime/graphics/vulkan/VKInstance.hx index de6a9af7c5..71d4e079a3 100644 --- a/src/lime/graphics/vulkan/VKInstance.hx +++ b/src/lime/graphics/vulkan/VKInstance.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import lime.graphics.VulkanRenderContext; -import lime.system.CFFI; #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; diff --git a/src/lime/graphics/vulkan/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx index 47d1b5b214..1edb88aec4 100644 --- a/src/lime/graphics/vulkan/VKPhysicalDevice.hx +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -1,7 +1,9 @@ package lime.graphics.vulkan; import haxe.Int64; +#if (!lime_doc_gen || lime_cffi) import lime.system.CFFI; +#end /** Describes a Vulkan physical device discovered through a `VKInstance`. @@ -27,7 +29,7 @@ class VKPhysicalDevice { this.instance = instance; handle = VK.__makeHandle(data.handle); - name = (data.name != null) ? CFFI.stringValue(data.name) : ""; + 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; diff --git a/src/lime/graphics/vulkan/VKRenderer.hx b/src/lime/graphics/vulkan/VKRenderer.hx index 374c7c53d4..d736b84299 100644 --- a/src/lime/graphics/vulkan/VKRenderer.hx +++ b/src/lime/graphics/vulkan/VKRenderer.hx @@ -1,8 +1,12 @@ 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; @@ -20,11 +24,11 @@ class VKRenderer public var isValid(get, never):Bool; public var lastError(get, never):String; - private var __handle:CFFIPointer; + 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:CFFIPointer) + private function new(handle:#if (!lime_doc_gen || lime_cffi) CFFIPointer #else Dynamic #end) { __handle = handle; __info = ""; From ff8ad734074c4c964b8b25fb317ee06bbbc29b14 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 19 May 2026 22:49:35 -0400 Subject: [PATCH 009/251] Restore frame timing for directly-created windows --- src/lime/app/Application.hx | 1 + src/lime/ui/Window.hx | 1 + 2 files changed, 2 insertions(+) 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/ui/Window.hx b/src/lime/ui/Window.hx index 4a25da753c..b53f65b2af 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -238,6 +238,7 @@ class Window __minimized = Reflect.hasField(__attributes, "minimized") ? __attributes.minimized : 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", From 7dfdf49548528a83100dfebbaaaab69507ac7cb3 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 19 May 2026 23:08:14 -0400 Subject: [PATCH 010/251] Fix Vulkan smoke coverage on Linux --- .github/workflows/main.yml | 7 +++++-- .../lib/custom/sdl/include/SDL_config_linux.h | 3 +++ project/src/backend/sdl/SDLWindow.cpp | 11 ++++++++++- .../_internal/backend/native/NativeCFFI.hx | 2 +- .../_internal/backend/native/NativeWindow.hx | 18 ++++++++++-------- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e7c87e1f36..7965bbfae6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -193,7 +193,7 @@ jobs: - name: Install system dependencies run: | 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 libvulkan-dev mesa-vulkan-drivers xvfb + 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: @@ -230,7 +230,10 @@ jobs: - name: Run Vulkan smoke test app working-directory: tests/vulkan-smoke run: | - xvfb-run -a Export/linux/bin/LimeVulkanSmoke + 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 - name: Install samples run: | 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/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index 9686ae6894..522556fcf8 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -1578,7 +1578,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/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 7db7353e27..f6adb901ec 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -920,7 +920,7 @@ class NativeCFFI 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", 6); + 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); diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index 3da3ec90e2..ecadbb89c1 100644 --- a/src/lime/_internal/backend/native/NativeWindow.hx +++ b/src/lime/_internal/backend/native/NativeWindow.hx @@ -121,17 +121,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(); From 35d97de87fa2ec76dc714a45c08cc9fbfd876daf Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 20 May 2026 19:34:05 -0400 Subject: [PATCH 011/251] Wire up Vulkan devices and command buffers Add the first logical device, queue, command pool, command buffer, fence, and semaphore wrappers for Lime's Vulkan API. Back them with native CFFI calls and exercise the path in the Vulkan smoke test. Keep the deeper Vulkan primitives behind lime-vulkan so regular Lime apps do not resolve Vulkan-only bindings during startup. --- docs/ImportAll.hx | 6 + project/src/ExternalInterface.cpp | 1473 +++++++++++++++++ .../_internal/backend/native/NativeCFFI.hx | 219 +++ src/lime/graphics/VulkanRenderContext.hx | 13 +- src/lime/graphics/vulkan/VK.hx | 63 +- src/lime/graphics/vulkan/VKCommandBuffer.hx | 96 ++ src/lime/graphics/vulkan/VKCommandPool.hx | 93 ++ src/lime/graphics/vulkan/VKDevice.hx | 134 ++ src/lime/graphics/vulkan/VKFence.hx | 78 + src/lime/graphics/vulkan/VKPhysicalDevice.hx | 37 + src/lime/graphics/vulkan/VKQueue.hx | 75 + src/lime/graphics/vulkan/VKRenderer.hx | 6 +- src/lime/graphics/vulkan/VKSemaphore.hx | 47 + tests/vulkan-smoke/Source/Main.hx | 108 ++ 14 files changed, 2432 insertions(+), 16 deletions(-) create mode 100644 src/lime/graphics/vulkan/VKCommandBuffer.hx create mode 100644 src/lime/graphics/vulkan/VKCommandPool.hx create mode 100644 src/lime/graphics/vulkan/VKDevice.hx create mode 100644 src/lime/graphics/vulkan/VKFence.hx create mode 100644 src/lime/graphics/vulkan/VKQueue.hx create mode 100644 src/lime/graphics/vulkan/VKSemaphore.hx diff --git a/docs/ImportAll.hx b/docs/ImportAll.hx index ba022480ee..cd1be55208 100644 --- a/docs/ImportAll.hx +++ b/docs/ImportAll.hx @@ -60,10 +60,16 @@ import lime.graphics.RenderContextAttributes; import lime.graphics.RenderContextType; import lime.graphics.VulkanRenderContext; import lime.graphics.vulkan.VK; +import lime.graphics.vulkan.VKCommandBuffer; +import lime.graphics.vulkan.VKCommandPool; +import lime.graphics.vulkan.VKDevice; +import lime.graphics.vulkan.VKFence; import lime.graphics.vulkan.VKRenderer; import lime.graphics.vulkan.VKInstance; import lime.graphics.vulkan.VKPhysicalDevice; +import lime.graphics.vulkan.VKQueue; import lime.graphics.vulkan.VKQueueFamilyInfo; +import lime.graphics.vulkan.VKSemaphore; import lime.graphics.vulkan.VKSurface; import lime.graphics.WebGL2RenderContext; import lime.graphics.WebGLRenderContext; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 4fc72f7cc3..7bab73d4a4 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -241,6 +241,259 @@ namespace lime { return true; } + + + static std::vector GetVulkanDeviceExtensions (value extensions) { + + std::vector deviceExtensions; + + if (val_is_null (extensions)) { + + deviceExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return deviceExtensions; + + } + + 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)) { + + deviceExtensions.push_back (val_string (extension)); + + } + + } + + return deviceExtensions; + + } + + + static std::vector GetHLVulkanDeviceExtensions (hl_varray* extensions) { + + std::vector deviceExtensions; + + if (!extensions) { + + deviceExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return deviceExtensions; + + } + + int length = extensions->size; + hl_vstring** extensionData = hl_aptr (extensions, hl_vstring*); + + for (int i = 0; i < length; ++i) { + + hl_vstring* extension = *extensionData++; + if (extension) { + + deviceExtensions.push_back (hl_to_utf8 ((const uchar*)extension->bytes)); + + } + + } + + return deviceExtensions; + + } + + + static PFN_vkVoidFunction GetManagedVulkanDeviceProc (Window* targetWindow, VkInstance instance, VkDevice device, const char* name) { + + if (!targetWindow || !instance || !device) { + + lastVKError = "Missing Vulkan window, instance, or device"; + return 0; + + } + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return 0; + + } + + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); + if (!vkGetDeviceProcAddr) { + + lastVKError = "Missing Vulkan device proc address function"; + return 0; + + } + + PFN_vkVoidFunction proc = vkGetDeviceProcAddr (device, name); + if (!proc) { + + lastVKError = std::string ("Missing Vulkan device function: ") + name; + return 0; + + } + + return proc; + + } + + + static bool CreateManagedVulkanDevice (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, + const std::vector& requestedExtensions, VkDevice* outDevice, VkQueue* outQueue) { + + if (!targetWindow || !instance || !physicalDevice || !outDevice || !outQueue) { + + lastVKError = "Missing Vulkan instance, physical device, or output device"; + return false; + + } + + *outDevice = VK_NULL_HANDLE; + *outQueue = VK_NULL_HANDLE; + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; + + } + + 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"); + + if (!vkCreateDevice || !vkGetDeviceProcAddr || !vkEnumerateDeviceExtensionProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { + + lastVKError = "Missing required Vulkan device creation functions"; + return false; + + } + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties (physicalDevice, &queueFamilyCount, 0); + if (queueFamilyIndex >= queueFamilyCount) { + + lastVKError = "Invalid Vulkan queue family index"; + return false; + + } + + 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; + + std::vector deviceExtensions; + for (size_t i = 0; i < requestedExtensions.size (); ++i) { + + deviceExtensions.push_back (requestedExtensions[i].c_str ()); + + } + + if (!requestedExtensions.empty ()) { + + uint32_t extensionCount = 0; + VkResult extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, 0); + if (extensionResult != VK_SUCCESS) { + + lastVKError = "Could not enumerate Vulkan device extensions"; + return false; + + } + + std::vector availableExtensions (extensionCount); + if (extensionCount > 0) { + + extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, availableExtensions.data ()); + if (extensionResult != VK_SUCCESS) { + + lastVKError = "Could not enumerate Vulkan device extensions"; + return false; + + } + + } + + for (size_t i = 0; i < requestedExtensions.size (); ++i) { + + bool extensionSupported = false; + + for (size_t e = 0; e < availableExtensions.size (); ++e) { + + if (strcmp (availableExtensions[e].extensionName, requestedExtensions[i].c_str ()) == 0) { + + extensionSupported = true; + break; + + } + + } + + if (!extensionSupported) { + + lastVKError = std::string ("Vulkan physical device does not support ") + requestedExtensions[i]; + return false; + + } + + } + + } + + VkPhysicalDeviceFeatures deviceFeatures; + memset (&deviceFeatures, 0, sizeof (deviceFeatures)); + + 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 (); + + VkResult result = vkCreateDevice (physicalDevice, &createInfo, 0, outDevice); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateDevice failed"; + return false; + + } + + PFN_vkGetDeviceQueue vkGetDeviceQueue = (PFN_vkGetDeviceQueue)vkGetDeviceProcAddr (*outDevice, "vkGetDeviceQueue"); + if (!vkGetDeviceQueue) { + + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (*outDevice, "vkDestroyDevice"); + if (vkDestroyDevice) vkDestroyDevice (*outDevice, 0); + *outDevice = VK_NULL_HANDLE; + lastVKError = "Missing Vulkan device queue function"; + return false; + + } + + vkGetDeviceQueue (*outDevice, queueFamilyIndex, 0, outQueue); + if (!*outQueue) { + + PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (*outDevice, "vkDestroyDevice"); + if (vkDestroyDevice) vkDestroyDevice (*outDevice, 0); + *outDevice = VK_NULL_HANDLE; + lastVKError = "Failed to get Vulkan device queue"; + return false; + + } + + lastVKError.clear (); + return true; + + } #endif @@ -4284,6 +4537,1188 @@ namespace lime { } + value lime_vk_create_device (value window, int instanceHigh, int instanceLow, int physicalDeviceHigh, int physicalDeviceLow, int queueFamilyIndex, + value extensions) { + +#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); + std::vector deviceExtensions = GetVulkanDeviceExtensions (extensions); + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; + + if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { + + return alloc_null (); + + } + + 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)); + 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) { + + 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) { + + 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) { + + lastVKError = "vkQueueSubmit 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_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) { + + lastVKError = "vkQueueSubmit failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + value lime_vk_get_last_error () { return alloc_string (lastVKError.c_str ()); @@ -5371,6 +6806,25 @@ namespace lime { 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_PRIME0 (lime_vk_get_last_error); DEFINE_PRIME2 (lime_vulkan_renderer_create); DEFINE_PRIME1v (lime_vulkan_renderer_destroy); @@ -5587,6 +7041,25 @@ namespace lime { 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 (_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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index f6adb901ec..b9abfcc40a 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -360,6 +360,62 @@ class NativeCFFI @: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; + #end + @:cffi private static function lime_vk_get_last_error():Dynamic; @:cffi private static function lime_vulkan_renderer_create(handle:Dynamic, applicationName:String):CFFIPointer; @@ -694,6 +750,46 @@ class NativeCFFI "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)); + #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", @@ -915,6 +1011,27 @@ class NativeCFFI 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); + #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); @@ -1587,6 +1704,108 @@ class NativeCFFI 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; + } + #end + @:hlNative("lime", "hl_vk_get_last_error") private static function lime_vk_get_last_error():hl.Bytes { return null; diff --git a/src/lime/graphics/VulkanRenderContext.hx b/src/lime/graphics/VulkanRenderContext.hx index f56636b8b4..39e2e3c1b6 100644 --- a/src/lime/graphics/VulkanRenderContext.hx +++ b/src/lime/graphics/VulkanRenderContext.hx @@ -22,14 +22,15 @@ import lime._internal.backend.native.NativeCFFI; The `VulkanRenderContext` exposes native Vulkan window bootstrap helpers when Vulkan is the render context type of the current `Window`. - Lime does not provide Vulkan API bindings or manage swapchains for you. - Instead, this context focuses on the window-specific pieces an external - Vulkan layer needs: + 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 @@ -141,10 +142,10 @@ class VulkanRenderContext } /** - Creates a minimal Vulkan swapchain renderer for the current window. + Creates Lime's validation Vulkan swapchain renderer for the current window. - This is intentionally narrow and currently only exposes clear-and-present - rendering so we can validate Lime's Vulkan window path end-to-end. + 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. **/ diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx index 4f5359eecc..24cc8b32e3 100644 --- a/src/lime/graphics/vulkan/VK.hx +++ b/src/lime/graphics/vulkan/VK.hx @@ -13,14 +13,49 @@ import lime._internal.backend.native.NativeCFFI; @:access(lime.graphics.VulkanRenderContext) @:access(lime._internal.backend.native.NativeCFFI) /** - Entry point for Lime's lightweight Vulkan bootstrap helpers. + Entry point for Lime's Vulkan API surface. - This API is intentionally smaller than `lime.graphics.opengl.GL`. It focuses - on the native window/bootstrap work needed to get a Vulkan app started while - Lime's wider Vulkan surface continues to grow. + 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 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; + /** Creates a managed `VkInstance` for the current Lime Vulkan window. **/ @@ -100,8 +135,14 @@ class VK } @:allow(lime.graphics.VulkanRenderContext) + @:allow(lime.graphics.vulkan.VKCommandBuffer) + @:allow(lime.graphics.vulkan.VKCommandPool) + @:allow(lime.graphics.vulkan.VKDevice) + @:allow(lime.graphics.vulkan.VKFence) @:allow(lime.graphics.vulkan.VKInstance) @:allow(lime.graphics.vulkan.VKPhysicalDevice) + @:allow(lime.graphics.vulkan.VKQueue) + @:allow(lime.graphics.vulkan.VKSemaphore) private static function __makeHandle(value:Dynamic):Int64 { if (value == null) @@ -113,7 +154,13 @@ class VK } @:allow(lime.graphics.VulkanRenderContext) + @:allow(lime.graphics.vulkan.VKCommandBuffer) + @:allow(lime.graphics.vulkan.VKCommandPool) + @:allow(lime.graphics.vulkan.VKDevice) + @:allow(lime.graphics.vulkan.VKFence) @:allow(lime.graphics.vulkan.VKInstance) + @:allow(lime.graphics.vulkan.VKQueue) + @:allow(lime.graphics.vulkan.VKSemaphore) private static inline function __isZero(handle:Int64):Bool { return handle.high == 0 && handle.low == 0; @@ -130,13 +177,13 @@ class VK switch (device.deviceType) { - case 2: + case PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: score += preferDiscrete ? 400 : 250; - case 1: + case PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: score += preferDiscrete ? 300 : 400; - case 3: + case PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: score += 150; - case 4: + case PHYSICAL_DEVICE_TYPE_CPU: score += 100; default: score += 50; diff --git a/src/lime/graphics/vulkan/VKCommandBuffer.hx b/src/lime/graphics/vulkan/VKCommandBuffer.hx new file mode 100644 index 0000000000..685ecfe448 --- /dev/null +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -0,0 +1,96 @@ +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 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 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; + } + + @: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/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx new file mode 100644 index 0000000000..dbcdd331aa --- /dev/null +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -0,0 +1,134 @@ +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 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 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; + } + + /** + 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/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/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx index 1edb88aec4..7958b2ce5a 100644 --- a/src/lime/graphics/vulkan/VKPhysicalDevice.hx +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -3,8 +3,11 @@ 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`. **/ @@ -64,6 +67,40 @@ class VKPhysicalDevice } } + /** + 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. **/ diff --git a/src/lime/graphics/vulkan/VKQueue.hx b/src/lime/graphics/vulkan/VKQueue.hx new file mode 100644 index 0000000000..9f6e62cb09 --- /dev/null +++ b/src/lime/graphics/vulkan/VKQueue.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) +/** + 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); + } + + /** + 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; + } + + /** + 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/VKRenderer.hx b/src/lime/graphics/vulkan/VKRenderer.hx index d736b84299..d3b70e3023 100644 --- a/src/lime/graphics/vulkan/VKRenderer.hx +++ b/src/lime/graphics/vulkan/VKRenderer.hx @@ -15,8 +15,10 @@ import lime._internal.backend.native.NativeCFFI; @:access(lime.graphics.VulkanRenderContext) @:access(lime._internal.backend.native.NativeCFFI) /** - A minimal managed Vulkan swapchain renderer exposed by Lime for validation - and sample work. This is intentionally narrower than Lime's GL API surface. + 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 { 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/tests/vulkan-smoke/Source/Main.hx b/tests/vulkan-smoke/Source/Main.hx index ff2e2a7fe8..24986fcb43 100644 --- a/tests/vulkan-smoke/Source/Main.hx +++ b/tests/vulkan-smoke/Source/Main.hx @@ -114,6 +114,114 @@ class Main extends Application return; } + var queueFamily = device.getQueueFamily(true, true); + var logicalDevice = device.createDevice(queueFamily); + if (logicalDevice == null || !logicalDevice.isValid() || logicalDevice.graphicsQueue == null || !logicalDevice.graphicsQueue.isValid()) + { + surface.dispose(); + instance.dispose(); + fail("Failed to create Vulkan logical device: " + VK.getLastError()); + return; + } + + if (!logicalDevice.graphicsQueue.waitIdle()) + { + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to wait for Vulkan graphics queue: " + VK.getLastError()); + return; + } + + var semaphore = logicalDevice.createSemaphore(); + if (semaphore == null || !semaphore.isValid()) + { + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to create Vulkan semaphore: " + VK.getLastError()); + return; + } + + var commandPool = logicalDevice.createCommandPool(queueFamily); + if (commandPool == null || !commandPool.isValid()) + { + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to create Vulkan command pool: " + VK.getLastError()); + return; + } + + var commandBuffer = commandPool.allocateCommandBuffer(); + if (commandBuffer == null || !commandBuffer.isValid()) + { + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to allocate Vulkan command buffer: " + VK.getLastError()); + return; + } + + if (!commandBuffer.begin(VK.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) || !commandBuffer.end()) + { + commandBuffer.dispose(); + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to record Vulkan command buffer: " + VK.getLastError()); + return; + } + + var fence = logicalDevice.createFence(); + if (fence == null || !fence.isValid()) + { + commandBuffer.dispose(); + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to create Vulkan fence: " + VK.getLastError()); + return; + } + + if (!logicalDevice.graphicsQueue.submit(commandBuffer, fence) || !fence.waitForever() || !fence.reset()) + { + fence.dispose(); + commandBuffer.dispose(); + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to submit Vulkan command buffer: " + VK.getLastError()); + return; + } + + if (!logicalDevice.waitIdle()) + { + fence.dispose(); + commandBuffer.dispose(); + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); + surface.dispose(); + instance.dispose(); + fail("Failed to wait for Vulkan logical device: " + VK.getLastError()); + return; + } + + fence.dispose(); + commandBuffer.dispose(); + commandPool.dispose(); + semaphore.dispose(); + logicalDevice.dispose(); surface.dispose(); instance.dispose(); } From 780cb40fe8923634111ec23e972abec19dde93f0 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 21 May 2026 00:58:04 -0400 Subject: [PATCH 012/251] Fix HashLink Vulkan signatures Match the HashLink declarations for Vulkan device enumeration and renderer overlays to the signatures exported by the native hdll. --- src/lime/_internal/backend/native/NativeCFFI.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index b9abfcc40a..a33d5fa464 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -1699,7 +1699,7 @@ class NativeCFFI 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):Dynamic + instanceLow:Int, surfaceHigh:Int, surfaceLow:Int):hl.NativeArray { return null; } @@ -1830,7 +1830,7 @@ class NativeCFFI } @:hlNative("lime", "hl_vulkan_renderer_set_overlay") private static function lime_vulkan_renderer_set_overlay(handle:CFFIPointer, - bytes:hl.Bytes, width:Int, height:Int, x:Int, y:Int):Bool + bytes:Bytes, width:Int, height:Int, x:Int, y:Int):Bool { return false; } From 251cb31ee2c8aa0f1210f1dfa7f73c68a503f5bd Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 22 May 2026 01:57:54 -0400 Subject: [PATCH 013/251] Add Vulkan types, swapchain & helper bindings Introduce comprehensive Vulkan bindings and runtime helpers across Haxe and native code. Updated docs/ImportAll.hx to expose many new lime.graphics.vulkan types. Added numerous Haxe VK* classes and shader SPIR-V assets for the vulkan-smoke test. Major changes in project/src/ExternalInterface.cpp: include , robust device extension enumeration and VK_KHR_portability_subset handling, helpers for choosing present modes, creating/destroying managed swapchains, querying swapchain images and surface formats, finding memory types, and conversion helpers between native Vulkan structs and Haxe/HL values. Also cleaned up existing garbage collectors and added utility functions for array conversions. Tests updated to include Vulkan smoke test assets and project configuration. --- docs/ImportAll.hx | 24 +- project/src/ExternalInterface.cpp | 10825 +++++++++++----- .../_internal/backend/native/NativeCFFI.hx | 670 + src/lime/graphics/vulkan/VK.hx | 274 + src/lime/graphics/vulkan/VKAcquireResult.hx | 22 + src/lime/graphics/vulkan/VKBuffer.hx | 123 + src/lime/graphics/vulkan/VKCommandBuffer.hx | 235 + src/lime/graphics/vulkan/VKDescriptorPool.hx | 62 + .../graphics/vulkan/VKDescriptorPoolSize.hx | 13 + src/lime/graphics/vulkan/VKDescriptorSet.hx | 73 + .../graphics/vulkan/VKDescriptorSetLayout.hx | 44 + .../vulkan/VKDescriptorSetLayoutBinding.hx | 17 + src/lime/graphics/vulkan/VKDevice.hx | 382 + src/lime/graphics/vulkan/VKDeviceMemory.hx | 85 + src/lime/graphics/vulkan/VKFramebuffer.hx | 50 + .../graphics/vulkan/VKGraphicsPipelineInfo.hx | 77 + src/lime/graphics/vulkan/VKImage.hx | 165 + src/lime/graphics/vulkan/VKImageView.hx | 55 + .../graphics/vulkan/VKMemoryRequirements.hx | 32 + src/lime/graphics/vulkan/VKPipeline.hx | 46 + src/lime/graphics/vulkan/VKPipelineCache.hx | 44 + src/lime/graphics/vulkan/VKPipelineLayout.hx | 44 + src/lime/graphics/vulkan/VKQueue.hx | 42 + src/lime/graphics/vulkan/VKRenderPass.hx | 50 + src/lime/graphics/vulkan/VKSampler.hx | 44 + src/lime/graphics/vulkan/VKShaderModule.hx | 44 + src/lime/graphics/vulkan/VKSwapchain.hx | 140 + src/lime/graphics/vulkan/VKVertexAttribute.hx | 17 + src/lime/graphics/vulkan/VKVertexBinding.hx | 15 + .../vulkan-smoke/Assets/shaders/cube.frag.spv | Bin 0 -> 668 bytes .../vulkan-smoke/Assets/shaders/cube.vert.spv | Bin 0 -> 1456 bytes .../vulkan-smoke/Assets/shaders/quad.frag.spv | Bin 0 -> 660 bytes .../vulkan-smoke/Assets/shaders/quad.vert.spv | Bin 0 -> 1116 bytes tests/vulkan-smoke/Source/Main.hx | 883 +- tests/vulkan-smoke/project.xml | 1 + 35 files changed, 11594 insertions(+), 3004 deletions(-) create mode 100644 src/lime/graphics/vulkan/VKAcquireResult.hx create mode 100644 src/lime/graphics/vulkan/VKBuffer.hx create mode 100644 src/lime/graphics/vulkan/VKDescriptorPool.hx create mode 100644 src/lime/graphics/vulkan/VKDescriptorPoolSize.hx create mode 100644 src/lime/graphics/vulkan/VKDescriptorSet.hx create mode 100644 src/lime/graphics/vulkan/VKDescriptorSetLayout.hx create mode 100644 src/lime/graphics/vulkan/VKDescriptorSetLayoutBinding.hx create mode 100644 src/lime/graphics/vulkan/VKDeviceMemory.hx create mode 100644 src/lime/graphics/vulkan/VKFramebuffer.hx create mode 100644 src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx create mode 100644 src/lime/graphics/vulkan/VKImage.hx create mode 100644 src/lime/graphics/vulkan/VKImageView.hx create mode 100644 src/lime/graphics/vulkan/VKMemoryRequirements.hx create mode 100644 src/lime/graphics/vulkan/VKPipeline.hx create mode 100644 src/lime/graphics/vulkan/VKPipelineCache.hx create mode 100644 src/lime/graphics/vulkan/VKPipelineLayout.hx create mode 100644 src/lime/graphics/vulkan/VKRenderPass.hx create mode 100644 src/lime/graphics/vulkan/VKSampler.hx create mode 100644 src/lime/graphics/vulkan/VKShaderModule.hx create mode 100644 src/lime/graphics/vulkan/VKSwapchain.hx create mode 100644 src/lime/graphics/vulkan/VKVertexAttribute.hx create mode 100644 src/lime/graphics/vulkan/VKVertexBinding.hx create mode 100644 tests/vulkan-smoke/Assets/shaders/cube.frag.spv create mode 100644 tests/vulkan-smoke/Assets/shaders/cube.vert.spv create mode 100644 tests/vulkan-smoke/Assets/shaders/quad.frag.spv create mode 100644 tests/vulkan-smoke/Assets/shaders/quad.vert.spv diff --git a/docs/ImportAll.hx b/docs/ImportAll.hx index cd1be55208..a5032842a4 100644 --- a/docs/ImportAll.hx +++ b/docs/ImportAll.hx @@ -60,17 +60,39 @@ 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.VKRenderer; +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; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 7bab73d4a4..dff828e2ab 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -58,6 +58,7 @@ #endif #include +#include #include #include #include @@ -398,10 +399,19 @@ namespace lime { } - if (!requestedExtensions.empty ()) { + uint32_t extensionCount = 0; + VkResult extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, 0); + if (extensionResult != VK_SUCCESS) { - uint32_t extensionCount = 0; - VkResult extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, 0); + lastVKError = "Could not enumerate Vulkan device extensions"; + return false; + + } + + std::vector availableExtensions (extensionCount); + if (extensionCount > 0) { + + extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, availableExtensions.data ()); if (extensionResult != VK_SUCCESS) { lastVKError = "Could not enumerate Vulkan device extensions"; @@ -409,45 +419,64 @@ namespace lime { } - std::vector availableExtensions (extensionCount); - if (extensionCount > 0) { + } + + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + bool portabilitySubsetSupported = false; + bool portabilitySubsetRequested = false; + #endif + + for (size_t i = 0; i < requestedExtensions.size (); ++i) { + + bool extensionSupported = false; + + for (size_t e = 0; e < availableExtensions.size (); ++e) { - extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, availableExtensions.data ()); - if (extensionResult != VK_SUCCESS) { + if (strcmp (availableExtensions[e].extensionName, requestedExtensions[i].c_str ()) == 0) { - lastVKError = "Could not enumerate Vulkan device extensions"; - return false; + extensionSupported = true; + break; } } - for (size_t i = 0; i < requestedExtensions.size (); ++i) { + if (!extensionSupported) { - bool extensionSupported = false; + lastVKError = std::string ("Vulkan physical device does not support ") + requestedExtensions[i]; + return false; - for (size_t e = 0; e < availableExtensions.size (); ++e) { + } - if (strcmp (availableExtensions[e].extensionName, requestedExtensions[i].c_str ()) == 0) { + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + if (strcmp (requestedExtensions[i].c_str (), VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) { - extensionSupported = true; - break; + portabilitySubsetRequested = true; - } + } + #endif - } + } - if (!extensionSupported) { + #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + for (size_t i = 0; i < availableExtensions.size (); ++i) { - lastVKError = std::string ("Vulkan physical device does not support ") + requestedExtensions[i]; - return false; + if (strcmp (availableExtensions[i].extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) { - } + portabilitySubsetSupported = true; + break; } } + if (portabilitySubsetSupported && !portabilitySubsetRequested) { + + deviceExtensions.push_back (VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + + } + #endif + VkPhysicalDeviceFeatures deviceFeatures; memset (&deviceFeatures, 0, sizeof (deviceFeatures)); @@ -494,797 +523,907 @@ namespace lime { return true; } -#endif - void gc_application (value handle) { + struct ManagedVulkanSwapchain { - Application* application = (Application*)val_data (handle); - delete application; + VkSwapchainKHR handle; + VkFormat format; + VkColorSpaceKHR colorSpace; + VkExtent2D extent; + VkPresentModeKHR presentMode; + uint32_t imageCount; - } + }; - void hl_gc_application (HL_CFFIPointer* handle) { + static VkPresentModeKHR ChooseManagedVulkanPresentMode (const std::vector& presentModes, VkPresentModeKHR requestedPresentMode) { - Application* application = (Application*)handle->ptr; - delete application; + 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; - void gc_file_watcher (value handle) { + } - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - delete watcher; - #endif + 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; } - void hl_gc_file_watcher (HL_CFFIPointer* handle) { + static value CreateVulkanSwapchainValue (const ManagedVulkanSwapchain& swapchain) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - delete watcher; - #endif + 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; } - void gc_font (value handle) { + static vdynamic* HLCreateVulkanSwapchainValue (const ManagedVulkanSwapchain& swapchain) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (handle); - delete font; - #endif + 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"); + + 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; } - void hl_gc_font (HL_CFFIPointer* handle) { + static value CreateVulkanAcquireValue (VkResult acquireResult, int imageIndex) { - #ifdef LIME_FREETYPE - Font* font = (Font*)handle->ptr; - delete font; - #endif + 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; } - void gc_window (value handle) { + static vdynamic* HLCreateVulkanAcquireValue (VkResult acquireResult, int imageIndex) { - Window* window = (Window*)val_data (handle); - delete window; + const int id_result = hl_hash_utf8 ("result"); + const int id_imageIndex = hl_hash_utf8 ("imageIndex"); + + 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; } - void hl_gc_window (HL_CFFIPointer* handle) { + static value CreateVulkanMemoryRequirementsValue (const VkMemoryRequirements& requirements) { - Window* window = (Window*)handle->ptr; - delete window; + 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; } - std::string wstring_utf8 (const std::wstring& val) { + static vdynamic* HLCreateVulkanMemoryRequirementsValue (const VkMemoryRequirements& requirements) { - std::string out; - unsigned int codepoint = 0; + const int id_size = hl_hash_utf8 ("size"); + const int id_alignment = hl_hash_utf8 ("alignment"); + const int id_memoryTypeBits = hl_hash_utf8 ("memoryTypeBits"); - for (const wchar_t chr : val) { + 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; - if (chr >= 0xd800 && chr <= 0xdbff) { + } - codepoint = ((chr - 0xd800) << 10) + 0x10000; - } else { + static value CreateVulkanMemoryValue (VkDeviceMemory memory, uint32_t memoryTypeIndex) { - if (chr >= 0xdc00 && chr <= 0xdfff) { + 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; - codepoint |= chr - 0xdc00; + } - } else { - codepoint = chr; + static vdynamic* HLCreateVulkanMemoryValue (VkDeviceMemory memory, uint32_t memoryTypeIndex) { - } + const int id_handle = hl_hash_utf8 ("handle"); + const int id_memoryTypeIndex = hl_hash_utf8 ("memoryTypeIndex"); - if (codepoint <= 0x7f) { + 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; - out.append (1, static_cast (codepoint)); + } - } else if (codepoint <= 0x7ff) { - out.append (1, static_cast (0xc0 | ((codepoint >> 6) & 0x1f))); - out.append (1, static_cast (0x80 | (codepoint & 0x3f))); + static std::vector GetVulkanIntVector (value data) { - } else if (codepoint <= 0xffff) { + std::vector result; + if (val_is_null (data)) return result; - 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))); + int length = val_array_size (data); + result.reserve (length); + for (int i = 0; i < length; ++i) { - } else { + result.push_back (val_int (val_array_i (data, i))); - 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))); + } - } + return result; - codepoint = 0; + } - } - } + static std::vector GetHLVulkanIntVector (hl_varray* data) { - return out; + std::vector result; + if (!data) return result; - } + result.reserve (data->size); + int* values = hl_aptr (data, int); + for (int i = 0; i < data->size; ++i) { + result.push_back (values[i]); - 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; + return result; } - std::wstring* hxstring_to_wstring (HxString val) { - - if (val.c_str ()) { + static std::vector GetVulkanDoubleVector (value data) { - #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 + 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; + } - std::wstring* hxstring_to_wstring (hl_vstring* val) { - if (val) { + static std::vector GetHLVulkanDoubleVector (hl_varray* data) { - 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 + std::vector result; + if (!data) return result; - } else { + result.reserve (data->size); + double* values = hl_aptr (data, double); + for (int i = 0; i < data->size; ++i) { - return 0; + result.push_back (values[i]); } - } - + return result; - value wstring_to_value (std::wstring* val) { + } - if (val) { - #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 ()); - #endif + static bool FindManagedVulkanMemoryType (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t typeFilter, + VkMemoryPropertyFlags properties, uint32_t* outMemoryTypeIndex) { - } else { + if (!targetWindow || !instance || !physicalDevice || !outMemoryTypeIndex) { - return 0; + lastVKError = "Missing Vulkan window, instance, physical device, or memory type output"; + return false; } - } + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; - value lime_application_create () { + } - Application* application = CreateApplication (); - return CFFIPointer (application, gc_application); + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = + (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceMemoryProperties"); + if (!vkGetPhysicalDeviceMemoryProperties) { - } + lastVKError = "Missing Vulkan physical device memory properties function"; + return false; + } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_application_create) () { + VkPhysicalDeviceMemoryProperties memoryProperties; + memset (&memoryProperties, 0, sizeof (memoryProperties)); + vkGetPhysicalDeviceMemoryProperties (physicalDevice, &memoryProperties); - Application* application = CreateApplication (); - return HLCFFIPointer (application, (hl_finalizer)hl_gc_application); + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { - } + if ((typeFilter & (1u << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { + *outMemoryTypeIndex = i; + lastVKError.clear (); + return true; - void lime_application_event_manager_register (value callback, value eventObject) { + } - ApplicationEvent::callback = new ValuePointer (callback); - ApplicationEvent::eventObject = new ValuePointer (eventObject); + } + + lastVKError = "Failed to find a compatible Vulkan memory type"; + return false; } - HL_PRIM void HL_NAME(hl_application_event_manager_register) (vclosure* callback, ApplicationEvent* eventObject) { + 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) { - ApplicationEvent::callback = new ValuePointer (callback); - ApplicationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + if (!targetWindow || !instance || !physicalDevice || !device || !surface || !outSwapchain) { - } + lastVKError = "Missing Vulkan window, instance, device, surface, or output swapchain"; + return false; + } - int lime_application_exec (value application) { + 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; - Application* app = (Application*)val_data (application); - return app->Exec (); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); + if (!vkGetInstanceProcAddr) { - } + lastVKError = "SDL did not expose vkGetInstanceProcAddr"; + return false; + } - HL_PRIM int HL_NAME(hl_application_exec) (HL_CFFIPointer* application) { + 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"); - Application* app = (Application*)application->ptr; - return app->Exec (); + if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR || !vkGetPhysicalDeviceSurfacePresentModesKHR) { - } + lastVKError = "Missing required Vulkan surface functions"; + return false; + } - void lime_application_init (value application) { + if (vkGetPhysicalDeviceSurfaceSupportKHR) { - Application* app = (Application*)val_data (application); - app->Init (); + 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; + } - HL_PRIM void HL_NAME(hl_application_init) (HL_CFFIPointer* application) { + } - Application* app = (Application*)application->ptr; - app->Init (); + VkSurfaceCapabilitiesKHR capabilities; + memset (&capabilities, 0, sizeof (capabilities)); + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physicalDevice, surface, &capabilities); + if (result != VK_SUCCESS) { - } + lastVKError = "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"; + return false; + } - int lime_application_quit (value application) { + uint32_t formatCount = 0; + result = vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, 0); + if (result != VK_SUCCESS || formatCount == 0) { - Application* app = (Application*)val_data (application); - return app->Quit (); + lastVKError = "Failed to query Vulkan surface formats"; + return false; - } + } + std::vector formats (formatCount); + result = vkGetPhysicalDeviceSurfaceFormatsKHR (physicalDevice, surface, &formatCount, formats.data ()); + if (result != VK_SUCCESS) { - HL_PRIM int HL_NAME(hl_application_quit) (HL_CFFIPointer* application) { + lastVKError = "vkGetPhysicalDeviceSurfaceFormatsKHR failed"; + return false; - Application* app = (Application*)application->ptr; - return app->Quit (); + } - } + VkSurfaceFormatKHR surfaceFormat = formats[0]; + if (formats.size () == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { + surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; + surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - void lime_application_set_frame_rate (value application, double frameRate) { + } else { - Application* app = (Application*)val_data (application); - app->SetFrameRate (frameRate); + 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; - HL_PRIM void HL_NAME(hl_application_set_frame_rate) (HL_CFFIPointer* application, double frameRate) { + } - Application* app = (Application*)application->ptr; - app->SetFrameRate (frameRate); + } - } + } + uint32_t presentModeCount = 0; + result = vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice, surface, &presentModeCount, 0); + if (result != VK_SUCCESS) { - void lime_application_set_main_loop (value application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + lastVKError = "Failed to query Vulkan present modes"; + return false; - Application* app = (Application*)val_data (application); - app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + } - } + 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) { - HL_PRIM void HL_NAME(hl_application_set_main_loop) (HL_CFFIPointer* application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { + lastVKError = "vkGetPhysicalDeviceSurfacePresentModesKHR failed"; + return false; - Application* app = (Application*)application->ptr; - app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); + } - } + } + int drawableWidth = requestedWidth; + int drawableHeight = requestedHeight; + if (drawableWidth <= 0 || drawableHeight <= 0) { - void lime_application_set_vsync_mode (value application, int vsyncMode) { + drawableWidth = 0; + drawableHeight = 0; + targetWindow->GetVulkanDrawableSize (&drawableWidth, &drawableHeight); - Application* app = (Application*)val_data (application); - app->SetVSyncMode (vsyncMode); + } - } + if (drawableWidth <= 0 || drawableHeight <= 0) { + lastVKError = "Vulkan drawable size is zero"; + return false; - HL_PRIM void HL_NAME(hl_application_set_vsync_mode) (HL_CFFIPointer* application, int vsyncMode) { + } - Application* app = (Application*)application->ptr; - app->SetVSyncMode (vsyncMode); + VkExtent2D extent; + if (capabilities.currentExtent.width != UINT32_MAX) { - } + extent = capabilities.currentExtent; + } else { - bool lime_application_update (value application) { + 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)); - Application* app = (Application*)val_data (application); - return app->Update (); + } - } + if ((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) { + + lastVKError = "Vulkan surface images do not support color attachments"; + return false; + } - HL_PRIM bool HL_NAME(hl_application_update) (HL_CFFIPointer* application) { + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { - Application* app = (Application*)application->ptr; - return app->Update (); + imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } + } + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { - value lime_audio_load_bytes (value data, value buffer) { + imageCount = capabilities.maxImageCount; - Resource resource; - Bytes bytes; + } - AudioBuffer audioBuffer = AudioBuffer (buffer); + VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + const VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = { + 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 + }; - bytes.Set (data); - resource = Resource (&bytes); + for (size_t i = 0; i < sizeof (compositeAlphaFlags) / sizeof (compositeAlphaFlags[0]); ++i) { - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, &audioBuffer)) { + if (capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { - return audioBuffer.Value (buffer); + compositeAlpha = compositeAlphaFlags[i]; + break; + + } } - #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; - if (WAV::Decode (&resource, &audioBuffer)) { + 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) { - return audioBuffer.Value (buffer); + lastVKError = "vkCreateSwapchainKHR failed"; + return false; } - #ifdef LIME_OGG - if (OGG::Decode (&resource, &audioBuffer)) { + uint32_t swapchainImageCount = 0; + result = vkGetSwapchainImagesKHR (device, swapchain, &swapchainImageCount, 0); + if (result != VK_SUCCESS || swapchainImageCount == 0) { - return audioBuffer.Value (buffer); + 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; } - #endif - return alloc_null (); + 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; } +#endif - HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_bytes) (Bytes* data, AudioBuffer* buffer) { - - Resource resource = Resource (data); + void gc_application (value handle) { - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, buffer)) { + Application* application = (Application*)val_data (handle); + delete application; - return buffer; + } - } - #endif - if (WAV::Decode (&resource, buffer)) { + void hl_gc_application (HL_CFFIPointer* handle) { - return buffer; + Application* application = (Application*)handle->ptr; + delete application; - } + } - #ifdef LIME_OGG - if (OGG::Decode (&resource, buffer)) { - return buffer; + void gc_file_watcher (value handle) { - } + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + delete watcher; #endif - return 0; - } - value lime_audio_load_file (value data, value buffer) { - - Resource resource; + void hl_gc_file_watcher (HL_CFFIPointer* handle) { - AudioBuffer audioBuffer = AudioBuffer (buffer); + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + delete watcher; + #endif - resource = Resource (val_string (data)); + } - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, &audioBuffer)) { - return audioBuffer.Value (buffer); + void gc_font (value handle) { - } + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (handle); + delete font; #endif - if (WAV::Decode (&resource, &audioBuffer)) { - - return audioBuffer.Value (buffer); - - } + } - #ifdef LIME_OGG - if (OGG::Decode (&resource, &audioBuffer)) { - return audioBuffer.Value (buffer); + void hl_gc_font (HL_CFFIPointer* handle) { - } + #ifdef LIME_FREETYPE + Font* font = (Font*)handle->ptr; + delete font; #endif - return alloc_null (); - } - HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_file) (hl_vstring* data, AudioBuffer* buffer) { + void gc_window (value handle) { - Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + Window* window = (Window*)val_data (handle); + delete window; - #ifdef LIME_SDL_SOUND - if (SDLSound::Decode (&resource, buffer)) { + } - return buffer; - } - #endif + void hl_gc_window (HL_CFFIPointer* handle) { - if (WAV::Decode (&resource, buffer)) { + Window* window = (Window*)handle->ptr; + delete window; - return buffer; + } - } - #ifdef LIME_OGG - if (OGG::Decode (&resource, buffer)) { + std::string wstring_utf8 (const std::wstring& val) { - return buffer; + std::string out; + unsigned int codepoint = 0; - } - #endif + for (const wchar_t chr : val) { - return 0; + if (chr >= 0xd800 && chr <= 0xdbff) { - } + codepoint = ((chr - 0xd800) << 10) + 0x10000; + } else { - value lime_audio_load (value data, value buffer) { + if (chr >= 0xdc00 && chr <= 0xdfff) { - if (val_is_string (data)) { + codepoint |= chr - 0xdc00; - return lime_audio_load_file (data, buffer); + } else { - } else { + codepoint = chr; - return lime_audio_load_bytes (data, buffer); + } - } + if (codepoint <= 0x7f) { - } + out.append (1, static_cast (codepoint)); + } else if (codepoint <= 0x7ff) { - value lime_bytes_from_data_pointer (double data, int length, value _bytes) { + out.append (1, static_cast (0xc0 | ((codepoint >> 6) & 0x1f))); + out.append (1, static_cast (0x80 | (codepoint & 0x3f))); - uintptr_t ptr = (uintptr_t)data; - Bytes bytes (_bytes); - bytes.Resize (length); + } else if (codepoint <= 0xffff) { - if (ptr) { + 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))); - memcpy (bytes.b, (const void*)ptr, length); + } 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))); - return bytes.Value (_bytes); + } - } + codepoint = 0; + } - 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); + return out; - if (ptr) { + } - memcpy (bytes->b, (const void*)ptr, length); - } + 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; } - double lime_bytes_get_data_pointer (value bytes) { + std::wstring* hxstring_to_wstring (HxString val) { - Bytes data = Bytes (bytes); - return (uintptr_t)data.b; + if (val.c_str ()) { - } + #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 { - HL_PRIM double HL_NAME(hl_bytes_get_data_pointer) (Bytes* bytes) { + return 0; - 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; + std::wstring* hxstring_to_wstring (hl_vstring* val) { - Bytes data = Bytes (bytes); - return (uintptr_t)data.b + offset; + if (val) { - } + 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 + } else { - HL_PRIM double HL_NAME(hl_bytes_get_data_pointer_offset) (Bytes* bytes, int offset) { + return 0; - if (!bytes) return 0; - return (uintptr_t)bytes->b + offset; + } } - value lime_bytes_read_file (HxString path, value bytes) { + value wstring_to_value (std::wstring* val) { - Bytes data (bytes); - data.ReadFile (hxs_utf8 (path, nullptr)); - return data.Value (bytes); + if (val) { - } + #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 ()); + #endif + } else { - HL_PRIM Bytes* HL_NAME(hl_bytes_read_file) (hl_vstring* path, Bytes* bytes) { + return 0; - if (!path) return 0; - bytes->ReadFile (hl_to_utf8 ((const uchar*)path->bytes)); - return bytes; + } } - double lime_cffi_get_native_pointer (value handle) { + value lime_application_create () { - return (uintptr_t)val_data (handle); + Application* application = CreateApplication (); + return CFFIPointer (application, gc_application); } - HL_PRIM double HL_NAME(hl_cffi_get_native_pointer) (HL_CFFIPointer* handle) { + HL_PRIM HL_CFFIPointer* HL_NAME(hl_application_create) () { - return (uintptr_t)handle->ptr; + Application* application = CreateApplication (); + return HLCFFIPointer (application, (hl_finalizer)hl_gc_application); } - void lime_cffi_finalizer (value abstract) { + void lime_application_event_manager_register (value callback, value eventObject) { - val_call0 ((value)val_data (abstract)); + ApplicationEvent::callback = new ValuePointer (callback); + ApplicationEvent::eventObject = new ValuePointer (eventObject); } - value lime_cffi_set_finalizer (value callback) { + HL_PRIM void HL_NAME(hl_application_event_manager_register) (vclosure* callback, ApplicationEvent* eventObject) { - value abstract = alloc_abstract (k_finalizer, callback); - val_gc (abstract, lime_cffi_finalizer); - return abstract; + ApplicationEvent::callback = new ValuePointer (callback); + ApplicationEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - void lime_clipboard_event_manager_register (value callback, value eventObject) { + int lime_application_exec (value application) { - ClipboardEvent::callback = new ValuePointer (callback); - ClipboardEvent::eventObject = new ValuePointer (eventObject); + Application* app = (Application*)val_data (application); + return app->Exec (); } - HL_PRIM void HL_NAME(hl_clipboard_event_manager_register) (vclosure* callback, ClipboardEvent* eventObject) { + HL_PRIM int HL_NAME(hl_application_exec) (HL_CFFIPointer* application) { - ClipboardEvent::callback = new ValuePointer (callback); - ClipboardEvent::eventObject = new ValuePointer ((vobj*)eventObject); + Application* app = (Application*)application->ptr; + return app->Exec (); } - 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 (); + void lime_application_init (value application) { - } + Application* app = (Application*)val_data (application); + app->Init (); } - HL_PRIM vbyte* HL_NAME(hl_clipboard_get_text) () { + HL_PRIM void HL_NAME(hl_application_init) (HL_CFFIPointer* application) { - if (Clipboard::HasText ()) { + Application* app = (Application*)application->ptr; + app->Init (); - const char* text = Clipboard::GetText (); - return (vbyte*)text; + } - } else { - return 0; + int lime_application_quit (value application) { - } + Application* app = (Application*)val_data (application); + return app->Quit (); } - void lime_clipboard_set_text (HxString text) { + HL_PRIM int HL_NAME(hl_application_quit) (HL_CFFIPointer* application) { - Clipboard::SetText (hxs_utf8 (text, nullptr)); + Application* app = (Application*)application->ptr; + return app->Quit (); } - HL_PRIM void HL_NAME(hl_clipboard_set_text) (hl_vstring* text) { + void lime_application_set_frame_rate (value application, double frameRate) { - Clipboard::SetText (text ? (const char*)hl_to_utf8 ((const uchar*)text->bytes) : NULL); + Application* app = (Application*)val_data (application); + app->SetFrameRate (frameRate); } - double lime_data_pointer_offset (double pointer, int offset) { + HL_PRIM void HL_NAME(hl_application_set_frame_rate) (HL_CFFIPointer* application, double frameRate) { - return (uintptr_t)pointer + offset; + Application* app = (Application*)application->ptr; + app->SetFrameRate (frameRate); } - HL_PRIM double HL_NAME(hl_data_pointer_offset) (double pointer, int offset) { + void lime_application_set_main_loop (value application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { - return (uintptr_t)pointer + offset; + Application* app = (Application*)val_data (application); + app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); } - value lime_deflate_compress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Compress (DEFLATE, &data, &result); + HL_PRIM void HL_NAME(hl_application_set_main_loop) (HL_CFFIPointer* application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { - return result.Value (bytes); - #else - return alloc_null(); - #endif + Application* app = (Application*)application->ptr; + app->SetMainLoop (profile, frameRate, timePrecision, busyWait, uncapMode); } - HL_PRIM Bytes* HL_NAME(hl_deflate_compress) (Bytes* buffer, Bytes* bytes) { + void lime_application_set_vsync_mode (value application, int vsyncMode) { - #ifdef LIME_ZLIB - Zlib::Compress (DEFLATE, buffer, bytes); - return bytes; - #else - return 0; - #endif + Application* app = (Application*)val_data (application); + app->SetVSyncMode (vsyncMode); } - value lime_deflate_decompress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Decompress (DEFLATE, &data, &result); + HL_PRIM void HL_NAME(hl_application_set_vsync_mode) (HL_CFFIPointer* application, int vsyncMode) { - return result.Value (bytes); - #else - return alloc_null (); - #endif + Application* app = (Application*)application->ptr; + app->SetVSyncMode (vsyncMode); } - HL_PRIM Bytes* HL_NAME(hl_deflate_decompress) (Bytes* buffer, Bytes* bytes) { + bool lime_application_update (value application) { - #ifdef LIME_ZLIB - Zlib::Decompress (DEFLATE, buffer, bytes); - return bytes; - #else - return 0; - #endif + Application* app = (Application*)val_data (application); + return app->Update (); } - void lime_drop_event_manager_register (value callback, value eventObject) { + HL_PRIM bool HL_NAME(hl_application_update) (HL_CFFIPointer* application) { - DropEvent::callback = new ValuePointer (callback); - DropEvent::eventObject = new ValuePointer (eventObject); + Application* app = (Application*)application->ptr; + return app->Update (); } - HL_PRIM void HL_NAME(hl_drop_event_manager_register) (vclosure* callback, DropEvent* eventObject) { + value lime_audio_load_bytes (value data, value buffer) { - DropEvent::callback = new ValuePointer (callback); - DropEvent::eventObject = new ValuePointer ((vobj*)eventObject); + Resource resource; + Bytes bytes; - } + AudioBuffer audioBuffer = AudioBuffer (buffer); + bytes.Set (data); + resource = Resource (&bytes); - value lime_file_dialog_open_directory (HxString title, HxString filter, HxString defaultPath) { + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, &audioBuffer)) { - #ifdef LIME_TINYFILEDIALOGS + return audioBuffer.Value (buffer); - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + } + #endif - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + if (WAV::Decode (&resource, &audioBuffer)) { - if (path) { + return audioBuffer.Value (buffer); - value _path = wstring_to_value (path); - delete path; - return _path; + } - } else { + #ifdef LIME_OGG + if (OGG::Decode (&resource, &audioBuffer)) { - return alloc_null (); + return audioBuffer.Value (buffer); } - #endif return alloc_null (); @@ -1292,448 +1431,334 @@ namespace lime { } - HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_directory) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_bytes) (Bytes* data, AudioBuffer* buffer) { - #ifdef LIME_TINYFILEDIALOGS + Resource resource = Resource (data); - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, buffer)) { - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); + return buffer; - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + } + #endif - if (path) { + if (WAV::Decode (&resource, buffer)) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + return buffer; - } else { + } - return NULL; + #ifdef LIME_OGG + if (OGG::Decode (&resource, buffer)) { - } + return buffer; + } #endif - return NULL; + return 0; } - value lime_file_dialog_open_file (HxString title, HxString filter, HxString defaultPath) { + value lime_audio_load_file (value data, value buffer) { - #ifdef LIME_TINYFILEDIALOGS + Resource resource; - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + AudioBuffer audioBuffer = AudioBuffer (buffer); - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); + resource = Resource (val_string (data)); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, &audioBuffer)) { - if (path) { + return audioBuffer.Value (buffer); - value _path = wstring_to_value (path); - delete path; - return _path; + } + #endif - } else { + if (WAV::Decode (&resource, &audioBuffer)) { - return alloc_null (); + return audioBuffer.Value (buffer); } - #endif + #ifdef LIME_OGG + if (OGG::Decode (&resource, &audioBuffer)) { - return alloc_null (); + return audioBuffer.Value (buffer); - } + } + #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 - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + HL_PRIM AudioBuffer* HL_NAME(hl_audio_load_file) (hl_vstring* data, AudioBuffer* buffer) { - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); + Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + #ifdef LIME_SDL_SOUND + if (SDLSound::Decode (&resource, buffer)) { - if (path) { + return buffer; - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + } + #endif - } else { + if (WAV::Decode (&resource, buffer)) { - return NULL; + return buffer; } + #ifdef LIME_OGG + if (OGG::Decode (&resource, buffer)) { + + return buffer; + + } #endif - return NULL; + return 0; } - value lime_file_dialog_open_files (HxString title, HxString filter, HxString defaultPath) { - - #ifdef LIME_TINYFILEDIALOGS + value lime_audio_load (value data, value buffer) { - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + if (val_is_string (data)) { - std::vector files; + return lime_audio_load_file (data, buffer); - FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); - value result = alloc_array (files.size ()); + } else { - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + return lime_audio_load_bytes (data, buffer); - for (int i = 0; i < files.size (); i++) { + } - value _file = wstring_to_value (files[i]); - val_array_set_i (result, i, _file); - delete files[i]; + } - } - #else - value result = alloc_array (0); - #endif + value lime_bytes_from_data_pointer (double data, int length, value _bytes) { - return result; + uintptr_t ptr = (uintptr_t)data; + Bytes bytes (_bytes); + bytes.Resize (length); - } + if (ptr) { + memcpy (bytes.b, (const void*)ptr, length); - HL_PRIM hl_varray* HL_NAME(hl_file_dialog_open_files) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { + } - #ifdef LIME_TINYFILEDIALOGS + return bytes.Value (_bytes); - 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*); + HL_PRIM Bytes* HL_NAME(hl_bytes_from_data_pointer) (double data, int length, Bytes* bytes) { - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + uintptr_t ptr = (uintptr_t)data; + bytes->Resize (length); - for (int i = 0; i < files.size (); i++) { + if (ptr) { - *resultData++ = hl_wstring_to_utf8_bytes (*files[i]); - delete files[i]; + memcpy (bytes->b, (const void*)ptr, length); } - #else - hl_varray* result = hl_alloc_array (&hlt_bytes, 0); - #endif - - return result; + return bytes; } - value lime_file_dialog_save_file (HxString title, HxString filter, HxString defaultPath) { - - #ifdef LIME_TINYFILEDIALOGS + double lime_bytes_get_data_pointer (value bytes) { - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + Bytes data = Bytes (bytes); + return (uintptr_t)data.b; - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); + } - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - if (path) { + HL_PRIM double HL_NAME(hl_bytes_get_data_pointer) (Bytes* bytes) { - value _path = wstring_to_value (path); - delete path; - return _path; + return bytes ? (uintptr_t)bytes->b : 0; - } else { + } - return alloc_null (); - } + double lime_bytes_get_data_pointer_offset (value bytes, int offset) { - #endif + if (val_is_null (bytes)) return 0; - return alloc_null (); + Bytes data = Bytes (bytes); + return (uintptr_t)data.b + offset; } - HL_PRIM vbyte* HL_NAME(hl_file_dialog_save_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { - - #ifdef LIME_TINYFILEDIALOGS - - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); + HL_PRIM double HL_NAME(hl_bytes_get_data_pointer_offset) (Bytes* bytes, int offset) { - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); + if (!bytes) return 0; + return (uintptr_t)bytes->b + offset; - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + } - if (path) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + value lime_bytes_read_file (HxString path, value bytes) { - } else { + Bytes data (bytes); + data.ReadFile (hxs_utf8 (path, nullptr)); + return data.Value (bytes); - return NULL; + } - } - #endif + HL_PRIM Bytes* HL_NAME(hl_bytes_read_file) (hl_vstring* path, Bytes* bytes) { - return NULL; + if (!path) return 0; + bytes->ReadFile (hl_to_utf8 ((const uchar*)path->bytes)); + return bytes; } - value lime_file_watcher_create (value callback) { + double lime_cffi_get_native_pointer (value handle) { - #ifdef LIME_EFSW - FileWatcher* watcher = new FileWatcher (callback); - return CFFIPointer (watcher, gc_file_watcher); - #else - return alloc_null (); - #endif + return (uintptr_t)val_data (handle); } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_file_watcher_create) (vclosure* callback) { + HL_PRIM double HL_NAME(hl_cffi_get_native_pointer) (HL_CFFIPointer* handle) { - // #ifdef LIME_EFSW - // FileWatcher* watcher = new FileWatcher (callback); - // return HLCFFIPointer (watcher, (hl_finalizer)hl_gc_file_watcher); - // #else - return 0; - // #endif + return (uintptr_t)handle->ptr; } - value lime_file_watcher_add_directory (value handle, value path, bool recursive) { + void lime_cffi_finalizer (value abstract) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - return alloc_int (watcher->AddDirectory (val_string (path), recursive)); - #else - return alloc_int (0); - #endif + val_call0 ((value)val_data (abstract)); } - HL_PRIM int HL_NAME(hl_file_watcher_add_directory) (HL_CFFIPointer* handle, hl_vstring* path, bool recursive) { + value lime_cffi_set_finalizer (value callback) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - return watcher->AddDirectory ((const char*)path, recursive); - #else - return 0; - #endif + value abstract = alloc_abstract (k_finalizer, callback); + val_gc (abstract, lime_cffi_finalizer); + return abstract; } - void lime_file_watcher_remove_directory (value handle, value watchID) { + void lime_clipboard_event_manager_register (value callback, value eventObject) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - watcher->RemoveDirectory (val_int (watchID)); - #endif + ClipboardEvent::callback = new ValuePointer (callback); + ClipboardEvent::eventObject = new ValuePointer (eventObject); } - HL_PRIM void HL_NAME(hl_file_watcher_remove_directory) (HL_CFFIPointer* handle, int watchID) { + HL_PRIM void HL_NAME(hl_clipboard_event_manager_register) (vclosure* callback, ClipboardEvent* eventObject) { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - watcher->RemoveDirectory (watchID); - #endif + ClipboardEvent::callback = new ValuePointer (callback); + ClipboardEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - void lime_file_watcher_update (value handle) { + value lime_clipboard_get_text () { - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)val_data (handle); - watcher->Update (); - #endif + if (Clipboard::HasText ()) { - } + const char* text = Clipboard::GetText (); + value _text = alloc_string (text); + // TODO: Should we free for all backends? (SDL requires it) - HL_PRIM void HL_NAME(hl_file_watcher_update) (HL_CFFIPointer* handle) { + free ((char*)text); + return _text; - #ifdef LIME_EFSW - FileWatcher* watcher = (FileWatcher*)handle->ptr; - watcher->Update (); - #endif + } else { - } + return alloc_null (); + } - 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 vbyte* HL_NAME(hl_clipboard_get_text) () { + if (Clipboard::HasText ()) { - 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 - - } + const char* text = Clipboard::GetText (); + return (vbyte*)text; + } else { - int lime_font_get_descender (value fontHandle) { + return 0; - #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) { + void lime_clipboard_set_text (HxString text) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetDescender (); - #else - return 0; - #endif + Clipboard::SetText (hxs_utf8 (text, nullptr)); } - value lime_font_get_family_name (value fontHandle) { + HL_PRIM void HL_NAME(hl_clipboard_set_text) (hl_vstring* text) { - #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 + Clipboard::SetText (text ? (const char*)hl_to_utf8 ((const uchar*)text->bytes) : NULL); } - HL_PRIM vbyte* HL_NAME(hl_font_get_family_name) (HL_CFFIPointer* fontHandle) { + double lime_data_pointer_offset (double pointer, int offset) { - #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 + return (uintptr_t)pointer + offset; } - int lime_font_get_glyph_index (value fontHandle, HxString character) { + HL_PRIM double HL_NAME(hl_data_pointer_offset) (double pointer, int offset) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetGlyphIndex (hxs_utf8 (character, nullptr)); - #else - return -1; - #endif + return (uintptr_t)pointer + offset; } - 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_deflate_compress (value buffer, value bytes) { + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); - value lime_font_get_glyph_indices (value fontHandle, HxString characters) { + Zlib::Compress (DEFLATE, &data, &result); - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->GetGlyphIndices (true, hxs_utf8 (characters, nullptr)); + return result.Value (bytes); #else - return alloc_null (); + return alloc_null(); #endif } - HL_PRIM hl_varray* HL_NAME(hl_font_get_glyph_indices) (HL_CFFIPointer* fontHandle, hl_vstring* characters) { + HL_PRIM Bytes* HL_NAME(hl_deflate_compress) (Bytes* buffer, Bytes* bytes) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (hl_varray*)font->GetGlyphIndices (false, characters ? (char*)hl_to_utf8 ((const uchar*)characters->bytes) : NULL); + #ifdef LIME_ZLIB + Zlib::Compress (DEFLATE, buffer, bytes); + return bytes; #else return 0; #endif @@ -1741,11 +1766,15 @@ namespace lime { } - value lime_font_get_glyph_metrics (value fontHandle, int index) { + value lime_deflate_decompress (value buffer, value bytes) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->GetGlyphMetrics (true, index); + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); + + Zlib::Decompress (DEFLATE, &data, &result); + + return result.Value (bytes); #else return alloc_null (); #endif @@ -1753,11 +1782,11 @@ namespace lime { } - HL_PRIM vdynamic* HL_NAME(hl_font_get_glyph_metrics) (HL_CFFIPointer* fontHandle, int index) { + HL_PRIM Bytes* HL_NAME(hl_deflate_decompress) (Bytes* buffer, Bytes* bytes) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->GetGlyphMetrics (false, index); + #ifdef LIME_ZLIB + Zlib::Decompress (DEFLATE, buffer, bytes); + return bytes; #else return 0; #endif @@ -1765,252 +1794,248 @@ namespace lime { } - int lime_font_get_height (value fontHandle) { + void lime_drop_event_manager_register (value callback, value eventObject) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetHeight (); - #else - return 0; - #endif + DropEvent::callback = new ValuePointer (callback); + DropEvent::eventObject = new ValuePointer (eventObject); } - HL_PRIM int HL_NAME(hl_font_get_height) (HL_CFFIPointer* fontHandle) { + HL_PRIM void HL_NAME(hl_drop_event_manager_register) (vclosure* callback, DropEvent* eventObject) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetHeight (); - #else - return 0; - #endif + DropEvent::callback = new ValuePointer (callback); + DropEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - int lime_font_get_num_glyphs (value fontHandle) { + value lime_file_dialog_open_directory (HxString title, HxString filter, HxString defaultPath) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetNumGlyphs (); - #else - return 0; - #endif + #ifdef LIME_TINYFILEDIALOGS - } + 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); - HL_PRIM int HL_NAME(hl_font_get_num_glyphs) (HL_CFFIPointer* fontHandle) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetNumGlyphs (); - #else - return 0; - #endif + if (path) { - } + value _path = wstring_to_value (path); + delete path; + return _path; + } else { - int lime_font_get_underline_position (value fontHandle) { + return alloc_null (); + + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnderlinePosition (); - #else - return 0; #endif + return alloc_null (); + } - HL_PRIM int HL_NAME(hl_font_get_underline_position) (HL_CFFIPointer* fontHandle) { + HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_directory) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnderlinePosition (); - #else - return 0; - #endif + #ifdef LIME_TINYFILEDIALOGS - } + 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); - int lime_font_get_underline_thickness (value fontHandle) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnderlineThickness (); - #else - return 0; - #endif + if (path) { - } + vbyte* const result = hl_wstring_to_utf8_bytes (*path); + delete path; + return result; + } else { - HL_PRIM int HL_NAME(hl_font_get_underline_thickness) (HL_CFFIPointer* fontHandle) { + return NULL; + + } - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnderlineThickness (); - #else - return 0; #endif + return NULL; + } - int lime_font_get_strikethrough_position (value fontHandle) { + value lime_file_dialog_open_file (HxString title, HxString filter, HxString defaultPath) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetStrikethroughPosition (); - #else - return 0; - #endif + #ifdef LIME_TINYFILEDIALOGS - } + 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::OpenFile (_title, _filter, _defaultPath); - HL_PRIM int HL_NAME(hl_font_get_strikethrough_position) (HL_CFFIPointer* fontHandle) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetStrikethroughPosition (); - #else - return 0; - #endif + if (path) { - } + value _path = wstring_to_value (path); + delete path; + return _path; + } else { - int lime_font_get_strikethrough_thickness (value fontHandle) { + return alloc_null (); + + } - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetStrikethroughThickness (); - #else - return 0; #endif + return alloc_null (); + } - HL_PRIM int HL_NAME(hl_font_get_strikethrough_thickness) (HL_CFFIPointer* fontHandle) { + HL_PRIM vbyte* HL_NAME(hl_file_dialog_open_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetStrikethroughThickness (); - #else - return 0; - #endif + #ifdef LIME_TINYFILEDIALOGS - } + 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::OpenFile (_title, _filter, _defaultPath); - int lime_font_get_units_per_em (value fontHandle) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return font->GetUnitsPerEM (); - #else - return 0; - #endif + if (path) { - } + vbyte* const result = hl_wstring_to_utf8_bytes (*path); + delete path; + return result; + } else { - HL_PRIM int HL_NAME(hl_font_get_units_per_em) (HL_CFFIPointer* fontHandle) { + return NULL; - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return font->GetUnitsPerEM (); - #else - return 0; - #endif + } - } + #endif + return NULL; - value lime_font_load_bytes (value data) { + } - #ifdef LIME_FREETYPE - Resource resource; - Bytes bytes; - bytes.Set (data); - resource = Resource (&bytes); + value lime_file_dialog_open_files (HxString title, HxString filter, HxString defaultPath) { - Font *font = new Font (&resource, 0); + #ifdef LIME_TINYFILEDIALOGS - if (font) { + std::wstring* _title = hxstring_to_wstring (title); + std::wstring* _filter = hxstring_to_wstring (filter); + std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - if (font->face) { + std::vector files; - return CFFIPointer (font, gc_font); + FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); + value result = alloc_array (files.size ()); - } else { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - delete font; + for (int i = 0; i < files.size (); i++) { - } + value _file = wstring_to_value (files[i]); + val_array_set_i (result, i, _file); + delete files[i]; } + + #else + value result = alloc_array (0); #endif - return alloc_null (); + return result; } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_bytes) (Bytes* data) { - - #ifdef LIME_FREETYPE - Resource resource = Resource (data); + HL_PRIM hl_varray* HL_NAME(hl_file_dialog_open_files) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { - Font *font = new Font (&resource, 0); + #ifdef LIME_TINYFILEDIALOGS - if (font) { + std::wstring* _title = hxstring_to_wstring (title); + std::wstring* _filter = hxstring_to_wstring (filter); + std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - if (font->face) { + std::vector files; - return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); + hl_varray* result = (hl_varray*)hl_alloc_array (&hlt_bytes, files.size ()); + vbyte** resultData = hl_aptr (result, vbyte*); - } else { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - delete font; + for (int i = 0; i < files.size (); i++) { - } + *resultData++ = hl_wstring_to_utf8_bytes (*files[i]); + delete files[i]; } + + #else + hl_varray* result = hl_alloc_array (&hlt_bytes, 0); #endif - return 0; + return result; } - value lime_font_load_file (value data) { + value lime_file_dialog_save_file (HxString title, HxString filter, HxString defaultPath) { - #ifdef LIME_FREETYPE - Resource resource = Resource (val_string (data)); + #ifdef LIME_TINYFILEDIALOGS - Font *font = new Font (&resource, 0); + std::wstring* _title = hxstring_to_wstring (title); + std::wstring* _filter = hxstring_to_wstring (filter); + std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - if (font) { + std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); - if (font->face) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - return CFFIPointer (font, gc_font); + if (path) { - } else { + value _path = wstring_to_value (path); + delete path; + return _path; - delete font; + } else { - } + return alloc_null (); } + #endif return alloc_null (); @@ -2018,345 +2043,380 @@ namespace lime { } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_file) (hl_vstring* data) { + HL_PRIM vbyte* HL_NAME(hl_file_dialog_save_file) (hl_vstring* title, hl_vstring* filter, hl_vstring* defaultPath) { - #ifdef LIME_FREETYPE - Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); + #ifdef LIME_TINYFILEDIALOGS - Font *font = new Font (&resource, 0); + std::wstring* _title = hxstring_to_wstring (title); + std::wstring* _filter = hxstring_to_wstring (filter); + std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - if (font) { + std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); - if (font->face) { + if (_title) delete _title; + if (_filter) delete _filter; + if (_defaultPath) delete _defaultPath; - return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); + if (path) { - } else { + vbyte* const result = hl_wstring_to_utf8_bytes (*path); + delete path; + return result; - delete font; + } else { - } + return NULL; } + #endif - return 0; + return NULL; } - value lime_font_load (value data) { + value lime_file_watcher_create (value callback) { - if (val_is_string (data)) { + #ifdef LIME_EFSW + FileWatcher* watcher = new FileWatcher (callback); + return CFFIPointer (watcher, gc_file_watcher); + #else + return alloc_null (); + #endif - return lime_font_load_file (data); + } - } else { - return lime_font_load_bytes (data); + 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_font_outline_decompose (value fontHandle, int size) { + value lime_file_watcher_add_directory (value handle, value path, bool recursive) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->Decompose (true, size); + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + return alloc_int (watcher->AddDirectory (val_string (path), recursive)); #else - return alloc_null (); + return alloc_int (0); #endif } - value lime_font_outline_decompose_no_hint (value fontHandle, int size) { + HL_PRIM int HL_NAME(hl_file_watcher_add_directory) (HL_CFFIPointer* handle, hl_vstring* path, bool recursive) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - return (value)font->Decompose (true, size, false); + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + return watcher->AddDirectory ((const char*)path, recursive); #else - return alloc_null (); + return 0; #endif } - HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose) (HL_CFFIPointer* fontHandle, int size) { + void lime_file_watcher_remove_directory (value handle, value watchID) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->Decompose (false, size); - #else - return 0; + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + watcher->RemoveDirectory (val_int (watchID)); #endif } - HL_PRIM vdynamic* HL_NAME(hl_font_outline_decompose_no_hint) (HL_CFFIPointer* fontHandle, int size) { + HL_PRIM void HL_NAME(hl_file_watcher_remove_directory) (HL_CFFIPointer* handle, int watchID) { - #ifdef LIME_FREETYPE - Font *font = (Font*)fontHandle->ptr; - return (vdynamic*)font->Decompose (false, size, false); - #else - return 0; + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + watcher->RemoveDirectory (watchID); #endif } - value lime_font_render_glyph (value fontHandle, int index, value data) { + void lime_file_watcher_update (value handle) { - #ifdef LIME_FREETYPE - Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)val_data (handle); + watcher->Update (); + #endif - if (font->RenderGlyph (index, &bytes)) { + } - return bytes.Value (data); - } - #endif + HL_PRIM void HL_NAME(hl_file_watcher_update) (HL_CFFIPointer* handle) { - return alloc_null (); + #ifdef LIME_EFSW + FileWatcher* watcher = (FileWatcher*)handle->ptr; + watcher->Update (); + #endif } - value lime_font_render_glyph_with_flags (value fontHandle, int index, int loadFlags, value data) { + int lime_font_get_ascender (value fontHandle) { #ifdef LIME_FREETYPE Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); - - if (font->RenderGlyphWithFlags (index, loadFlags, &bytes)) { - - return bytes.Value (data); - - } + return font->GetAscender (); + #else + return 0; #endif - return alloc_null (); - } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyph) (HL_CFFIPointer* fontHandle, int index, Bytes* data) { + 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 - if (font->RenderGlyph (index, data)) { + } - return data; - } - #endif + int lime_font_get_descender (value fontHandle) { - return NULL; + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetDescender (); + #else + return 0; + #endif } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyph_with_flags) (HL_CFFIPointer* fontHandle, int index, int loadFlags, Bytes* data) { + HL_PRIM int HL_NAME(hl_font_get_descender) (HL_CFFIPointer* fontHandle) { #ifdef LIME_FREETYPE Font *font = (Font*)fontHandle->ptr; - - if (font->RenderGlyphWithFlags (index, loadFlags, data)) { - - return data; - - } + return font->GetDescender (); + #else + return 0; #endif - return NULL; - } - value lime_font_render_glyphs (value fontHandle, value indices, value data) { + value lime_font_get_family_name (value fontHandle) { #ifdef LIME_FREETYPE Font *font = (Font*)val_data (fontHandle); - Bytes bytes (data); - - if (font->RenderGlyphs (indices, &bytes)) { - - return bytes.Value (data); - - } - #endif - + wchar_t *name = font->GetFamilyName (); + value result = alloc_wstring (name); + delete name; + return result; + #else return alloc_null (); + #endif } - HL_PRIM Bytes* HL_NAME(hl_font_render_glyphs) (HL_CFFIPointer* fontHandle, hl_varray* indices, Bytes* data) { + HL_PRIM vbyte* HL_NAME(hl_font_get_family_name) (HL_CFFIPointer* fontHandle) { - // #ifdef LIME_FREETYPE - // Font *font = (Font*)fontHandle->ptr; - // return font->RenderGlyphs (indices, &bytes); - // #else - return NULL; - // #endif + #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 } - void lime_font_set_size (value fontHandle, int fontSize, int dpi) { + int lime_font_get_glyph_index (value fontHandle, HxString character) { #ifdef LIME_FREETYPE Font *font = (Font*)val_data (fontHandle); - font->SetSize (fontSize, dpi); + return font->GetGlyphIndex (hxs_utf8 (character, nullptr)); + #else + return -1; #endif } - HL_PRIM void HL_NAME(hl_font_set_size) (HL_CFFIPointer* fontHandle, int fontSize, int dpi) { + HL_PRIM int HL_NAME(hl_font_get_glyph_index) (HL_CFFIPointer* fontHandle, hl_vstring* character) { #ifdef LIME_FREETYPE Font *font = (Font*)fontHandle->ptr; - font->SetSize (fontSize, dpi); + return font->GetGlyphIndex (character ? (char*)hl_to_utf8 ((const uchar*)character->bytes) : NULL); + #else + return -1; #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))); + 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 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))); + 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 } - void lime_gamepad_event_manager_register (value callback, value eventObject) { + value lime_font_get_glyph_metrics (value fontHandle, int index) { - GamepadEvent::callback = new ValuePointer (callback); - GamepadEvent::eventObject = new ValuePointer (eventObject); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->GetGlyphMetrics (true, index); + #else + return alloc_null (); + #endif } - HL_PRIM void HL_NAME(hl_gamepad_event_manager_register) (vclosure* callback, GamepadEvent* eventObject) { + HL_PRIM vdynamic* HL_NAME(hl_font_get_glyph_metrics) (HL_CFFIPointer* fontHandle, int index) { - GamepadEvent::callback = new ValuePointer (callback); - GamepadEvent::eventObject = new ValuePointer ((vobj*)eventObject); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return (vdynamic*)font->GetGlyphMetrics (false, index); + #else + return 0; + #endif } - 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 (); + 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 vbyte* HL_NAME(hl_gamepad_get_device_guid) (int id) { - - const char* guid = Gamepad::GetDeviceGUID (id); + HL_PRIM int HL_NAME(hl_font_get_height) (HL_CFFIPointer* fontHandle) { - if (guid) { + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetHeight (); + #else + return 0; + #endif - return (vbyte*)guid; + } - } else { - return 0; + int lime_font_get_num_glyphs (value fontHandle) { - } + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetNumGlyphs (); + #else + return 0; + #endif } - value lime_gamepad_get_device_name (int id) { + HL_PRIM int HL_NAME(hl_font_get_num_glyphs) (HL_CFFIPointer* fontHandle) { - const char* name = Gamepad::GetDeviceName (id); - return name ? alloc_string (name) : alloc_null (); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetNumGlyphs (); + #else + return 0; + #endif } - HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_name) (int id) { + int lime_font_get_underline_position (value fontHandle) { - return (vbyte*)Gamepad::GetDeviceName (id); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnderlinePosition (); + #else + return 0; + #endif } - void lime_gamepad_rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { + HL_PRIM int HL_NAME(hl_font_get_underline_position) (HL_CFFIPointer* fontHandle) { - Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnderlinePosition (); + #else + return 0; + #endif } - HL_PRIM void HL_NAME(hl_gamepad_rumble) (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { + int lime_font_get_underline_thickness (value fontHandle) { - Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnderlineThickness (); + #else + return 0; + #endif } - value lime_gzip_compress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Compress (GZIP, &data, &result); + HL_PRIM int HL_NAME(hl_font_get_underline_thickness) (HL_CFFIPointer* fontHandle) { - return result.Value (bytes); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnderlineThickness (); #else - return alloc_null (); + return 0; #endif } - HL_PRIM Bytes* HL_NAME(hl_gzip_compress) (Bytes* buffer, Bytes* bytes) { + int lime_font_get_strikethrough_position (value fontHandle) { - #ifdef LIME_ZLIB - Zlib::Compress (GZIP, buffer, bytes); - return bytes; + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetStrikethroughPosition (); #else return 0; #endif @@ -2364,27 +2424,23 @@ namespace lime { } - value lime_gzip_decompress (value buffer, value bytes) { - - #ifdef LIME_ZLIB - Bytes data (buffer); - Bytes result (bytes); - - Zlib::Decompress (GZIP, &data, &result); + HL_PRIM int HL_NAME(hl_font_get_strikethrough_position) (HL_CFFIPointer* fontHandle) { - return result.Value (bytes); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetStrikethroughPosition (); #else - return alloc_null (); + return 0; #endif } - HL_PRIM Bytes* HL_NAME(hl_gzip_decompress) (Bytes* buffer, Bytes* bytes) { + int lime_font_get_strikethrough_thickness (value fontHandle) { - #ifdef LIME_ZLIB - Zlib::Decompress (GZIP, buffer, bytes); - return bytes; + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetStrikethroughThickness (); #else return 0; #endif @@ -2392,119 +2448,118 @@ namespace lime { } - void lime_haptic_vibrate (int period, int duration) { + HL_PRIM int HL_NAME(hl_font_get_strikethrough_thickness) (HL_CFFIPointer* fontHandle) { - #ifdef IPHONE - Haptic::Vibrate (period, duration); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetStrikethroughThickness (); + #else + return 0; #endif } - HL_PRIM void HL_NAME(hl_haptic_vibrate) (int period, int duration) { + int lime_font_get_units_per_em (value fontHandle) { - #ifdef IPHONE - Haptic::Vibrate (period, duration); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->GetUnitsPerEM (); + #else + return 0; #endif } - value lime_image_encode (value buffer, int type, int quality, value bytes) { + HL_PRIM int HL_NAME(hl_font_get_units_per_em) (HL_CFFIPointer* fontHandle) { - ImageBuffer imageBuffer = ImageBuffer (buffer); - Bytes data = Bytes (bytes); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->GetUnitsPerEM (); + #else + return 0; + #endif - switch (type) { + } - case 0: - #ifdef LIME_PNG - if (PNG::Encode (&imageBuffer, &data)) { + value lime_font_load_bytes (value data) { - return data.Value (bytes); + #ifdef LIME_FREETYPE + Resource resource; + Bytes bytes; - } - #endif - break; + bytes.Set (data); + resource = Resource (&bytes); - case 1: + Font *font = new Font (&resource, 0); - #ifdef LIME_JPEG - if (JPEG::Encode (&imageBuffer, &data, quality)) { + if (font) { - return data.Value (bytes); + if (font->face) { - } - #endif - break; + return CFFIPointer (font, gc_font); - default: break; + } else { + + delete font; + + } } + #endif return alloc_null (); } - HL_PRIM Bytes* HL_NAME(hl_image_encode) (ImageBuffer* buffer, int type, int quality, Bytes* bytes) { - - switch (type) { - - case 0: + HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_bytes) (Bytes* data) { - #ifdef LIME_PNG - if (PNG::Encode (buffer, bytes)) { + #ifdef LIME_FREETYPE + Resource resource = Resource (data); - return bytes; + Font *font = new Font (&resource, 0); - } - #endif - break; + if (font) { - case 1: + if (font->face) { - #ifdef LIME_JPEG - if (JPEG::Encode (buffer, bytes, quality)) { + return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); - return bytes; + } else { - } - #endif - break; + delete font; - default: break; + } } + #endif return 0; } - value lime_image_load_bytes (value data, value buffer) { + value lime_font_load_file (value data) { - Resource resource; - Bytes bytes; + #ifdef LIME_FREETYPE + Resource resource = Resource (val_string (data)); - ImageBuffer imageBuffer = ImageBuffer (buffer); + Font *font = new Font (&resource, 0); - bytes.Set (data); - resource = Resource (&bytes); + if (font) { - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer)) { + if (font->face) { - return imageBuffer.Value (buffer); + return CFFIPointer (font, gc_font); - } - #endif + } else { - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer)) { + delete font; - return imageBuffer.Value (buffer); + } } #endif @@ -2514,22 +2569,24 @@ namespace lime { } - HL_PRIM ImageBuffer* HL_NAME(hl_image_load_bytes) (Bytes* data, ImageBuffer* buffer) { + HL_PRIM HL_CFFIPointer* HL_NAME(hl_font_load_file) (hl_vstring* data) { - Resource resource = Resource (data); + #ifdef LIME_FREETYPE + Resource resource = Resource (data ? hl_to_utf8 ((const uchar*)data->bytes) : NULL); - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer)) { + Font *font = new Font (&resource, 0); - return buffer; + if (font) { - } - #endif + if (font->face) { - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer)) { + return HLCFFIPointer (font, (hl_finalizer)hl_gc_font); - return buffer; + } else { + + delete font; + + } } #endif @@ -2539,347 +2596,346 @@ namespace lime { } - value lime_image_load_file (value data, value buffer) { + value lime_font_load (value data) { - Resource resource = Resource (val_string (data)); - ImageBuffer imageBuffer = ImageBuffer (buffer); + if (val_is_string (data)) { - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer)) { + return lime_font_load_file (data); - return imageBuffer.Value (buffer); + } else { + + return lime_font_load_bytes (data); } - #endif - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer)) { + } - return imageBuffer.Value (buffer); - } - #endif + 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 } - HL_PRIM ImageBuffer* HL_NAME(hl_image_load_file) (hl_vstring* data, ImageBuffer* buffer) { + value lime_font_outline_decompose_no_hint (value fontHandle, int size) { - Resource resource = Resource (data); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return (value)font->Decompose (true, size, false); + #else + return alloc_null (); + #endif - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer)) { + } - return buffer; - } + 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 - #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer)) { + } - return buffer; - } - #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_image_load (value data, value buffer) { - - if (val_is_string (data)) { + value lime_font_render_glyph (value fontHandle, int index, value data) { - return lime_image_load_file (data, buffer); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); - } else { + if (font->RenderGlyph (index, &bytes)) { - return lime_image_load_bytes (data, buffer); + return bytes.Value (data); } + #endif + + return alloc_null (); } - void lime_image_data_util_color_transform (value image, value rect, value colorMatrix) { + value lime_font_render_glyph_with_flags (value fontHandle, int index, int loadFlags, value data) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); - ImageDataUtil::ColorTransform (&_image, &_rect, &_colorMatrix); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); - } + if (font->RenderGlyphWithFlags (index, loadFlags, &bytes)) { + return bytes.Value (data); - HL_PRIM void HL_NAME(hl_image_data_util_color_transform) (Image* image, Rectangle* rect, ArrayBufferView* colorMatrix) { + } + #endif - ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); - ImageDataUtil::ColorTransform (image, rect, &_colorMatrix); + return alloc_null (); } - void lime_image_data_util_copy_channel (value image, value sourceImage, value sourceRect, value destPoint, int srcChannel, int destChannel) { + HL_PRIM Bytes* HL_NAME(hl_font_render_glyph) (HL_CFFIPointer* fontHandle, int index, Bytes* data) { - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); - ImageDataUtil::CopyChannel (&_image, &_sourceImage, &_sourceRect, &_destPoint, srcChannel, destChannel); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; - } + if (font->RenderGlyph (index, data)) { + return data; - HL_PRIM void HL_NAME(hl_image_data_util_copy_channel) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) { + } + #endif - ImageDataUtil::CopyChannel (image, sourceImage, sourceRect, destPoint, srcChannel, destChannel); + return NULL; } - void lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value alphaImage, value alphaPoint, bool mergeAlpha) { + HL_PRIM Bytes* HL_NAME(hl_font_render_glyph_with_flags) (HL_CFFIPointer* fontHandle, int index, int loadFlags, Bytes* data) { - Image _image = Image (image); - Image _sourceImage = Image (sourceImage); - Rectangle _sourceRect = Rectangle (sourceRect); - Vector2 _destPoint = Vector2 (destPoint); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; - if (val_is_null (alphaImage)) { + if (font->RenderGlyphWithFlags (index, loadFlags, data)) { - 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); + return data; } + #endif - } + return NULL; + } - 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_font_render_glyphs (value fontHandle, value indices, value data) { - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, NULL, NULL, mergeAlpha); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + Bytes bytes (data); - } else { + if (font->RenderGlyphs (indices, &bytes)) { - if (!alphaPoint) { + return bytes.Value (data); - Vector2 _alphaPoint = Vector2 (0, 0); + } + #endif - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, &_alphaPoint, mergeAlpha); + return alloc_null (); - } else { + } - ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha); - } + 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_image_data_util_fill_rect (value image, value rect, int rg, int ba) { + void lime_font_set_size (value fontHandle, int fontSize, int dpi) { - Image _image = Image (image); - Rectangle _rect = Rectangle (rect); - int32_t color = (rg << 16) | ba; - ImageDataUtil::FillRect (&_image, &_rect, color); + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + font->SetSize (fontSize, dpi); + #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_font_set_size) (HL_CFFIPointer* fontHandle, int fontSize, int dpi) { - int32_t color = (rg << 16) | ba; - ImageDataUtil::FillRect (image, rect, color); + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + font->SetSize (fontSize, dpi); + #endif } - 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); + void lime_gamepad_add_mappings (value mappings) { - } + int length = val_array_size (mappings); + for (int i = 0; i < length; i++) { - HL_PRIM void HL_NAME(hl_image_data_util_flood_fill) (Image* image, int x, int y, int rg, int ba) { + Gamepad::AddMapping (val_string (val_array_i (mappings, i))); - 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_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++) { - HL_PRIM void HL_NAME(hl_image_data_util_get_pixels) (Image* image, Rectangle* rect, PixelFormat format, Bytes* bytes) { + Gamepad::AddMapping (hl_to_utf8 ((const uchar*)((*mappingsData++)->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) { + void lime_gamepad_event_manager_register (value callback, value eventObject) { - 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); + GamepadEvent::callback = new ValuePointer (callback); + GamepadEvent::eventObject = new ValuePointer (eventObject); } - 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 void HL_NAME(hl_gamepad_event_manager_register) (vclosure* callback, GamepadEvent* eventObject) { - ImageDataUtil::Merge (image, sourceImage, sourceRect, destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); + GamepadEvent::callback = new ValuePointer (callback); + GamepadEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - void lime_image_data_util_multiply_alpha (value image) { + value lime_gamepad_get_device_guid (int id) { - Image _image = Image (image); - ImageDataUtil::MultiplyAlpha (&_image); + const char* guid = Gamepad::GetDeviceGUID (id); - } + if (guid) { + value result = alloc_string (guid); + delete guid; + return result; - HL_PRIM void HL_NAME(hl_image_data_util_multiply_alpha) (Image* image) { + } else { - ImageDataUtil::MultiplyAlpha (image); + return alloc_null (); + + } } - void lime_image_data_util_resize (value image, value buffer, int width, int height) { + HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_guid) (int id) { - Image _image = Image (image); - ImageBuffer _buffer = ImageBuffer (buffer); - ImageDataUtil::Resize (&_image, &_buffer, width, height); + const char* guid = Gamepad::GetDeviceGUID (id); - } + if (guid) { + return (vbyte*)guid; - HL_PRIM void HL_NAME(hl_image_data_util_resize) (Image* image, ImageBuffer* buffer, int width, int height) { + } else { - ImageDataUtil::Resize (image, buffer, width, height); + return 0; + + } } - void lime_image_data_util_set_format (value image, int format) { + value lime_gamepad_get_device_name (int id) { - Image _image = Image (image); - PixelFormat _format = (PixelFormat)format; - ImageDataUtil::SetFormat (&_image, _format); + const char* name = Gamepad::GetDeviceName (id); + return name ? alloc_string (name) : alloc_null (); } - HL_PRIM void HL_NAME(hl_image_data_util_set_format) (Image* image, PixelFormat format) { + HL_PRIM vbyte* HL_NAME(hl_gamepad_get_device_name) (int id) { - ImageDataUtil::SetFormat (image, format); + return (vbyte*)Gamepad::GetDeviceName (id); } - void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format, int endian) { + void lime_gamepad_rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { - 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); + Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); } - 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 void HL_NAME(hl_gamepad_rumble) (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) { - ImageDataUtil::SetPixels (image, rect, bytes, offset, format, endian); + Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration); } - 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); - - } + value lime_gzip_compress (value buffer, value bytes) { + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); - 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) { + Zlib::Compress (GZIP, &data, &result); - 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); + return result.Value (bytes); + #else + return alloc_null (); + #endif } - void lime_image_data_util_unmultiply_alpha (value image) { + HL_PRIM Bytes* HL_NAME(hl_gzip_compress) (Bytes* buffer, Bytes* bytes) { - Image _image = Image (image); - ImageDataUtil::UnmultiplyAlpha (&_image); + #ifdef LIME_ZLIB + Zlib::Compress (GZIP, buffer, bytes); + return bytes; + #else + return 0; + #endif } - HL_PRIM void HL_NAME(hl_image_data_util_unmultiply_alpha) (Image* image) { - - ImageDataUtil::UnmultiplyAlpha (image); - - } + value lime_gzip_decompress (value buffer, value bytes) { + #ifdef LIME_ZLIB + Bytes data (buffer); + Bytes result (bytes); - double lime_jni_getenv () { + Zlib::Decompress (GZIP, &data, &result); - #ifdef ANDROID - return (uintptr_t)JNI::GetEnv (); + return result.Value (bytes); #else - return 0; + return alloc_null (); #endif } - HL_PRIM double HL_NAME(hl_jni_getenv) () { + HL_PRIM Bytes* HL_NAME(hl_gzip_decompress) (Bytes* buffer, Bytes* bytes) { - #ifdef ANDROID - return (uintptr_t)JNI::GetEnv (); + #ifdef LIME_ZLIB + Zlib::Decompress (GZIP, buffer, bytes); + return bytes; #else return 0; #endif @@ -2887,103 +2943,117 @@ namespace lime { } - void lime_joystick_event_manager_register (value callback, value eventObject) { + void lime_haptic_vibrate (int period, int duration) { - JoystickEvent::callback = new ValuePointer (callback); - JoystickEvent::eventObject = new ValuePointer (eventObject); + #ifdef IPHONE + Haptic::Vibrate (period, duration); + #endif } - HL_PRIM void HL_NAME(hl_joystick_event_manager_register) (vclosure* callback, JoystickEvent* eventObject) { + HL_PRIM void HL_NAME(hl_haptic_vibrate) (int period, int duration) { - JoystickEvent::callback = new ValuePointer (callback); - JoystickEvent::eventObject = new ValuePointer ((vobj*)eventObject); + #ifdef IPHONE + Haptic::Vibrate (period, duration); + #endif } - value lime_joystick_get_device_guid (int id) { - - const char* guid = Joystick::GetDeviceGUID (id); - return guid ? alloc_string (guid) : alloc_null (); + value lime_image_encode (value buffer, int type, int quality, value bytes) { - } + ImageBuffer imageBuffer = ImageBuffer (buffer); + Bytes data = Bytes (bytes); + switch (type) { - HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_guid) (int id) { + case 0: - return (vbyte*)Joystick::GetDeviceGUID (id); + #ifdef LIME_PNG + if (PNG::Encode (&imageBuffer, &data)) { - } + return data.Value (bytes); + } + #endif + break; - value lime_joystick_get_device_name (int id) { + case 1: - const char* name = Joystick::GetDeviceName (id); - return name ? alloc_string (name) : alloc_null (); + #ifdef LIME_JPEG + if (JPEG::Encode (&imageBuffer, &data, quality)) { - } + return data.Value (bytes); + } + #endif + break; - HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_name) (int id) { - - return (vbyte*)Joystick::GetDeviceName (id); - - } - + default: break; - int lime_joystick_get_num_axes (int id) { + } - return Joystick::GetNumAxes (id); + return alloc_null (); } - HL_PRIM int HL_NAME(hl_joystick_get_num_axes) (int id) { - - return Joystick::GetNumAxes (id); + HL_PRIM Bytes* HL_NAME(hl_image_encode) (ImageBuffer* buffer, int type, int quality, Bytes* bytes) { - } + switch (type) { + case 0: - int lime_joystick_get_num_buttons (int id) { + #ifdef LIME_PNG + if (PNG::Encode (buffer, bytes)) { - return Joystick::GetNumButtons (id); + return bytes; - } + } + #endif + break; + case 1: - HL_PRIM int HL_NAME(hl_joystick_get_num_buttons) (int id) { + #ifdef LIME_JPEG + if (JPEG::Encode (buffer, bytes, quality)) { - return Joystick::GetNumButtons (id); + return bytes; - } + } + #endif + break; + default: break; - int lime_joystick_get_num_hats (int id) { + } - return Joystick::GetNumHats (id); + return 0; } - HL_PRIM int HL_NAME(hl_joystick_get_num_hats) (int id) { + value lime_image_load_bytes (value data, value buffer) { - return Joystick::GetNumHats (id); + Resource resource; + Bytes bytes; - } + ImageBuffer imageBuffer = ImageBuffer (buffer); + bytes.Set (data); + resource = Resource (&bytes); - value lime_jpeg_decode_bytes (value data, bool decodeData, value buffer) { + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer)) { - ImageBuffer imageBuffer (buffer); + return imageBuffer.Value (buffer); - Bytes bytes (data); - Resource resource = Resource (&bytes); + } + #endif #ifdef LIME_JPEG - if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + if (JPEG::Decode (&resource, &imageBuffer)) { return imageBuffer.Value (buffer); @@ -2995,12 +3065,20 @@ namespace lime { } - HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { + 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, decodeData)) { + if (JPEG::Decode (&resource, buffer)) { return buffer; @@ -3012,13 +3090,21 @@ namespace lime { } - value lime_jpeg_decode_file (HxString path, bool decodeData, value buffer) { + value lime_image_load_file (value data, value buffer) { - ImageBuffer imageBuffer (buffer); - Resource resource = Resource (hxs_utf8 (path, nullptr)); + 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, decodeData)) { + if (JPEG::Decode (&resource, &imageBuffer)) { return imageBuffer.Value (buffer); @@ -3030,12 +3116,20 @@ namespace lime { } - HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + HL_PRIM ImageBuffer* HL_NAME(hl_image_load_file) (hl_vstring* data, ImageBuffer* buffer) { - Resource resource = Resource (path); + Resource resource = Resource (data); + + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer)) { + + return buffer; + + } + #endif #ifdef LIME_JPEG - if (JPEG::Decode (&resource, buffer, decodeData)) { + if (JPEG::Decode (&resource, buffer)) { return buffer; @@ -3047,639 +3141,598 @@ namespace lime { } - int lime_key_code_from_scan_code (int scanCode) { + value lime_image_load (value data, value buffer) { - return KeyCode::FromScanCode (scanCode); + if (val_is_string (data)) { - } + return lime_image_load_file (data, buffer); + } else { - HL_PRIM int HL_NAME(hl_key_code_from_scan_code) (int scanCode) { + return lime_image_load_bytes (data, buffer); - return KeyCode::FromScanCode (scanCode); + } } - int lime_key_code_to_scan_code (int keyCode) { + void lime_image_data_util_color_transform (value image, value rect, value colorMatrix) { - return KeyCode::ToScanCode (keyCode); + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); + ImageDataUtil::ColorTransform (&_image, &_rect, &_colorMatrix); } - HL_PRIM int HL_NAME(hl_key_code_to_scan_code) (int keyCode) { + HL_PRIM void HL_NAME(hl_image_data_util_color_transform) (Image* image, Rectangle* rect, ArrayBufferView* colorMatrix) { - return KeyCode::ToScanCode (keyCode); + ColorMatrix _colorMatrix = ColorMatrix (colorMatrix); + ImageDataUtil::ColorTransform (image, rect, &_colorMatrix); } - void lime_key_event_manager_register (value callback, value eventObject) { + void lime_image_data_util_copy_channel (value image, value sourceImage, value sourceRect, value destPoint, int srcChannel, int destChannel) { - KeyEvent::callback = new ValuePointer (callback); - KeyEvent::eventObject = new ValuePointer (eventObject); + 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_key_event_manager_register) (vclosure* callback, KeyEvent* eventObject) { + HL_PRIM void HL_NAME(hl_image_data_util_copy_channel) (Image* image, Image* sourceImage, Rectangle* sourceRect, Vector2* destPoint, int srcChannel, int destChannel) { - KeyEvent::callback = new ValuePointer (callback); - KeyEvent::eventObject = new ValuePointer ((vobj*)eventObject); + ImageDataUtil::CopyChannel (image, sourceImage, sourceRect, destPoint, srcChannel, destChannel); } - value lime_locale_get_system_locale () { + void lime_image_data_util_copy_pixels (value image, value sourceImage, value sourceRect, value destPoint, value alphaImage, value alphaPoint, bool mergeAlpha) { - std::string* locale = Locale::GetSystemLocale (); + Image _image = Image (image); + Image _sourceImage = Image (sourceImage); + Rectangle _sourceRect = Rectangle (sourceRect); + Vector2 _destPoint = Vector2 (destPoint); - if (!locale) { + if (val_is_null (alphaImage)) { - return alloc_null (); + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, 0, 0, mergeAlpha); } else { - value result = alloc_string (locale->c_str ()); - delete locale; - return result; + Image _alphaImage = Image (alphaImage); + Vector2 _alphaPoint = Vector2 (alphaPoint); + + ImageDataUtil::CopyPixels (&_image, &_sourceImage, &_sourceRect, &_destPoint, &_alphaImage, &_alphaPoint, mergeAlpha); } } - HL_PRIM vbyte* HL_NAME(hl_locale_get_system_locale) () { - - std::string* locale = Locale::GetSystemLocale (); + 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 (!locale) { + if (!alphaImage) { - return 0; + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, NULL, NULL, mergeAlpha); } 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; - - } + if (!alphaPoint) { - } + Vector2 _alphaPoint = Vector2 (0, 0); + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, &_alphaPoint, mergeAlpha); - value lime_lzma_compress (value buffer, value bytes) { + } else { - #ifdef LIME_LZMA - Bytes data (buffer); - Bytes result (bytes); + ImageDataUtil::CopyPixels (image, sourceImage, sourceRect, destPoint, alphaImage, alphaPoint, mergeAlpha); - 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) { + void lime_image_data_util_fill_rect (value image, value rect, int rg, int ba) { - #ifdef LIME_LZMA - LZMA::Compress (buffer, bytes); - return bytes; - #else - return 0; - #endif + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + int32_t color = (rg << 16) | ba; + ImageDataUtil::FillRect (&_image, &_rect, color); } - value lime_lzma_decompress (value buffer, value bytes) { - - #ifdef LIME_LZMA - Bytes data (buffer); - Bytes result (bytes); - - LZMA::Decompress (&data, &result); + HL_PRIM void HL_NAME(hl_image_data_util_fill_rect) (Image* image, Rectangle* rect, int rg, int ba) { - return result.Value (bytes); - #else - return alloc_null (); - #endif + int32_t color = (rg << 16) | ba; + ImageDataUtil::FillRect (image, rect, color); } - HL_PRIM Bytes* HL_NAME(hl_lzma_decompress) (Bytes* buffer, Bytes* bytes) { + void lime_image_data_util_flood_fill (value image, int x, int y, int rg, int ba) { - #ifdef LIME_LZMA - LZMA::Decompress (buffer, bytes); - return bytes; - #else - return 0; - #endif + Image _image = Image (image); + int32_t color = (rg << 16) | ba; + ImageDataUtil::FloodFill (&_image, x, y, color); } - void lime_mouse_event_manager_register (value callback, value eventObject) { + HL_PRIM void HL_NAME(hl_image_data_util_flood_fill) (Image* image, int x, int y, int rg, int ba) { - MouseEvent::callback = new ValuePointer (callback); - MouseEvent::eventObject = new ValuePointer (eventObject); + int32_t color = (rg << 16) | ba; + ImageDataUtil::FloodFill (image, x, y, color); } - HL_PRIM void HL_NAME(hl_mouse_event_manager_register) (vclosure* callback, MouseEvent* eventObject) { + void lime_image_data_util_get_pixels (value image, value rect, int format, value bytes) { - MouseEvent::callback = new ValuePointer (callback); - MouseEvent::eventObject = new ValuePointer ((vobj*)eventObject); + Image _image = Image (image); + Rectangle _rect = Rectangle (rect); + PixelFormat _format = (PixelFormat)format; + Bytes pixels = Bytes (bytes); + ImageDataUtil::GetPixels (&_image, &_rect, _format, &pixels); } - void lime_neko_execute (HxString module) { + HL_PRIM void HL_NAME(hl_image_data_util_get_pixels) (Image* image, Rectangle* rect, PixelFormat format, Bytes* bytes) { - #ifdef LIME_NEKO - NekoVM::Execute (module.c_str ()); - #endif + ImageDataUtil::GetPixels (image, rect, format, bytes); } - void lime_orientation_event_manager_register (value callback, value eventObject) { + void lime_image_data_util_merge (value image, value sourceImage, value sourceRect, value destPoint, int redMultiplier, int greenMultiplier, int blueMultiplier, int alphaMultiplier) { - OrientationEvent::callback = new ValuePointer (callback); - OrientationEvent::eventObject = new ValuePointer (eventObject); - System::EnableDeviceOrientationChange(true); + 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_orientation_event_manager_register) (vclosure* callback, OrientationEvent* eventObject) { + 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) { - OrientationEvent::callback = new ValuePointer (callback); - OrientationEvent::eventObject = new ValuePointer ((vobj*)eventObject); + ImageDataUtil::Merge (image, sourceImage, sourceRect, destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier); } - value lime_png_decode_bytes (value data, bool decodeData, value buffer) { + void lime_image_data_util_multiply_alpha (value image) { - ImageBuffer imageBuffer (buffer); - Bytes bytes (data); - Resource resource = Resource (&bytes); + Image _image = Image (image); + ImageDataUtil::MultiplyAlpha (&_image); - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + HL_PRIM void HL_NAME(hl_image_data_util_multiply_alpha) (Image* image) { - return alloc_null (); + ImageDataUtil::MultiplyAlpha (image); } - HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { + void lime_image_data_util_resize (value image, value buffer, int width, int height) { - Resource resource = Resource (data); + Image _image = Image (image); + ImageBuffer _buffer = ImageBuffer (buffer); + ImageDataUtil::Resize (&_image, &_buffer, width, height); - #ifdef LIME_PNG - if (PNG::Decode (&resource, buffer, decodeData)) { + } - return buffer; - } - #endif + HL_PRIM void HL_NAME(hl_image_data_util_resize) (Image* image, ImageBuffer* buffer, int width, int height) { - return 0; + ImageDataUtil::Resize (image, buffer, width, height); } - value lime_png_decode_file (HxString path, bool decodeData, value buffer) { + void lime_image_data_util_set_format (value image, int format) { - ImageBuffer imageBuffer (buffer); - Resource resource = Resource (hxs_utf8 (path, nullptr)); + Image _image = Image (image); + PixelFormat _format = (PixelFormat)format; + ImageDataUtil::SetFormat (&_image, _format); - #ifdef LIME_PNG - if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + } - return imageBuffer.Value (buffer); - } - #endif + HL_PRIM void HL_NAME(hl_image_data_util_set_format) (Image* image, PixelFormat format) { - return alloc_null (); + ImageDataUtil::SetFormat (image, format); } - HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + void lime_image_data_util_set_pixels (value image, value rect, value bytes, int offset, int format, int endian) { - Resource resource = Resource (path); + 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_PNG - if (PNG::Decode (&resource, buffer, decodeData)) { + } - return buffer; - } - #endif + HL_PRIM void HL_NAME(hl_image_data_util_set_pixels) (Image* image, Rectangle* rect, Bytes* bytes, int offset, PixelFormat format, Endian endian) { - return 0; + ImageDataUtil::SetPixels (image, rect, bytes, offset, format, endian); } - void lime_render_event_manager_register (value callback, value eventObject) { + 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) { - RenderEvent::callback = new ValuePointer (callback); - RenderEvent::eventObject = new ValuePointer (eventObject); + 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 void HL_NAME(hl_render_event_manager_register) (vclosure* callback, RenderEvent* eventObject) { + 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) { - RenderEvent::callback = new ValuePointer (callback); - RenderEvent::eventObject = new ValuePointer ((vobj*)eventObject); + 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_sensor_event_manager_register (value callback, value eventObject) { + void lime_image_data_util_unmultiply_alpha (value image) { - SensorEvent::callback = new ValuePointer (callback); - SensorEvent::eventObject = new ValuePointer (eventObject); + Image _image = Image (image); + ImageDataUtil::UnmultiplyAlpha (&_image); } - HL_PRIM void HL_NAME(hl_sensor_event_manager_register) (vclosure* callback, SensorEvent* eventObject) { + HL_PRIM void HL_NAME(hl_image_data_util_unmultiply_alpha) (Image* image) { - SensorEvent::callback = new ValuePointer (callback); - SensorEvent::eventObject = new ValuePointer ((vobj*)eventObject); + ImageDataUtil::UnmultiplyAlpha (image); } - bool lime_system_get_allow_screen_timeout () { + double lime_jni_getenv () { - return System::GetAllowScreenTimeout (); + #ifdef ANDROID + return (uintptr_t)JNI::GetEnv (); + #else + return 0; + #endif } - HL_PRIM bool HL_NAME(hl_system_get_allow_screen_timeout) () { + HL_PRIM double HL_NAME(hl_jni_getenv) () { - return System::GetAllowScreenTimeout (); + #ifdef ANDROID + return (uintptr_t)JNI::GetEnv (); + #else + return 0; + #endif } - value lime_system_get_device_model () { - - std::wstring* model = System::GetDeviceModel (); + void lime_joystick_event_manager_register (value callback, value eventObject) { - if (model) { + JoystickEvent::callback = new ValuePointer (callback); + JoystickEvent::eventObject = new ValuePointer (eventObject); - value result = alloc_wstring (model->c_str ()); - delete model; - return result; + } - } else { - return alloc_null (); + 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); } - HL_PRIM vbyte* HL_NAME(hl_system_get_device_model) () { + value lime_joystick_get_device_guid (int id) { - #ifndef EMSCRIPTEN + const char* guid = Joystick::GetDeviceGUID (id); + return guid ? alloc_string (guid) : alloc_null (); - std::wstring* model = System::GetDeviceModel (); + } - if (model) { - vbyte* const result = hl_wstring_to_utf8_bytes (*model); - delete model; - return result; + HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_guid) (int id) { - } + return (vbyte*)Joystick::GetDeviceGUID (id); - #endif + } - return 0; - } + value lime_joystick_get_device_name (int id) { + const char* name = Joystick::GetDeviceName (id); + return name ? alloc_string (name) : alloc_null (); - value lime_system_get_device_vendor () { + } - std::wstring* vendor = System::GetDeviceVendor (); - if (vendor) { + HL_PRIM vbyte* HL_NAME(hl_joystick_get_device_name) (int id) { - value result = alloc_wstring (vendor->c_str ()); - delete vendor; - return result; + return (vbyte*)Joystick::GetDeviceName (id); - } else { + } - return alloc_null (); - } + int lime_joystick_get_num_axes (int id) { + + return Joystick::GetNumAxes (id); } - HL_PRIM vbyte* HL_NAME(hl_system_get_device_vendor) () { + HL_PRIM int HL_NAME(hl_joystick_get_num_axes) (int id) { - #ifndef EMSCRIPTEN + return Joystick::GetNumAxes (id); - std::wstring* vendor = System::GetDeviceVendor (); + } - if (vendor) { - vbyte* const result = hl_wstring_to_utf8_bytes (*vendor); - delete vendor; - return result; + int lime_joystick_get_num_buttons (int id) { - } + return Joystick::GetNumButtons (id); - #endif + } - return 0; - } + HL_PRIM int HL_NAME(hl_joystick_get_num_buttons) (int id) { + return Joystick::GetNumButtons (id); - 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) { + int lime_joystick_get_num_hats (int id) { - value result = alloc_wstring (path->c_str ()); - delete path; - return result; + return Joystick::GetNumHats (id); - } else { + } - return alloc_null (); - } + HL_PRIM int HL_NAME(hl_joystick_get_num_hats) (int id) { + + return Joystick::GetNumHats (id); } - HL_PRIM vbyte* HL_NAME(hl_system_get_directory) (int type, hl_vstring* company, hl_vstring* title) { + value lime_jpeg_decode_bytes (value data, bool decodeData, value buffer) { - #ifndef EMSCRIPTEN + ImageBuffer imageBuffer (buffer); - 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); + Bytes bytes (data); + Resource resource = Resource (&bytes); - if (path) { + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; + return imageBuffer.Value (buffer); } - #endif - return 0; + return alloc_null (); } - value lime_system_get_display (int id) { + HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { - return (value)System::GetDisplay (true, id); + Resource resource = Resource (data); - } + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer, decodeData)) { + return buffer; - HL_PRIM vdynamic* HL_NAME(hl_system_get_display) (int id) { + } + #endif - return (vdynamic*)System::GetDisplay (false, id); + return 0; } - bool lime_system_get_ios_tablet () { + value lime_jpeg_decode_file (HxString path, bool decodeData, value buffer) { - #ifdef IPHONE - return System::GetIOSTablet (); - #else - return false; - #endif + ImageBuffer imageBuffer (buffer); + Resource resource = Resource (hxs_utf8 (path, nullptr)); - } + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, &imageBuffer, decodeData)) { + return imageBuffer.Value (buffer); - HL_PRIM bool HL_NAME(hl_system_get_ios_tablet) () { - - #ifdef IPHONE - return System::GetIOSTablet (); - #else - return false; + } #endif + return alloc_null (); + } - int lime_system_get_num_displays () { + HL_PRIM ImageBuffer* HL_NAME(hl_jpeg_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { - return System::GetNumDisplays (); + Resource resource = Resource (path); - } + #ifdef LIME_JPEG + if (JPEG::Decode (&resource, buffer, decodeData)) { + return buffer; - HL_PRIM int HL_NAME(hl_system_get_num_displays) () { + } + #endif - return System::GetNumDisplays (); + return 0; } - int lime_system_get_device_orientation () { + int lime_key_code_from_scan_code (int scanCode) { - return System::GetDeviceOrientation(); + return KeyCode::FromScanCode (scanCode); } - HL_PRIM int HL_NAME(hl_system_get_device_orientation) () { + HL_PRIM int HL_NAME(hl_key_code_from_scan_code) (int scanCode) { - return System::GetDeviceOrientation(); + return KeyCode::FromScanCode (scanCode); } - value lime_system_get_platform_label () { - - std::wstring* label = System::GetPlatformLabel (); + int lime_key_code_to_scan_code (int keyCode) { - if (label) { + return KeyCode::ToScanCode (keyCode); - value result = alloc_wstring (label->c_str ()); - delete label; - return result; + } - } else { - return alloc_null (); + HL_PRIM int HL_NAME(hl_key_code_to_scan_code) (int keyCode) { - } + return KeyCode::ToScanCode (keyCode); } - HL_PRIM vbyte* HL_NAME(hl_system_get_platform_label) () { - - #ifndef EMSCRIPTEN - - std::wstring* label = System::GetPlatformLabel (); + void lime_key_event_manager_register (value callback, value eventObject) { - if (label) { + KeyEvent::callback = new ValuePointer (callback); + KeyEvent::eventObject = new ValuePointer (eventObject); - vbyte* const result = hl_wstring_to_utf8_bytes (*label); - delete label; - return result; + } - } - #endif + HL_PRIM void HL_NAME(hl_key_event_manager_register) (vclosure* callback, KeyEvent* eventObject) { - return 0; + KeyEvent::callback = new ValuePointer (callback); + KeyEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - value lime_system_get_platform_name () { + value lime_locale_get_system_locale () { - std::wstring* name = System::GetPlatformName (); + std::string* locale = Locale::GetSystemLocale (); - if (name) { + if (!locale) { - value result = alloc_wstring (name->c_str ()); - delete name; - return result; + return alloc_null (); } 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; + value result = alloc_string (locale->c_str ()); + delete locale; return result; } - #endif - - return 0; - } - value lime_system_get_platform_version () { + HL_PRIM vbyte* HL_NAME(hl_locale_get_system_locale) () { - std::wstring* version = System::GetPlatformVersion (); + std::string* locale = Locale::GetSystemLocale (); - if (version) { + if (!locale) { - value result = alloc_wstring (version->c_str ()); - delete version; - return result; + return 0; } else { - return alloc_null (); + int size = locale->size (); + char* _locale = (char*)malloc (size + 1); + strncpy (_locale, locale->c_str (), size); + _locale[size] = '\0'; + delete locale; + + return (vbyte*)_locale; } } - HL_PRIM vbyte* HL_NAME(hl_system_get_platform_version) () { - - #ifndef EMSCRIPTEN - - std::wstring* version = System::GetPlatformVersion (); + value lime_lzma_compress (value buffer, value bytes) { - if (version) { + #ifdef LIME_LZMA + Bytes data (buffer); + Bytes result (bytes); - vbyte* const result = hl_wstring_to_utf8_bytes (*version); - delete version; - return result; - } + LZMA::Compress (&data, &result); + return result.Value (bytes); + #else + return alloc_null (); #endif - return 0; - } - double lime_system_get_timer () { + HL_PRIM Bytes* HL_NAME(hl_lzma_compress) (Bytes* buffer, Bytes* bytes) { - return System::GetTimer (); + #ifdef LIME_LZMA + LZMA::Compress (buffer, bytes); + return bytes; + #else + return 0; + #endif } - HL_PRIM double HL_NAME(hl_system_get_timer) () { - - return System::GetTimer (); - - } + value lime_lzma_decompress (value buffer, value bytes) { + #ifdef LIME_LZMA + Bytes data (buffer); + Bytes result (bytes); - int lime_system_get_windows_console_mode (int handleType) { + LZMA::Decompress (&data, &result); - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::GetWindowsConsoleMode (handleType); + return result.Value (bytes); #else - return 0; + return alloc_null (); #endif } - HL_PRIM int HL_NAME(hl_system_get_windows_console_mode) (int handleType) { + HL_PRIM Bytes* HL_NAME(hl_lzma_decompress) (Bytes* buffer, Bytes* bytes) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::GetWindowsConsoleMode (handleType); + #ifdef LIME_LZMA + LZMA::Decompress (buffer, bytes); + return bytes; #else return 0; #endif @@ -3687,1010 +3740,6002 @@ namespace lime { } - void lime_system_open_file (HxString path) { + void lime_mouse_event_manager_register (value callback, value eventObject) { - #ifdef IPHONE - System::OpenFile (path.c_str ()); - #endif + MouseEvent::callback = new ValuePointer (callback); + MouseEvent::eventObject = new ValuePointer (eventObject); } - HL_PRIM void HL_NAME(hl_system_open_file) (vbyte* path) { + HL_PRIM void HL_NAME(hl_mouse_event_manager_register) (vclosure* callback, MouseEvent* eventObject) { - #ifdef IPHONE - System::OpenFile ((char*)path); - #endif + MouseEvent::callback = new ValuePointer (callback); + MouseEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - void lime_system_open_url (HxString url, HxString target) { + void lime_neko_execute (HxString module) { - #ifdef IPHONE - System::OpenURL (url.c_str (), target.c_str ()); + #ifdef LIME_NEKO + NekoVM::Execute (module.c_str ()); #endif } - HL_PRIM void HL_NAME(hl_system_open_url) (vbyte* url, vbyte* target) { + void lime_orientation_event_manager_register (value callback, value eventObject) { - #ifdef IPHONE - System::OpenURL ((char*)url, (char*)target); - #endif + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer (eventObject); + System::EnableDeviceOrientationChange(true); } - bool lime_system_set_allow_screen_timeout (bool allow) { + HL_PRIM void HL_NAME(hl_orientation_event_manager_register) (vclosure* callback, OrientationEvent* eventObject) { - return System::SetAllowScreenTimeout (allow); + OrientationEvent::callback = new ValuePointer (callback); + OrientationEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - HL_PRIM bool HL_NAME(hl_system_set_allow_screen_timeout) (bool allow) { - - return System::SetAllowScreenTimeout (allow); + 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)) { - bool lime_system_set_windows_console_mode (int handleType, int mode) { + return imageBuffer.Value (buffer); - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::SetWindowsConsoleMode (handleType, mode); - #else - return false; + } #endif + return alloc_null (); + } - HL_PRIM bool HL_NAME(hl_system_set_windows_console_mode) (int handleType, int mode) { + HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { - #if defined (HX_WINDOWS) && !defined (HX_WINRT) - return System::SetWindowsConsoleMode (handleType, mode); - #else - return false; - #endif + Resource resource = Resource (data); - } + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer, decodeData)) { + return buffer; - void lime_text_event_manager_register (value callback, value eventObject) { + } + #endif - TextEvent::callback = new ValuePointer (callback); - TextEvent::eventObject = new ValuePointer (eventObject); + return 0; } - HL_PRIM void HL_NAME(hl_text_event_manager_register) (vclosure* callback, TextEvent* eventObject) { + value lime_png_decode_file (HxString path, bool decodeData, value buffer) { - TextEvent::callback = new ValuePointer (callback); - TextEvent::eventObject = new ValuePointer ((vobj*)eventObject); + ImageBuffer imageBuffer (buffer); + Resource resource = Resource (hxs_utf8 (path, nullptr)); - } + #ifdef LIME_PNG + if (PNG::Decode (&resource, &imageBuffer, decodeData)) { + return imageBuffer.Value (buffer); - void lime_touch_event_manager_register (value callback, value eventObject) { + } + #endif - TouchEvent::callback = new ValuePointer (callback); - TouchEvent::eventObject = new ValuePointer (eventObject); + return alloc_null (); } - HL_PRIM void HL_NAME(hl_touch_event_manager_register) (vclosure* callback, TouchEvent* eventObject) { + HL_PRIM ImageBuffer* HL_NAME(hl_png_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { - TouchEvent::callback = new ValuePointer (callback); - TouchEvent::eventObject = new ValuePointer ((vobj*)eventObject); + Resource resource = Resource (path); - } + #ifdef LIME_PNG + if (PNG::Decode (&resource, buffer, decodeData)) { + return buffer; - void lime_window_alert (value window, HxString message, HxString title) { + } + #endif - Window* targetWindow = (Window*)val_data (window); - targetWindow->Alert (hxs_utf8 (message, nullptr), hxs_utf8 (title, nullptr)); + return 0; } - HL_PRIM void HL_NAME(hl_window_alert) (HL_CFFIPointer* window, hl_vstring* message, hl_vstring* title) { + void lime_render_event_manager_register (value callback, value eventObject) { - 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); + RenderEvent::callback = new ValuePointer (callback); + RenderEvent::eventObject = new ValuePointer (eventObject); } - void lime_window_close (value window) { + HL_PRIM void HL_NAME(hl_render_event_manager_register) (vclosure* callback, RenderEvent* eventObject) { - Window* targetWindow = (Window*)val_data (window); - targetWindow->Close (); + RenderEvent::callback = new ValuePointer (callback); + RenderEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - HL_PRIM void HL_NAME(hl_window_close) (HL_CFFIPointer* window) { + void lime_sensor_event_manager_register (value callback, value eventObject) { - Window* targetWindow = (Window*)window->ptr; - targetWindow->Close (); + SensorEvent::callback = new ValuePointer (callback); + SensorEvent::eventObject = new ValuePointer (eventObject); } - void lime_window_context_flip (value window) { + HL_PRIM void HL_NAME(hl_sensor_event_manager_register) (vclosure* callback, SensorEvent* eventObject) { - ((Window*)val_data (window))->ContextFlip (); + SensorEvent::callback = new ValuePointer (callback); + SensorEvent::eventObject = new ValuePointer ((vobj*)eventObject); } - HL_PRIM void HL_NAME(hl_window_context_flip) (HL_CFFIPointer* window) { + bool lime_system_get_allow_screen_timeout () { - ((Window*)window->ptr)->ContextFlip (); + return System::GetAllowScreenTimeout (); } - value lime_window_context_lock (value window) { + HL_PRIM bool HL_NAME(hl_system_get_allow_screen_timeout) () { - return (value)((Window*)val_data (window))->ContextLock (true); + return System::GetAllowScreenTimeout (); } - HL_PRIM vdynamic* HL_NAME(hl_window_context_lock) (HL_CFFIPointer* window) { + value lime_system_get_device_model () { - return (vdynamic*)((Window*)window->ptr)->ContextLock (false); + std::wstring* model = System::GetDeviceModel (); - } + if (model) { + value result = alloc_wstring (model->c_str ()); + delete model; + return result; - void lime_window_context_make_current (value window) { + } else { - ((Window*)val_data (window))->ContextMakeCurrent (); + return alloc_null (); + + } } - HL_PRIM void HL_NAME(hl_window_context_make_current) (HL_CFFIPointer* window) { + HL_PRIM vbyte* HL_NAME(hl_system_get_device_model) () { - ((Window*)window->ptr)->ContextMakeCurrent (); + #ifndef EMSCRIPTEN - } + std::wstring* model = System::GetDeviceModel (); + if (model) { - void lime_window_context_unlock (value window) { + vbyte* const result = hl_wstring_to_utf8_bytes (*model); + delete model; + return result; - ((Window*)val_data (window))->ContextUnlock (); + } + + #endif + + return 0; } - HL_PRIM void HL_NAME(hl_window_context_unlock) (HL_CFFIPointer* window) { + value lime_system_get_device_vendor () { - ((Window*)window->ptr)->ContextUnlock (); + std::wstring* vendor = System::GetDeviceVendor (); - } + if (vendor) { + value result = alloc_wstring (vendor->c_str ()); + delete vendor; + return result; - value lime_window_create (value application, int width, int height, int flags, HxString title) { + } else { - Window* window = CreateWindow ((Application*)val_data (application), width, height, flags, hxs_utf8 (title, nullptr)); - return CFFIPointer (window, gc_window); + return alloc_null (); + + } } - 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_system_get_device_vendor) () { - 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); + #ifndef EMSCRIPTEN - } + std::wstring* vendor = System::GetDeviceVendor (); + if (vendor) { - void lime_window_event_manager_register (value callback, value eventObject) { + vbyte* const result = hl_wstring_to_utf8_bytes (*vendor); + delete vendor; + return result; - WindowEvent::callback = new ValuePointer (callback); - WindowEvent::eventObject = new ValuePointer (eventObject); + } + + #endif + + return 0; } - HL_PRIM void HL_NAME(hl_window_event_manager_register) (vclosure* callback, WindowEvent* eventObject) { + value lime_system_get_directory (int type, HxString company, HxString title) { - WindowEvent::callback = new ValuePointer (callback); - WindowEvent::eventObject = new ValuePointer ((vobj*)eventObject); + 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; - void lime_window_focus (value window) { + } else { - Window* targetWindow = (Window*)val_data (window); - targetWindow->Focus (); + return alloc_null (); + + } } - HL_PRIM void HL_NAME(hl_window_focus) (HL_CFFIPointer* window) { + HL_PRIM vbyte* HL_NAME(hl_system_get_directory) (int type, hl_vstring* company, hl_vstring* title) { - Window* targetWindow = (Window*)window->ptr; - targetWindow->Focus (); + #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) { - double lime_window_get_context (value window) { + vbyte* const result = hl_wstring_to_utf8_bytes (*path); + delete path; + return result; - Window* targetWindow = (Window*)val_data (window); - return (uintptr_t)targetWindow->GetContext (); + } + + #endif + + return 0; } - HL_PRIM double HL_NAME(hl_window_get_context) (HL_CFFIPointer* window) { + value lime_system_get_display (int id) { - Window* targetWindow = (Window*)window->ptr; - return (uintptr_t)targetWindow->GetContext (); + return (value)System::GetDisplay (true, id); } - value lime_window_get_context_type (value window) { + HL_PRIM vdynamic* HL_NAME(hl_system_get_display) (int id) { - Window* targetWindow = (Window*)val_data (window); - const char* type = targetWindow->GetContextType (); - return type ? alloc_string (type) : alloc_null (); + return (vdynamic*)System::GetDisplay (false, id); } - HL_PRIM vbyte* HL_NAME(hl_window_get_context_type) (HL_CFFIPointer* window) { + bool lime_system_get_ios_tablet () { - Window* targetWindow = (Window*)window->ptr; - return (vbyte*)targetWindow->GetContextType (); + #ifdef IPHONE + return System::GetIOSTablet (); + #else + return false; + #endif } - value lime_window_get_vulkan_instance_extensions (value window) { + HL_PRIM bool HL_NAME(hl_system_get_ios_tablet) () { - Window* targetWindow = (Window*)val_data (window); - unsigned int count = 0; + #ifdef IPHONE + return System::GetIOSTablet (); + #else + return false; + #endif - if (!targetWindow->GetVulkanInstanceExtensions (&count, 0) || count == 0) { + } - return alloc_array (0); - } + int lime_system_get_num_displays () { - std::vector names (count); - if (!targetWindow->GetVulkanInstanceExtensions (&count, names.data ())) { + return System::GetNumDisplays (); - return alloc_array (0); + } - } - value result = alloc_array (count); + HL_PRIM int HL_NAME(hl_system_get_num_displays) () { - for (unsigned int i = 0; i < count; ++i) { + return System::GetNumDisplays (); - val_array_set_i (result, i, alloc_string (names[i])); + } - } - return result; + int lime_system_get_device_orientation () { + + return System::GetDeviceOrientation(); } - HL_PRIM hl_varray* HL_NAME(hl_window_get_vulkan_instance_extensions) (HL_CFFIPointer* window) { + HL_PRIM int HL_NAME(hl_system_get_device_orientation) () { - Window* targetWindow = (Window*)window->ptr; - unsigned int count = 0; + return System::GetDeviceOrientation(); - if (!targetWindow->GetVulkanInstanceExtensions (&count, 0) || count == 0) { + } - return hl_alloc_array (&hlt_bytes, 0); - } + value lime_system_get_platform_label () { - std::vector names (count); - if (!targetWindow->GetVulkanInstanceExtensions (&count, names.data ())) { + std::wstring* label = System::GetPlatformLabel (); - return hl_alloc_array (&hlt_bytes, 0); + if (label) { + + value result = alloc_wstring (label->c_str ()); + delete label; + return result; + + } else { + + return alloc_null (); } - 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); + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_label) () { - } + #ifndef EMSCRIPTEN - return result; + std::wstring* label = System::GetPlatformLabel (); - } + if (label) { + vbyte* const result = hl_wstring_to_utf8_bytes (*label); + delete label; + 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); + #endif - 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; + return 0; } - HL_PRIM vdynamic* HL_NAME(hl_window_get_vulkan_drawable_size) (HL_CFFIPointer* window) { + value lime_system_get_platform_name () { - Window* targetWindow = (Window*)window->ptr; - int width = 0; - int height = 0; - targetWindow->GetVulkanDrawableSize (&width, &height); + std::wstring* name = System::GetPlatformName (); - 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; + if (name) { - } + value result = alloc_wstring (name->c_str ()); + delete name; + return result; + } else { - value lime_window_get_vulkan_instance_proc_addr (value window) { + return 0; - 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) { + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_name) () { - Window* targetWindow = (Window*)window->ptr; - return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)targetWindow->GetVulkanInstanceProcAddr ()); + #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_window_create_vulkan_surface (value window, int instanceHigh, int instanceLow) { + value lime_system_get_platform_version () { - Window* targetWindow = (Window*)val_data (window); - uint64_t surface = targetWindow->CreateVulkanSurface ((uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow)); + std::wstring* version = System::GetPlatformVersion (); - if (!surface) { + if (version) { + + value result = alloc_wstring (version->c_str ()); + delete version; + return result; + + } else { return alloc_null (); } - return CreateVulkanHandleValue (surface); - } - HL_PRIM vdynamic* HL_NAME(hl_window_create_vulkan_surface) (HL_CFFIPointer* window, int instanceHigh, int instanceLow) { + HL_PRIM vbyte* HL_NAME(hl_system_get_platform_version) () { - Window* targetWindow = (Window*)window->ptr; - uint64_t surface = targetWindow->CreateVulkanSurface ((uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow)); + #ifndef EMSCRIPTEN - if (!surface) { + std::wstring* version = System::GetPlatformVersion (); - return 0; + if (version) { + vbyte* const result = hl_wstring_to_utf8_bytes (*version); + delete version; + return result; } - return HLCreateVulkanHandleValue (surface); + #endif + + return 0; } - value lime_vk_create_instance (value window, HxString applicationName) { + double lime_system_get_timer () { -#ifdef LIME_VULKAN - Window* targetWindow = (Window*)val_data (window); - VkInstance instance = VK_NULL_HANDLE; + return System::GetTimer (); - if (!CreateManagedVulkanInstance (targetWindow, applicationName.c_str () ? hxs_utf8 (applicationName, nullptr) : 0, &instance)) { + } - return alloc_null (); - } + HL_PRIM double HL_NAME(hl_system_get_timer) () { - return CreateVulkanHandleValue ((uint64_t)(uintptr_t)instance); -#else - lastVKError = "Lime was built without lime-vulkan support"; - return alloc_null (); -#endif + return System::GetTimer (); } - HL_PRIM vdynamic* HL_NAME(hl_vk_create_instance) (HL_CFFIPointer* window, hl_vstring* applicationName) { + int lime_system_get_windows_console_mode (int handleType) { -#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 defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::GetWindowsConsoleMode (handleType); + #else + return 0; + #endif - if (!CreateManagedVulkanInstance (targetWindow, applicationNameUTF8, &instance)) { + } - return 0; - } + HL_PRIM int HL_NAME(hl_system_get_windows_console_mode) (int handleType) { - return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)instance); -#else - lastVKError = "Lime was built without lime-vulkan support"; + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::GetWindowsConsoleMode (handleType); + #else return 0; -#endif + #endif } - void lime_vk_destroy_instance (value window, int instanceHigh, int instanceLow) { + void lime_system_open_file (HxString path) { -#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; + #ifdef IPHONE + System::OpenFile (path.c_str ()); + #endif - 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_system_open_file) (vbyte* path) { + + #ifdef IPHONE + System::OpenFile ((char*)path); + #endif } - HL_PRIM void HL_NAME(hl_vk_destroy_instance) (HL_CFFIPointer* window, int instanceHigh, int instanceLow) { + void lime_system_open_url (HxString url, HxString target) { -#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; + #ifdef IPHONE + System::OpenURL (url.c_str (), target.c_str ()); + #endif - 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_system_open_url) (vbyte* url, vbyte* target) { + + #ifdef IPHONE + System::OpenURL ((char*)url, (char*)target); + #endif } - void lime_vk_destroy_surface (value window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + bool lime_system_set_allow_screen_timeout (bool allow) { -#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; + return System::SetAllowScreenTimeout (allow); - 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); + HL_PRIM bool HL_NAME(hl_system_set_allow_screen_timeout) (bool allow) { - } -#else - lastVKError = "Lime was built without lime-vulkan support"; -#endif + return System::SetAllowScreenTimeout (allow); } - HL_PRIM void HL_NAME(hl_vk_destroy_surface) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + bool lime_system_set_windows_console_mode (int handleType, int mode) { -#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; + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::SetWindowsConsoleMode (handleType, mode); + #else + return false; + #endif - 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); + HL_PRIM bool HL_NAME(hl_system_set_windows_console_mode) (int handleType, int mode) { - } -#else - lastVKError = "Lime was built without lime-vulkan support"; -#endif + #if defined (HX_WINDOWS) && !defined (HX_WINRT) + return System::SetWindowsConsoleMode (handleType, mode); + #else + return false; + #endif } - value lime_vk_get_physical_devices (value window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + void lime_text_event_manager_register (value callback, value eventObject) { -#ifdef LIME_VULKAN - Window* targetWindow = (Window*)val_data (window); - VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + TextEvent::callback = new ValuePointer (callback); + TextEvent::eventObject = new ValuePointer (eventObject); - if (!targetWindow || !instance) { + } - lastVKError = "Missing Vulkan window or instance"; - return alloc_null (); - } + HL_PRIM void HL_NAME(hl_text_event_manager_register) (vclosure* callback, TextEvent* eventObject) { - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); - if (!vkGetInstanceProcAddr) { + TextEvent::callback = new ValuePointer (callback); + TextEvent::eventObject = new ValuePointer ((vobj*)eventObject); - 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"); + void lime_touch_event_manager_register (value callback, value eventObject) { - if (!vkEnumeratePhysicalDevices || !vkGetPhysicalDeviceProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { + TouchEvent::callback = new ValuePointer (callback); + TouchEvent::eventObject = new ValuePointer (eventObject); - 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); + HL_PRIM void HL_NAME(hl_touch_event_manager_register) (vclosure* callback, TouchEvent* eventObject) { - if (result != VK_SUCCESS) { + TouchEvent::callback = new ValuePointer (callback); + TouchEvent::eventObject = new ValuePointer ((vobj*)eventObject); - lastVKError = "vkEnumeratePhysicalDevices failed"; - return alloc_null (); + } - } - value devices = alloc_array (deviceCount); + 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_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_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; + 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_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_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 + Window* targetWindow = (Window*)val_data (window); + VkInstance instance = (VkInstance)(uintptr_t)CombineVulkanHandle (instanceHigh, instanceLow); + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)(uintptr_t)CombineVulkanHandle (physicalDeviceHigh, physicalDeviceLow); + std::vector deviceExtensions = GetVulkanDeviceExtensions (extensions); + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; + + if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { + + return alloc_null (); + + } + + 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)); + 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) { + + 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) { + + 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) { + + lastVKError = "vkQueueSubmit 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_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) { + + lastVKError = "vkQueueSubmit failed"; + 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) { + + 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) { + + 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 + + } + + + 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; + + } + + 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 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_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_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_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 + + } + + + 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_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 + + } + + + 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_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 + + } + + + 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_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 + + } + + + void lime_vk_destroy_image_view (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int imageViewHigh, + int imageViewLow) { + +#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 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_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 + + } + + + 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_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 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_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 + + } + + + value lime_vk_create_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int colorFormat, + int depthStencilFormat, int samples, int colorLoadOp, int colorStoreOp, int colorInitialLayout, int colorFinalLayout, int depthLoadOp, + int depthStoreOp, int depthFinalLayout) { + +#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 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; + 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 = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; + attachments.push_back (depthAttachment); + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } + + VkSubpassDescription subpass; + memset (&subpass, 0, sizeof (subpass)); + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + 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, int colorFormat, int depthStencilFormat, int samples, int colorLoadOp, int colorStoreOp, int colorInitialLayout, + int colorFinalLayout, int depthLoadOp, int depthStoreOp, int depthFinalLayout) { + +#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 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; + 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 = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; + attachments.push_back (depthAttachment); + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } + + VkSubpassDescription subpass; + memset (&subpass, 0, sizeof (subpass)); + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + 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 + + } + + 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 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_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 + + } + + + 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_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 (); + + } + + std::vector imageViews; + imageViews.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { + + 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 (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)framebuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + 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_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; + + } + + std::vector imageViews; + imageViews.reserve ((size_t)packed[0]); + for (int i = 0; i < packed[0]; ++i) { + + 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; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)framebuffer); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_framebuffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int framebufferHigh, + int framebufferLow) { + +#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 void HL_NAME(hl_vk_destroy_framebuffer) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int framebufferHigh, int framebufferLow) { + +#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_vk_create_shader_module (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, 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); + Bytes data (bytes); + if (!data.b || byteOffset < 0 || byteLength <= 0 || byteOffset + byteLength > data.length || (byteLength % 4) != 0) { + + lastVKError = "Invalid Vulkan shader module bytes"; + return alloc_null (); + + } + + PFN_vkCreateShaderModule vkCreateShaderModule = (PFN_vkCreateShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateShaderModule"); + if (!vkCreateShaderModule) return alloc_null (); + + 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); + + VkShaderModule shaderModule = VK_NULL_HANDLE; + VkResult result = vkCreateShaderModule (device, &createInfo, 0, &shaderModule); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateShaderModule failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)shaderModule); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + 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) { + +#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) { + + lastVKError = "Invalid Vulkan shader module bytes"; + return 0; + + } + + PFN_vkCreateShaderModule vkCreateShaderModule = (PFN_vkCreateShaderModule)GetManagedVulkanDeviceProc (targetWindow, instance, device, + "vkCreateShaderModule"); + if (!vkCreateShaderModule) return 0; + + 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); + + VkShaderModule shaderModule = VK_NULL_HANDLE; + VkResult result = vkCreateShaderModule (device, &createInfo, 0, &shaderModule); + if (result != VK_SUCCESS) { + + lastVKError = "vkCreateShaderModule failed"; + return 0; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)shaderModule); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_shader_module (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int shaderModuleHigh, + int shaderModuleLow) { + +#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) { + + vkDestroyShaderModule (device, shaderModule, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + 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) { + +#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 (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + 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) { + +#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 (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)sampler); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + 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; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)sampler); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_sampler (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int samplerHigh, int samplerLow) { + +#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) { + + vkDestroySampler (device, sampler, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + 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_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_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); + + } + + 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) { + + lastVKError = "vkCreateDescriptorSetLayout 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 + + } + + + 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_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); + + } + + 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; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + + void lime_vk_destroy_descriptor_set_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { + +#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) { + + vkDestroyDescriptorSetLayout (device, layout, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + 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) { + +#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) { + + vkDestroyDescriptorSetLayout (device, layout, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_create_descriptor_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value poolSizes) { + +#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 (); + + 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); + + } + + PFN_vkCreateDescriptorPool vkCreateDescriptorPool = + (PFN_vkCreateDescriptorPool)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateDescriptorPool"); + if (!vkCreateDescriptorPool) return alloc_null (); + + 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) { + + lastVKError = "vkCreateDescriptorPool failed"; + return alloc_null (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)pool); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + 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_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); + + } + + 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) { + + lastVKError = "vkCreateDescriptorPool failed"; + return 0; + + } + + 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) () { + + return hl_copy_bytes ((const vbyte*)lastVKError.c_str (), (int)lastVKError.size () + 1); + + } + + + 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_vk_destroy_descriptor_pool) (HL_CFFIPointer* 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*)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) { + + vkDestroyDescriptorPool (device, pool, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_allocate_descriptor_set (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, + int poolLow, int layoutHigh, int layoutLow) { + +#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 (); + + } + + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)descriptorSet); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif + + } + + + 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 + + } + + + 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) { + +#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 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) { + +#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) { + + 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 (); + + } + + lastVulkanRendererError.clear (); + return CFFIPointer (renderer); + + } + + + 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) { + +#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 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_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_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, + int pushConstantStages, int pushConstantSize) { + +#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])); + + } + + 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 + + } + + + 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) { + +#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; + + 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])); + + } + + 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; + + } + + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)layout); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif + + } + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { + + Window* targetWindow = (Window*)window->ptr; + VulkanRenderer* renderer = new VulkanRenderer (targetWindow); + const char* applicationNameUTF8 = applicationName ? (const char*)hl_to_utf8 ((const uchar*)applicationName->bytes) : 0; + + if (!renderer->Create (applicationNameUTF8)) { + + lastVulkanRendererError = renderer->GetLastError (); + delete renderer; + return 0; + + } + + lastVulkanRendererError.clear (); + return HLCFFIPointer (renderer); + + } + + + void lime_vk_destroy_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { + +#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) { + + vkDestroyPipelineLayout (device, layout, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - std::vector physicalDevices (deviceCount); - result = vkEnumeratePhysicalDevices (instance, &deviceCount, physicalDevices.data ()); + } + + + 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) { + +#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) { + + vkDestroyPipelineLayout (device, layout, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + value lime_vk_create_pipeline_cache (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_vkCreatePipelineCache vkCreatePipelineCache = + (PFN_vkCreatePipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineCache"); + if (!vkCreatePipelineCache) return alloc_null (); + + VkPipelineCacheCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + + VkPipelineCache cache = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); if (result != VK_SUCCESS) { - lastVKError = "vkEnumeratePhysicalDevices returned incomplete data"; + lastVKError = "vkCreatePipelineCache failed"; 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_queueFamilies = val_id ("queueFamilies"); + lastVKError.clear (); + return CreateVulkanHandleValue ((uint64_t)(uintptr_t)cache); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); +#endif - 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); + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow) { - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, 0); - std::vector queueFamilies (queueFamilyCount); - if (queueFamilyCount > 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_vkCreatePipelineCache vkCreatePipelineCache = + (PFN_vkCreatePipelineCache)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreatePipelineCache"); + if (!vkCreatePipelineCache) return 0; - vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, queueFamilies.data ()); + VkPipelineCacheCreateInfo createInfo; + memset (&createInfo, 0, sizeof (createInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; - } + VkPipelineCache cache = VK_NULL_HANDLE; + VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); + if (result != VK_SUCCESS) { - value queueFamilyArray = alloc_array (queueFamilyCount); + lastVKError = "vkCreatePipelineCache failed"; + return 0; - for (uint32_t q = 0; q < queueFamilyCount; ++q) { + } - VkBool32 supportsPresent = VK_FALSE; - if (surface && vkGetPhysicalDeviceSurfaceSupportKHR) { + lastVKError.clear (); + return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)cache); +#else + lastVKError = "Lime was built without lime-vulkan support"; + return 0; +#endif - 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); + void lime_vk_destroy_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow) { - } +#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) { - 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_queueFamilies, queueFamilyArray); - val_array_set_i (devices, i, deviceObject); + vkDestroyPipelineCache (device, cache, 0); + lastVKError.clear (); + + } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif + + } + + + 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) { + +#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 + + } + + void lime_vulkan_renderer_destroy (value handle) { + + if (val_is_null (handle)) return; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + delete renderer; + + } + + +#ifdef LIME_VULKAN + static VkPipeline CreateManagedVulkanGraphicsPipeline (Window* targetWindow, VkInstance instance, VkDevice device, VkRenderPass renderPass, + VkPipelineLayout layout, VkShaderModule vertexShader, VkShaderModule fragmentShader, const std::vector& state) { + + if (state.size () < 19 || !renderPass || !layout || !vertexShader || !fragmentShader) { + + lastVKError = "Invalid Vulkan graphics pipeline state"; + return VK_NULL_HANDLE; + + } + + 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 bindingCount = state[cursor++]; + + if ((int)state.size () < cursor + bindingCount * 3 + 1) { + + lastVKError = "Invalid Vulkan vertex binding state"; + return VK_NULL_HANDLE; + + } + + 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); + + } + + int attributeCount = state[cursor++]; + if ((int)state.size () < cursor + attributeCount * 4) { + + lastVKError = "Invalid Vulkan vertex attribute state"; + return VK_NULL_HANDLE; + + } + + std::vector attributes; + attributes.reserve ((size_t)attributeCount); + for (int i = 0; i < attributeCount; ++i) { + + 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); + + } + + 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 = VK_SAMPLE_COUNT_1_BIT; + + 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; + + VkPipelineColorBlendAttachmentState colorAttachment; + memset (&colorAttachment, 0, sizeof (colorAttachment)); + colorAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + 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 devices; + return pipeline; + + } + +#endif + + + 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) { + +#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_array (0); + return alloc_null (); #endif } - HL_PRIM hl_varray* HL_NAME(hl_vk_get_physical_devices) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int surfaceHigh, int surfaceLow) { + 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) { #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 - 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"); + void lime_vk_destroy_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int pipelineHigh, int pipelineLow) { - if (!vkEnumeratePhysicalDevices || !vkGetPhysicalDeviceProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { +#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) { - lastVKError = "Missing required Vulkan instance functions"; - return 0; + vkDestroyPipeline (device, pipeline, 0); + lastVKError.clear (); } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - 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_PRIM void HL_NAME(hl_vk_destroy_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int pipelineHigh, int pipelineLow) { - hl_varray* devices = (hl_varray*)hl_alloc_array (&hlt_dynobj, deviceCount); - if (deviceCount == 0) { +#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 (); - return devices; } +#else + lastVKError = "Lime was built without lime-vulkan support"; +#endif - std::vector physicalDevices (deviceCount); - result = vkEnumeratePhysicalDevices (instance, &deviceCount, physicalDevices.data ()); + } - if (result != VK_SUCCESS) { + HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) { - lastVKError = "vkEnumeratePhysicalDevices returned incomplete data"; - return 0; + if (!handle || !handle->ptr) return; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + handle->ptr = 0; + delete renderer; - } + } - 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_queueFamilies = hl_hash_utf8 ("queueFamilies"); + 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) { - 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"); +#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; - for (uint32_t i = 0; i < deviceCount; ++i) { + 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; - VkPhysicalDeviceProperties properties; - memset (&properties, 0, sizeof (properties)); - vkGetPhysicalDeviceProperties (physicalDevices[i], &properties); + 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; - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, 0); - std::vector queueFamilies (queueFamilyCount); - if (queueFamilyCount > 0) { + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { - vkGetPhysicalDeviceQueueFamilyProperties (physicalDevices[i], &queueFamilyCount, queueFamilies.data ()); + lastVKError = "vkQueueSubmit failed"; + return false; - } + } - hl_varray* queueFamilyArray = (hl_varray*)hl_alloc_array (&hlt_dynobj, queueFamilyCount); - vdynamic** queueFamilyData = hl_aptr (queueFamilyArray, vdynamic*); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - for (uint32_t q = 0; q < queueFamilyCount; ++q) { + } - VkBool32 supportsPresent = VK_FALSE; - if (surface && vkGetPhysicalDeviceSurfaceSupportKHR) { - vkGetPhysicalDeviceSurfaceSupportKHR (physicalDevices[i], q, surface, &supportsPresent); + 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) { - } +#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; - 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); + 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; - 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_setp (deviceObject, id_queueFamilies, &hlt_array, queueFamilyArray); + VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); + if (result != VK_SUCCESS) { + + lastVKError = "vkQueueSubmit failed"; + return false; } lastVKError.clear (); - return devices; + return true; #else lastVKError = "Lime was built without lime-vulkan support"; - return (hl_varray*)hl_alloc_array (&hlt_dynobj, 0); + return false; #endif } - value lime_vk_create_device (value window, int instanceHigh, int instanceLow, int physicalDeviceHigh, int physicalDeviceLow, int queueFamilyIndex, - value extensions) { + 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) { #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); - std::vector deviceExtensions = GetVulkanDeviceExtensions (extensions); - VkDevice device = VK_NULL_HANDLE; - VkQueue queue = VK_NULL_HANDLE; - - if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { - - return alloc_null (); - - } - - 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)); - return result; + 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 alloc_null (); + return false; #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) { + 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) { #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; + 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 - if (!CreateManagedVulkanDevice (targetWindow, instance, physicalDevice, queueFamilyIndex, deviceExtensions, &device, &queue)) { + } - return 0; - } + bool lime_vk_cmd_end_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow) { - 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; +#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 0; + return false; #endif } - void lime_vk_destroy_device (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + 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 LIME_VULKAN - if (deviceHigh == 0 && deviceLow == 0) return; - Window* targetWindow = (Window*)val_data (window); + 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_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 - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); - if (!vkGetDeviceProcAddr) return; + } - PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (device, "vkDestroyDevice"); - if (vkDestroyDevice) { - vkDestroyDevice (device, 0); + 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 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_vk_destroy_device) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + 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) { #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) { - - vkDestroyDevice (device, 0); - - } + 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 } - bool lime_vk_device_wait_idle (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + 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) { #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 (); + 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"; @@ -4700,45 +9745,75 @@ namespace lime { } - HL_PRIM bool HL_NAME(hl_vk_device_wait_idle) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + 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) { #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_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 - } + } - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr (instance, "vkGetDeviceProcAddr"); - if (!vkGetDeviceProcAddr) { + value lime_vulkan_renderer_get_info (value handle) { - lastVKError = "Missing Vulkan device proc address function"; - return false; + if (val_is_null (handle)) return alloc_string (""); + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + return alloc_string (renderer->GetInfo ().c_str ()); - } + } - PFN_vkDeviceWaitIdle vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)vkGetDeviceProcAddr (device, "vkDeviceWaitIdle"); - if (!vkDeviceWaitIdle) { - lastVKError = "Missing Vulkan device wait idle function"; - return false; + 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) { - } +#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 - VkResult result = vkDeviceWaitIdle (device); - if (result != VK_SUCCESS) { + } - lastVKError = "vkDeviceWaitIdle failed"; - return false; - } + 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) { - lastVKError.clear (); +#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"; @@ -4748,46 +9823,19 @@ namespace lime { } - bool lime_vk_queue_wait_idle (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueHigh, int queueLow) { + 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) { #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 (); + 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"; @@ -4797,47 +9845,47 @@ namespace lime { } - 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) { + 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 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; - - } + 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 - VkResult result = vkQueueWaitIdle (queue); - if (result != VK_SUCCESS) { + } - lastVKError = "vkQueueWaitIdle failed"; - return false; - } + 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) { - lastVKError.clear (); +#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"; @@ -4847,136 +9895,144 @@ namespace lime { } - value lime_vk_create_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int queueFamilyIndex, int flags) { + 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) { #ifdef LIME_VULKAN - Window* targetWindow = (Window*)val_data (window); + 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 alloc_null (); + 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 - 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) { + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { - lastVKError = "vkCreateCommandPool failed"; - return alloc_null (); + 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); - } + } - lastVKError.clear (); - return CreateVulkanHandleValue ((uint64_t)(uintptr_t)commandPool); + + 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) { + +#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 alloc_null (); + return false; #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) { + 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) { #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); + 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 0; + return false; #endif } - void lime_vk_destroy_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, - int commandPoolLow) { + 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) { #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); + 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 void HL_NAME(hl_vk_destroy_command_pool) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, - int commandPoolHigh, int commandPoolLow) { + 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) { #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); + 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 } - bool lime_vk_reset_command_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, - int commandPoolLow, int flags) { + 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) { #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 (); + 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"; @@ -4986,27 +10042,18 @@ namespace lime { } - 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) { + 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) { #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 (); + 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"; @@ -5015,149 +10062,203 @@ namespace lime { } + value lime_vulkan_renderer_get_last_error () { + + return alloc_string (lastVulkanRendererError.c_str ()); + + } + - value lime_vk_allocate_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandPoolHigh, - int commandPoolLow, int level) { + 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 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); + 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 alloc_null (); + return false; #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) { + 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_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); + 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 0; + return false; #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) { + bool lime_vk_cmd_copy_buffer_to_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, int height, int layout) { #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); + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage = + (PFN_vkCmdCopyBufferToImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBufferToImage"); 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); + if (!vkCmdCopyBufferToImage || !commandBuffer) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = (uint32_t)width; + region.imageExtent.height = (uint32_t)height; + region.imageExtent.depth = 1; + vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), + (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, 1, ®ion); + return true; #else lastVKError = "Lime was built without lime-vulkan support"; + return false; #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) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, + int height, int layout) { #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); + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage = + (PFN_vkCmdCopyBufferToImage)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCmdCopyBufferToImage"); 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); + if (!vkCmdCopyBufferToImage || !commandBuffer) return false; + + VkBufferImageCopy region; + memset (®ion, 0, sizeof (region)); + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = (uint32_t)width; + region.imageExtent.height = (uint32_t)height; + region.imageExtent.depth = 1; + vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), + (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, 1, ®ion); + return true; #else lastVKError = "Lime was built without lime-vulkan support"; + return false; #endif } + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { + + return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); + + } - bool lime_vk_begin_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, - int commandBufferLow, int flags) { + + 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) { #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); - 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; + 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 - VkResult result = vkBeginCommandBuffer (commandBuffer, &beginInfo); - if (result != VK_SUCCESS) { + } - lastVKError = "vkBeginCommandBuffer failed"; - return false; - } + 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) { - lastVKError.clear (); +#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"; @@ -5167,32 +10268,63 @@ namespace lime { } - 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) { + 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) { #ifdef LIME_VULKAN - Window* targetWindow = (Window*)window->ptr; + 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); - 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; + 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 - VkResult result = vkBeginCommandBuffer (commandBuffer, &beginInfo); - if (result != VK_SUCCESS) { + } - lastVKError = "vkBeginCommandBuffer failed"; - return false; - } + 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) { - lastVKError.clear (); +#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"; @@ -5202,27 +10334,67 @@ namespace lime { } - bool lime_vk_end_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, - int commandBufferLow) { + 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) { #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); - PFN_vkEndCommandBuffer vkEndCommandBuffer = (PFN_vkEndCommandBuffer)GetManagedVulkanDeviceProc (targetWindow, instance, device, - "vkEndCommandBuffer"); - if (!vkEndCommandBuffer) return false; + std::vector packed = GetVulkanIntVector (state); + if (!vkCmdBlitImage || !commandBuffer || packed.size () < 5) return false; + + VkImageBlit blit; + memset (&blit, 0, sizeof (blit)); + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.layerCount = 1; + blit.srcOffsets[1].x = packed[0]; + blit.srcOffsets[1].y = packed[1]; + blit.srcOffsets[1].z = 1; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.layerCount = 1; + blit.dstOffsets[1].x = packed[0]; + blit.dstOffsets[1].y = packed[1]; + blit.dstOffsets[1].z = 1; + vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)packed[2], + (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)packed[3], 1, &blit, (VkFilter)packed[4]); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif - VkResult result = vkEndCommandBuffer (commandBuffer); - if (result != VK_SUCCESS) { + } - lastVKError = "vkEndCommandBuffer failed"; - return false; - } + 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) { - lastVKError.clear (); +#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 () < 5) return false; + + VkImageBlit blit; + memset (&blit, 0, sizeof (blit)); + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.layerCount = 1; + blit.srcOffsets[1].x = packed[0]; + blit.srcOffsets[1].y = packed[1]; + blit.srcOffsets[1].z = 1; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.layerCount = 1; + blit.dstOffsets[1].x = packed[0]; + blit.dstOffsets[1].y = packed[1]; + blit.dstOffsets[1].z = 1; + vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)packed[2], + (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)packed[3], 1, &blit, (VkFilter)packed[4]); return true; #else lastVKError = "Lime was built without lime-vulkan support"; @@ -5231,687 +10403,497 @@ namespace lime { } + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { + + 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 bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { + + 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; + + } + + + bool lime_vulkan_renderer_clear_overlay (value handle) { + + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + + + HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { + + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->ClearOverlay (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } + - 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) { + bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { -#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; + 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; - VkResult result = vkEndCommandBuffer (commandBuffer); - if (result != VK_SUCCESS) { + } - lastVKError = "vkEndCommandBuffer failed"; - return false; - } + HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Render (red, green, blue, alpha); + lastVulkanRendererError = renderer->GetLastError (); + return result; } - bool lime_vk_reset_command_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, - int commandBufferLow, int flags) { + bool lime_vulkan_renderer_resize (value handle) { -#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; + if (val_is_null (handle)) return false; + VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; - VkResult result = vkResetCommandBuffer (commandBuffer, flags); - if (result != VK_SUCCESS) { + } - lastVKError = "vkResetCommandBuffer failed"; - return false; - } + HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { - lastVKError.clear (); - return true; + if (!handle || !handle->ptr) return false; + VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; + bool result = renderer->Resize (); + lastVulkanRendererError = renderer->GetLastError (); + return result; + + } #else + static inline bool LimeVulkanUnavailableBool () { + 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) { + static inline value LimeVulkanUnavailableValue () { -#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; + lastVKError = "Lime was built without lime-vulkan support"; + return alloc_null (); - VkResult result = vkResetCommandBuffer (commandBuffer, flags); - if (result != VK_SUCCESS) { + } - lastVKError = "vkResetCommandBuffer failed"; - return false; - } + static inline vdynamic* HLLimeVulkanUnavailableValue () { - lastVKError.clear (); - return true; -#else lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + return 0; } - 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 (); + static inline void LimeVulkanUnavailableVoid () { - VkSemaphoreCreateInfo createInfo; - memset (&createInfo, 0, sizeof (createInfo)); - createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + lastVKError = "Lime was built without lime-vulkan support"; - VkSemaphore semaphore = VK_NULL_HANDLE; - VkResult result = vkCreateSemaphore (device, &createInfo, 0, &semaphore); - if (result != VK_SUCCESS) { + } - lastVKError = "vkCreateSemaphore failed"; - return alloc_null (); - } + 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) { - lastVKError.clear (); - return CreateVulkanHandleValue ((uint64_t)(uintptr_t)semaphore); -#else - lastVKError = "Lime was built without lime-vulkan support"; - return alloc_null (); -#endif + return LimeVulkanUnavailableBool (); } - 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; + 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) { - VkSemaphoreCreateInfo createInfo; - memset (&createInfo, 0, sizeof (createInfo)); - createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + return LimeVulkanUnavailableBool (); - VkSemaphore semaphore = VK_NULL_HANDLE; - VkResult result = vkCreateSemaphore (device, &createInfo, 0, &semaphore); - if (result != VK_SUCCESS) { + } - lastVKError = "vkCreateSemaphore failed"; - return 0; - } + value lime_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, + int pushConstantStages, int pushConstantSize) { - lastVKError.clear (); - return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)semaphore); -#else - lastVKError = "Lime was built without lime-vulkan support"; - return 0; -#endif + return LimeVulkanUnavailableValue (); } - void lime_vk_destroy_semaphore (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int semaphoreHigh, - int semaphoreLow) { + 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) { -#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 + return HLLimeVulkanUnavailableValue (); } - HL_PRIM void HL_NAME(hl_vk_destroy_semaphore) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, - int semaphoreHigh, int semaphoreLow) { + void lime_vk_destroy_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int layoutHigh, + int layoutLow) { -#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 + LimeVulkanUnavailableVoid (); } - 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 (); + 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) { - VkFenceCreateInfo createInfo; - memset (&createInfo, 0, sizeof (createInfo)); - createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - createInfo.flags = flags; + LimeVulkanUnavailableVoid (); - VkFence fence = VK_NULL_HANDLE; - VkResult result = vkCreateFence (device, &createInfo, 0, &fence); - if (result != VK_SUCCESS) { + } - lastVKError = "vkCreateFence failed"; - return alloc_null (); - } + value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { - lastVKError.clear (); - return CreateVulkanHandleValue ((uint64_t)(uintptr_t)fence); -#else - lastVKError = "Lime was built without lime-vulkan support"; - return alloc_null (); -#endif + return LimeVulkanUnavailableValue (); } - 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; + HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow) { - VkFenceCreateInfo createInfo; - memset (&createInfo, 0, sizeof (createInfo)); - createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - createInfo.flags = flags; + return HLLimeVulkanUnavailableValue (); - VkFence fence = VK_NULL_HANDLE; - VkResult result = vkCreateFence (device, &createInfo, 0, &fence); - if (result != VK_SUCCESS) { + } - lastVKError = "vkCreateFence failed"; - return 0; - } + void lime_vk_destroy_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow) { - lastVKError.clear (); - return HLCreateVulkanHandleValue ((uint64_t)(uintptr_t)fence); -#else - lastVKError = "Lime was built without lime-vulkan support"; - return 0; -#endif + LimeVulkanUnavailableVoid (); } - void lime_vk_destroy_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow) { + 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) { -#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 + LimeVulkanUnavailableVoid (); } - HL_PRIM void HL_NAME(hl_vk_destroy_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, - int fenceLow) { + 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) { -#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 + return LimeVulkanUnavailableValue (); } - bool lime_vk_wait_for_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow, - int timeoutHigh, int timeoutLow) { + 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) { -#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; + return HLLimeVulkanUnavailableValue (); - VkResult result = vkWaitForFences (device, 1, &fence, VK_TRUE, timeout); - if (result != VK_SUCCESS) { + } - lastVKError = "vkWaitForFences failed"; - return false; - } + void lime_vk_destroy_pipeline (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int pipelineHigh, + int pipelineLow) { - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + LimeVulkanUnavailableVoid (); } - 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) { + HL_PRIM void HL_NAME(hl_vk_destroy_pipeline) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int pipelineHigh, int pipelineLow) { -#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; + LimeVulkanUnavailableVoid (); - VkResult result = vkWaitForFences (device, 1, &fence, VK_TRUE, timeout); - if (result != VK_SUCCESS) { + } - lastVKError = "vkWaitForFences failed"; - return false; - } + 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) { - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + return LimeVulkanUnavailableBool (); } - bool lime_vk_reset_fence (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, int fenceLow) { + 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) { -#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; + return LimeVulkanUnavailableBool (); - VkResult result = vkResetFences (device, 1, &fence); - if (result != VK_SUCCESS) { + } - lastVKError = "vkResetFences failed"; - return false; - } + 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) { - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_vk_reset_fence) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int fenceHigh, - int fenceLow) { + 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) { -#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; + return LimeVulkanUnavailableBool (); - VkResult result = vkResetFences (device, 1, &fence); - if (result != VK_SUCCESS) { + } - lastVKError = "vkResetFences failed"; - return false; - } + bool lime_vk_cmd_end_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow) { - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + return LimeVulkanUnavailableBool (); } - 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) { + 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 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; + return LimeVulkanUnavailableBool (); - 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) { - lastVKError = "vkQueueSubmit failed"; - return false; + 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) { - } + return LimeVulkanUnavailableBool (); + + } - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + + 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 LimeVulkanUnavailableBool (); } - 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) { + 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) { -#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; + return LimeVulkanUnavailableBool (); - 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) { - lastVKError = "vkQueueSubmit failed"; - return false; + 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 LimeVulkanUnavailableBool (); + + } - lastVKError.clear (); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif + + 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 (); } - value lime_vk_get_last_error () { + 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 alloc_string (lastVKError.c_str ()); + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_vk_get_last_error) () { + 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) { - return hl_copy_bytes ((const vbyte*)lastVKError.c_str (), (int)lastVKError.size () + 1); + return LimeVulkanUnavailableBool (); } -#ifdef LIME_VULKAN - value lime_vulkan_renderer_create (value window, HxString applicationName) { + 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) { - Window* targetWindow = (Window*)val_data (window); - VulkanRenderer* renderer = new VulkanRenderer (targetWindow); + return LimeVulkanUnavailableBool (); - if (!renderer->Create (applicationName.c_str () ? hxs_utf8 (applicationName, nullptr) : 0)) { + } - lastVulkanRendererError = renderer->GetLastError (); - delete renderer; - return alloc_null (); - } + 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) { - lastVulkanRendererError.clear (); - return CFFIPointer (renderer); + return LimeVulkanUnavailableBool (); } - HL_PRIM HL_CFFIPointer* HL_NAME(hl_vulkan_renderer_create) (HL_CFFIPointer* window, hl_vstring* applicationName) { + 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) { - Window* targetWindow = (Window*)window->ptr; - VulkanRenderer* renderer = new VulkanRenderer (targetWindow); - const char* applicationNameUTF8 = applicationName ? (const char*)hl_to_utf8 ((const uchar*)applicationName->bytes) : 0; + return LimeVulkanUnavailableBool (); - if (!renderer->Create (applicationNameUTF8)) { + } - lastVulkanRendererError = renderer->GetLastError (); - delete renderer; - 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) { - lastVulkanRendererError.clear (); - return HLCFFIPointer (renderer); + return LimeVulkanUnavailableBool (); } - void lime_vulkan_renderer_destroy (value handle) { + 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) { - if (val_is_null (handle)) return; - VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); - delete renderer; + return LimeVulkanUnavailableBool (); } - HL_PRIM void HL_NAME(hl_vulkan_renderer_destroy) (HL_CFFIPointer* handle) { + 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) { - if (!handle || !handle->ptr) return; - VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; - handle->ptr = 0; - delete renderer; + return LimeVulkanUnavailableBool (); } - value lime_vulkan_renderer_get_info (value handle) { + 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) { - if (val_is_null (handle)) return alloc_string (""); - VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); - return alloc_string (renderer->GetInfo ().c_str ()); + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_info) (HL_CFFIPointer* handle) { + 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) { - 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); + return LimeVulkanUnavailableBool (); } - value lime_vulkan_renderer_get_last_error () { + 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 alloc_string (lastVulkanRendererError.c_str ()); + return LimeVulkanUnavailableBool (); } - HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { + 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 hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); + return LimeVulkanUnavailableBool (); } - bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { + 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) { - 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; + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_vulkan_renderer_set_overlay) (HL_CFFIPointer* handle, Bytes* bytes, int width, int height, int x, int y) { + bool lime_vk_cmd_copy_buffer_to_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, + int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, int height, int layout) { - 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; + return LimeVulkanUnavailableBool (); } - bool lime_vulkan_renderer_clear_overlay (value handle) { + HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, + int height, int layout) { - if (val_is_null (handle)) return false; - VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); - bool result = renderer->ClearOverlay (); - lastVulkanRendererError = renderer->GetLastError (); - return result; + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_vulkan_renderer_clear_overlay) (HL_CFFIPointer* handle) { + 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 (!handle || !handle->ptr) return false; - VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; - bool result = renderer->ClearOverlay (); - lastVulkanRendererError = renderer->GetLastError (); - return result; + return LimeVulkanUnavailableBool (); } - bool lime_vulkan_renderer_render (value handle, double red, double green, double blue, double alpha) { + 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) { - 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; + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_vulkan_renderer_render) (HL_CFFIPointer* handle, double red, double green, double blue, double alpha) { + 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) { - if (!handle || !handle->ptr) return false; - VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; - bool result = renderer->Render (red, green, blue, alpha); - lastVulkanRendererError = renderer->GetLastError (); - return result; + return LimeVulkanUnavailableBool (); } - bool lime_vulkan_renderer_resize (value handle) { + 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) { - if (val_is_null (handle)) return false; - VulkanRenderer* renderer = (VulkanRenderer*)val_data (handle); - bool result = renderer->Resize (); - lastVulkanRendererError = renderer->GetLastError (); - return result; + return LimeVulkanUnavailableBool (); } - HL_PRIM bool HL_NAME(hl_vulkan_renderer_resize) (HL_CFFIPointer* handle) { + 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) { - if (!handle || !handle->ptr) return false; - VulkanRenderer* renderer = (VulkanRenderer*)handle->ptr; - bool result = renderer->Resize (); - lastVulkanRendererError = renderer->GetLastError (); - return result; + return LimeVulkanUnavailableBool (); } -#else + + + 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) { + + return LimeVulkanUnavailableBool (); + + } + + value lime_vulkan_renderer_create (value window, HxString applicationName) { lastVulkanRendererError = "Lime was built without lime-vulkan support"; @@ -6825,6 +11807,62 @@ namespace lime { 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_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_PRIME15 (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_PRIME9 (lime_vk_allocate_descriptor_set); + DEFINE_PRIME14 (lime_vk_update_descriptor_set_image); + DEFINE_PRIME13 (lime_vk_update_descriptor_set_buffer); + DEFINE_PRIME8 (lime_vk_create_pipeline_layout); + DEFINE_PRIME7v (lime_vk_destroy_pipeline_layout); + DEFINE_PRIME5 (lime_vk_create_pipeline_cache); + DEFINE_PRIME7v (lime_vk_destroy_pipeline_cache); + 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_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_PRIME12 (lime_vk_cmd_copy_buffer); + DEFINE_PRIME14 (lime_vk_cmd_copy_buffer_to_image); + DEFINE_PRIME10 (lime_vk_cmd_pipeline_barrier_image); + DEFINE_PRIME12 (lime_vk_cmd_clear_color_image); + DEFINE_PRIME12 (lime_vk_cmd_blit_image); DEFINE_PRIME0 (lime_vk_get_last_error); DEFINE_PRIME2 (lime_vulkan_renderer_create); DEFINE_PRIME1v (lime_vulkan_renderer_destroy); @@ -7060,6 +12098,13 @@ namespace lime { 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_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 (_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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index a33d5fa464..f36431e453 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -414,6 +414,182 @@ class NativeCFFI @: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_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, + colorFormat:Int, depthStencilFormat:Int, samples:Int, colorLoadOp:Int, colorStoreOp:Int, colorInitialLayout:Int, colorFinalLayout:Int, + depthLoadOp:Int, depthStoreOp:Int, depthFinalLayout:Int):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_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_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):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_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_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_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(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, + deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, imageHigh:Int, imageLow:Int, width:Int, + height:Int, layout:Int):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_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; #end @:cffi private static function lime_vk_get_last_error():Dynamic; @@ -789,6 +965,118 @@ class NativeCFFI "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_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->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>( + cpp.Prime._loadPrime("lime", "lime_vk_create_render_pass", "oiiiiiiiiiiiiiio", 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_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_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>(cpp.Prime._loadPrime("lime", + "lime_vk_create_pipeline_cache", "oiiiio", 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_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_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_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 = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( + cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer_to_image", "oiiiiiiiiiiiiib", 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_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)); #end private static var lime_vk_get_last_error = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_vk_get_last_error", "o", false)); @@ -1031,6 +1319,62 @@ class NativeCFFI 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_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_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_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_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_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_copy_buffer = CFFI.load("lime", "lime_vk_cmd_copy_buffer", -1); + private static var lime_vk_cmd_copy_buffer_to_image = CFFI.load("lime", "lime_vk_cmd_copy_buffer_to_image", -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_blit_image = CFFI.load("lime", "lime_vk_cmd_blit_image", -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); @@ -1804,6 +2148,332 @@ class NativeCFFI { 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_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, colorFormat:Int, depthStencilFormat:Int, samples:Int, colorLoadOp:Int, + colorStoreOp:Int, colorInitialLayout:Int, colorFinalLayout:Int, depthLoadOp:Int, depthStoreOp:Int, depthFinalLayout:Int):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_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_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):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_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_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_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") private static function lime_vk_cmd_copy_buffer_to_image(handle:CFFIPointer, + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, + bufferLow:Int, imageHigh:Int, imageLow:Int, width:Int, height:Int, layout:Int):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_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; + } #end @:hlNative("lime", "hl_vk_get_last_error") private static function lime_vk_get_last_error():hl.Bytes diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx index 24cc8b32e3..149ef3e60f 100644 --- a/src/lime/graphics/vulkan/VK.hx +++ b/src/lime/graphics/vulkan/VK.hx @@ -27,6 +27,9 @@ class VK 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"; @@ -56,6 +59,245 @@ class VK public static inline var FENCE_CREATE_SIGNALED_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 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. **/ @@ -135,14 +377,30 @@ class VK } @: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) @@ -154,13 +412,29 @@ class VK } @: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; 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..d173be9ab9 --- /dev/null +++ b/src/lime/graphics/vulkan/VKBuffer.hx @@ -0,0 +1,123 @@ +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 upload(bytes:Bytes, memoryOffset:Int64 = null, byteOffset:Int = 0, byteLength:Int = -1):Bool + { + return memory != null && memory.upload(bytes, memoryOffset, byteOffset, byteLength); + } +} diff --git a/src/lime/graphics/vulkan/VKCommandBuffer.hx b/src/lime/graphics/vulkan/VKCommandBuffer.hx index 685ecfe448..b3fe89118b 100644 --- a/src/lime/graphics/vulkan/VKCommandBuffer.hx +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -47,6 +47,185 @@ class VKCommandBuffer } } + 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):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(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 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 + { + var state = [width, height, sourceLayout, destinationLayout, filter]; + + #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 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 + { + #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(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, width, height, layout); + } + #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 end():Bool { #if (!macro && lime_cffi && lime_vulkan) @@ -60,6 +239,19 @@ class VKCommandBuffer 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; @@ -83,6 +275,49 @@ class VKCommandBuffer 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 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 { diff --git a/src/lime/graphics/vulkan/VKDescriptorPool.hx b/src/lime/graphics/vulkan/VKDescriptorPool.hx new file mode 100644 index 0000000000..3ec009bca9 --- /dev/null +++ b/src/lime/graphics/vulkan/VKDescriptorPool.hx @@ -0,0 +1,62 @@ +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); + } +} 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/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx index dbcdd331aa..1107c728ea 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -1,6 +1,7 @@ package lime.graphics.vulkan; import haxe.Int64; +import haxe.io.Bytes; #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; @@ -73,6 +74,335 @@ class VKDevice 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 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 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():VKPipelineCache + { + #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); + 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, + depthLoadOp:Int = VK.ATTACHMENT_LOAD_OP_CLEAR, depthStoreOp:Int = VK.ATTACHMENT_STORE_OP_DONT_CARE, + depthFinalLayout:Int = VK.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL):VKRenderPass + { + #if (!macro && lime_cffi && lime_vulkan) + if (isValid()) + { + var data:Dynamic = NativeCFFI.lime_vk_create_render_pass(instance.context.__windowHandle, instance.handle.high, instance.handle.low, + handle.high, handle.low, colorFormat, depthStencilFormat, samples, colorLoadOp, colorStoreOp, colorInitialLayout, colorFinalLayout, + depthLoadOp, depthStoreOp, depthFinalLayout); + var renderPassHandle = VK.__makeHandle(data); + if (!VK.__isZero(renderPassHandle)) + { + return new VKRenderPass(this, renderPassHandle, colorFormat, depthStencilFormat, samples); + } + } + #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) @@ -91,6 +421,58 @@ class VKDevice 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. diff --git a/src/lime/graphics/vulkan/VKDeviceMemory.hx b/src/lime/graphics/vulkan/VKDeviceMemory.hx new file mode 100644 index 0000000000..5a739ec646 --- /dev/null +++ b/src/lime/graphics/vulkan/VKDeviceMemory.hx @@ -0,0 +1,85 @@ +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 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 (!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); + } + + /** + 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; + } +} 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..c0733351b5 --- /dev/null +++ b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx @@ -0,0 +1,77 @@ +package lime.graphics.vulkan; + +class VKGraphicsPipelineInfo +{ + public var alphaBlendOp:Int = VK.BLEND_OP_ADD; + public var colorBlendOp:Int = VK.BLEND_OP_ADD; + public var cullMode:Int = VK.CULL_MODE_BACK_BIT; + 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 frontFace:Int = VK.FRONT_FACE_COUNTER_CLOCKWISE; + public var polygonMode:Int = VK.POLYGON_MODE_FILL; + public var primitiveRestart:Bool = false; + public var srcAlphaBlendFactor:Int = VK.BLEND_FACTOR_ONE; + public var srcColorBlendFactor:Int = VK.BLEND_FACTOR_SRC_ALPHA; + 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, + 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/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/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..69ea68dbe5 --- /dev/null +++ b/src/lime/graphics/vulkan/VKPipelineCache.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 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); + } +} 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 index 9f6e62cb09..a372e78d26 100644 --- a/src/lime/graphics/vulkan/VKQueue.hx +++ b/src/lime/graphics/vulkan/VKQueue.hx @@ -37,6 +37,24 @@ class VKQueue 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. @@ -57,6 +75,30 @@ class VKQueue 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. **/ diff --git a/src/lime/graphics/vulkan/VKRenderPass.hx b/src/lime/graphics/vulkan/VKRenderPass.hx new file mode 100644 index 0000000000..bcbf0ec83f --- /dev/null +++ b/src/lime/graphics/vulkan/VKRenderPass.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 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 samples(default, null):Int; + + @:allow(lime.graphics.vulkan.VKDevice) + private function new(device:VKDevice, handle:Int64, colorFormat:Int, depthStencilFormat:Int, samples:Int) + { + this.device = device; + this.handle = handle; + this.colorFormat = colorFormat; + this.depthStencilFormat = depthStencilFormat; + this.samples = samples; + } + + 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/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/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/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/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/tests/vulkan-smoke/Assets/shaders/cube.frag.spv b/tests/vulkan-smoke/Assets/shaders/cube.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..f55655e156556acbcf490d5b0fd224e3a9b8886a GIT binary patch literal 668 zcmYk2PfG$}5XRrsHOul(mKH&1-K9fC5Owk3#alt=Ko3E+u({F~=!^BKx&-}xZ!7I9 ztY932d*`S5LHnQ;fuxuwA_<`*q7$ZN&1pzgdj=S#pe%;k7b@M)|lEWut}O` z^T?~kS*xORin3ZKHt@{VIgQzWJ|g!9>uQ$y?rv_q$JXvWiWh_!_lfIZLu^35_nCXs zkpBkWuOxm`P>UfLKoxed6{4JP4li^k+ZL&*Qv^?_>(K zICp&6Fe#F3AatUPXND3_2E|$OJ0{Ni=p|n_O@19F!y+17#3LUY;JZoFkuT7E%+3k) zo0mR`iafc9hhPndalbh^@1u!ZkiM?Ofw6xyn%2g_$L){!uA61~rOSn%=n*zv@^#zI z(k!<;!CmC+Bh|Ky^L^~`nEhsaO=CO;2gI?j$GC&Re@`Cn#2pD?XHFm?-rMaGeT?bh zm^leGh@(bNHQ-}g!tr*?nxzdl&58{#RU1yQ*@JxEPu1=?n|=%Gif(BJ_Ts*zTSGdO zEGwTmvDtS~|C7?8gwt{M6W!^zA^WK`@nB8e;K$d%hlGlolJ;C4IGgtaMxU87&eo+5 z_N;`nA{*|g%Un%m!66v6pG&g~7`3tC6%79icPE}5m!+AR-uPFf$0Xq7W5YWbvk<#3 zG3L)V;#<0r%RJO;OB3V!?dXmloO;-NH!$*FN>khWvG*KCJoWjGKK_mK(GNd1-<2Al z^zP^jFC23I3*k+E*FU>2O5g)NzbFzOmL%ZV?7b#o=Tqgd%Z9_GM%bpq=Au-V8hPW+C&y6>LfT2f50E}tK67)PBX-5 zQdHmDw{BHUQaN4=VI|b~?S;i@hYCyx^-zs@G`<}VKl10{>Dh^jMo6MiO_RD+vhnux z^6tYr(I$3@7FyqE!Y#o$gl`H{*m6w@V_i1OZ?e~H$`vLJTjbf@uG#>`Zd|Ot(Q+uYdV0@d3&@59;*WEJSkpiQUO#|0Y>K=TzS!>m{#V?2dB2?-cjt zd}4R@{hTkVkGpuB`3EK?U%@&Z>3geQ`Iq@Bo@#un z&U`s-iZe&fSrg}5&b#;VSkE|nJ8zn8308iG7;}8D@S4Kr=qmC2X&S6A2hU)QmH&8; z-B(WkQ>^nPzc|foz2{)-JDc%ySaapAC-y$6-U4syCBN8v$t@GVgw0Xq%{_j}TmL3_ z8EZeeZC>6Y&7e0T_a|>0B7q@r6`SPA` z>^;4KVvoNt8TJ#bw|j = []; + 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 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() { @@ -36,13 +111,25 @@ class Main extends Application return; } - var context = window.context.vulkan; - validateBootstrap(context); + 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); - renderer = context.createRenderer("LimeVulkanSmoke"); - if (renderer == null || !renderer.isValid) + if (!finished && device != null && device.isValid() && width > 0 && height > 0) { - fail("Failed to create Vulkan renderer: " + VKRenderer.getLastError()); + recreateSwapchain(width, height); } } @@ -50,14 +137,13 @@ class Main extends Application { super.render(context); - if (finished || renderer == null) + if (finished || device == null) { return; } - if (!renderer.render(0.125, 0.25, 0.5, 1.0)) + if (!drawFrame()) { - fail("Failed to render Vulkan frame: " + renderer.lastError); return; } @@ -65,7 +151,7 @@ class Main extends Application Timer.delay(complete, 50); } - private function validateBootstrap(context:VulkanRenderContext):Void + private function createRenderer(context:VulkanRenderContext):Void { var extensions = context.getInstanceExtensions(); if (extensions == null || extensions.length == 0) @@ -81,180 +167,751 @@ class Main extends Application return; } - var instance = VK.createInstance(context, "LimeVulkanSmoke"); + instance = VK.createInstance(context, "LimeVulkanSmoke"); if (instance == null || !instance.isValid()) { fail("Failed to create Vulkan instance: " + VK.getLastError()); return; } - var surface = instance.createSurface(); + surface = instance.createSurface(); if (surface == null || !surface.isValid()) { - instance.dispose(); fail("Failed to create Vulkan surface"); return; } - var devices = instance.enumeratePhysicalDevices(surface); - if (devices.length == 0) + physicalDevice = instance.pickPhysicalDevice(surface); + if (physicalDevice == null || !physicalDevice.hasQueueFamily(true, true)) { - surface.dispose(); - instance.dispose(); - fail("No Vulkan physical devices were enumerated"); + fail("No present-capable graphics queue family was found"); return; } - var device = instance.pickPhysicalDevice(surface); - if (device == null || !device.hasQueueFamily(true, true)) + queueFamily = physicalDevice.getQueueFamily(true, true); + device = physicalDevice.createDevice(queueFamily); + if (device == null || !device.isValid() || device.graphicsQueue == null || !device.graphicsQueue.isValid()) { - surface.dispose(); - instance.dispose(); - fail("No present-capable graphics queue family was found"); + fail("Failed to create Vulkan logical device: " + VK.getLastError()); return; } - var queueFamily = device.getQueueFamily(true, true); - var logicalDevice = device.createDevice(queueFamily); - if (logicalDevice == null || !logicalDevice.isValid() || logicalDevice.graphicsQueue == null || !logicalDevice.graphicsQueue.isValid()) + 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) { - surface.dispose(); - instance.dispose(); - fail("Failed to create Vulkan logical device: " + VK.getLastError()); + fail("Failed to create Vulkan frame synchronization resources: " + VK.getLastError()); return; } - if (!logicalDevice.graphicsQueue.waitIdle()) + swapchain = device.createSwapchain(surface, window.width, window.height); + if (swapchain == null || !swapchain.isValid() || swapchain.images.length == 0) { - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to wait for Vulkan graphics queue: " + VK.getLastError()); + fail("Failed to create Vulkan swapchain: " + VK.getLastError()); return; } - var semaphore = logicalDevice.createSemaphore(); - if (semaphore == null || !semaphore.isValid()) + if (!createSourceTexture() || !createGeometry() || !createDescriptorLayouts() || !createOffscreenPass() || !createOnscreenPass()) { - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to create Vulkan semaphore: " + VK.getLastError()); return; } + } - var commandPool = logicalDevice.createCommandPool(queueFamily); - if (commandPool == null || !commandPool.isValid()) + private function tryCreateRenderer():Void + { + if (device != null || !windowCreated || !preloadComplete || window == null || window.context == null || window.context.vulkan == null) { - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to create Vulkan command pool: " + VK.getLastError()); return; } - var commandBuffer = commandPool.allocateCommandBuffer(); - if (commandBuffer == null || !commandBuffer.isValid()) + 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) { - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to allocate Vulkan command buffer: " + VK.getLastError()); - return; + fail("Failed to create Vulkan texture image: " + VK.getLastError()); + return false; } - if (!commandBuffer.begin(VK.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) || !commandBuffer.end()) + 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) { - commandBuffer.dispose(); - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to record Vulkan command buffer: " + VK.getLastError()); - return; + pixels.set(i, values[i]); } - var fence = logicalDevice.createFence(); - if (fence == null || !fence.isValid()) + var staging = device.createStagingBuffer(Int64.ofInt(pixels.length), pixels); + if (staging == null) { - commandBuffer.dispose(); - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to create Vulkan fence: " + VK.getLastError()); - return; + fail("Failed to create Vulkan texture staging buffer: " + VK.getLastError()); + return false; } - if (!logicalDevice.graphicsQueue.submit(commandBuffer, fence) || !fence.waitForever() || !fence.reset()) + 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()) { - fence.dispose(); - commandBuffer.dispose(); - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to submit Vulkan command buffer: " + VK.getLastError()); - return; + staging.dispose(true); + fail("Failed to record Vulkan texture upload commands: " + VK.getLastError()); + return false; } - if (!logicalDevice.waitIdle()) + if (!fence.waitForever() || !fence.reset() || !device.graphicsQueue.submit(commandBuffer, fence) || !fence.waitForever()) { - fence.dispose(); - commandBuffer.dispose(); - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); - fail("Failed to wait for Vulkan logical device: " + VK.getLastError()); - return; + 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; } - fence.dispose(); - commandBuffer.dispose(); - commandPool.dispose(); - semaphore.dispose(); - logicalDevice.dispose(); - surface.dispose(); - instance.dispose(); + return true; } - private function complete():Void + 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 + { + 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 || !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.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 createDepthResources():Bool + { + disposeDepthResources(); + + depthImage = device.createImage(swapchain.width, swapchain.height, DEPTH_FORMAT, VK.IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + 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 framebuffer = device.createFramebuffer(renderPass, [imageView, depthView], 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 (renderer != null) + if (width <= 0 || height <= 0 || swapchain == null) + { + return false; + } + + if (!device.waitIdle()) { - renderer.dispose(); - renderer = null; + 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 createDepthResources() && createFramebuffers(); + } + + private function disposeSwapchainResources():Void + { + disposeSwapchainFramebuffers(); + 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 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 fail(message:String):Void + private function disposeRenderer():Void { - trace("Vulkan smoke failed: " + message); - - if (renderer != null) + if (device != null && device.isValid()) { - renderer.dispose(); - renderer = null; + 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; + 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 index 4752ae8640..47c1e61a7a 100644 --- a/tests/vulkan-smoke/project.xml +++ b/tests/vulkan-smoke/project.xml @@ -5,6 +5,7 @@ + From 9acbfe74c154d3897d8a89c94a70880e3784b66e Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 22 May 2026 15:00:48 -0400 Subject: [PATCH 014/251] Vulkan: add memory download and command helpers Add multiple Vulkan helpers and extended pipeline/command support. - Implement lime_vk_download_memory (and HL variant) to map and copy device memory to host Bytes. - Add lime_vk_reset_descriptor_pool (and HL variant) to reset descriptor pools. - Extend pipeline cache creation to accept initial data and add lime_vk_get_pipeline_cache_data to retrieve cache blobs (with HL variants). - Expand graphics pipeline state parsing to include stencil ops and per-attachment color write mask. - Add new command helpers: cmd bind descriptor set (extended), copy buffer<->image region variants, clear depth/stencil image, push constants, and enhanced blit image parameter handling. - Register new native primes and update NativeCFFI.hx to expose the added functions. - Minor fix: include VK_IMAGE_USAGE_TRANSFER_SRC_BIT when supported. These changes are intended to expose more/additional Vulkan functionality to the higher-level API and allow using pipeline caches, fine-grained copy/blit/clear operations, push constants, and descriptor pool management. --- project/src/ExternalInterface.cpp | 870 +++++++++++++++++- .../_internal/backend/native/NativeCFFI.hx | 112 ++- src/lime/graphics/vulkan/VK.hx | 8 + src/lime/graphics/vulkan/VKBuffer.hx | 5 + src/lime/graphics/vulkan/VKCommandBuffer.hx | 160 +++- src/lime/graphics/vulkan/VKDescriptorPool.hx | 13 + src/lime/graphics/vulkan/VKDevice.hx | 9 +- src/lime/graphics/vulkan/VKDeviceMemory.hx | 30 + .../graphics/vulkan/VKGraphicsPipelineInfo.hx | 32 + src/lime/graphics/vulkan/VKPipelineCache.hx | 18 + 10 files changed, 1216 insertions(+), 41 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index dff828e2ab..45fd23893d 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -963,6 +963,11 @@ namespace lime { imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + if (capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { + + imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } uint32_t imageCount = capabilities.minImageCount + 1; @@ -6488,6 +6493,89 @@ namespace lime { } + 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 + + } + + value lime_vk_create_buffer (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int sizeHigh, int sizeLow, int usage) { #ifdef LIME_VULKAN @@ -8595,6 +8683,66 @@ namespace lime { } + bool lime_vk_reset_descriptor_pool (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, int poolLow, + 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); + 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; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + 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) { + +#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; + + VkResult result = vkResetDescriptorPool (device, pool, (VkDescriptorPoolResetFlags)flags); + if (result != VK_SUCCESS) { + + lastVKError = "vkResetDescriptorPool failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + value lime_vk_allocate_descriptor_set (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int poolHigh, int poolLow, int layoutHigh, int layoutLow) { @@ -9018,7 +9166,8 @@ namespace lime { } - value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bytes, int byteOffset, + int byteLength) { #ifdef LIME_VULKAN Window* targetWindow = (Window*)val_data (window); @@ -9031,6 +9180,20 @@ namespace lime { VkPipelineCacheCreateInfo createInfo; memset (&createInfo, 0, sizeof (createInfo)); createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + Bytes initialData (bytes); + if (initialData.b && byteLength > 0) { + + if (byteOffset < 0 || byteOffset + byteLength > initialData.length) { + + lastVKError = "Invalid Vulkan pipeline cache data range"; + return alloc_null (); + + } + + createInfo.initialDataSize = (size_t)byteLength; + createInfo.pInitialData = initialData.b + byteOffset; + + } VkPipelineCache cache = VK_NULL_HANDLE; VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); @@ -9052,7 +9215,7 @@ namespace lime { HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, - int deviceLow) { + int deviceLow, Bytes* bytes, int byteOffset, int byteLength) { #ifdef LIME_VULKAN Window* targetWindow = (Window*)window->ptr; @@ -9065,6 +9228,19 @@ namespace lime { VkPipelineCacheCreateInfo createInfo; memset (&createInfo, 0, sizeof (createInfo)); createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + if (bytes && bytes->b && byteLength > 0) { + + 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; + + } VkPipelineCache cache = VK_NULL_HANDLE; VkResult result = vkCreatePipelineCache (device, &createInfo, 0, &cache); @@ -9085,6 +9261,92 @@ namespace lime { } + bool lime_vk_get_pipeline_cache_data (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, + int cacheLow, value 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); + VkPipelineCache cache = (VkPipelineCache)(uintptr_t)CombineVulkanHandle (cacheHigh, cacheLow); + PFN_vkGetPipelineCacheData vkGetPipelineCacheData = + (PFN_vkGetPipelineCacheData)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkGetPipelineCacheData"); + if (!vkGetPipelineCacheData || !cache) return false; + + size_t size = 0; + VkResult result = vkGetPipelineCacheData (device, cache, &size, 0); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; + + } + + Bytes data (bytes); + data.Resize ((int)size); + if (size > 0 && !data.b) return false; + + result = vkGetPipelineCacheData (device, cache, &size, data.b); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; + + } + + data.Value (bytes); + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + + 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) { + +#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; + + size_t size = 0; + VkResult result = vkGetPipelineCacheData (device, cache, &size, 0); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; + + } + + bytes->Resize ((int)size); + if (size > 0 && !bytes->b) return false; + + result = vkGetPipelineCacheData (device, cache, &size, bytes->b); + if (result != VK_SUCCESS) { + + lastVKError = "vkGetPipelineCacheData failed"; + return false; + + } + + lastVKError.clear (); + return true; +#else + lastVKError = "Lime was built without lime-vulkan support"; + return false; +#endif + + } + + void lime_vk_destroy_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int cacheHigh, int cacheLow) { @@ -9145,7 +9407,7 @@ namespace lime { static VkPipeline CreateManagedVulkanGraphicsPipeline (Window* targetWindow, VkInstance instance, VkDevice device, VkRenderPass renderPass, VkPipelineLayout layout, VkShaderModule vertexShader, VkShaderModule fragmentShader, const std::vector& state) { - if (state.size () < 19 || !renderPass || !layout || !vertexShader || !fragmentShader) { + if (state.size () < 35 || !renderPass || !layout || !vertexShader || !fragmentShader) { lastVKError = "Invalid Vulkan graphics pipeline state"; return VK_NULL_HANDLE; @@ -9171,6 +9433,22 @@ namespace lime { 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 bindingCount = state[cursor++]; if ((int)state.size () < cursor + bindingCount * 3 + 1) { @@ -9280,10 +9558,25 @@ namespace lime { 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 = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorAttachment.colorWriteMask = (VkColorComponentFlags)colorWriteMask; colorAttachment.blendEnable = blend ? VK_TRUE : VK_FALSE; colorAttachment.srcColorBlendFactor = (VkBlendFactor)srcColorBlendFactor; colorAttachment.dstColorBlendFactor = (VkBlendFactor)dstColorBlendFactor; @@ -9768,6 +10061,70 @@ namespace lime { } + 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) { + +#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 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) { + +#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 + + } + + value lime_vulkan_renderer_get_info (value handle) { if (val_is_null (handle)) return alloc_string (""); @@ -10183,6 +10540,162 @@ namespace lime { } + + 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) { + +#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 + + } + + + 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) { + +#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 + + } + + + 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) { + +#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 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_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 + + } + HL_PRIM vbyte* HL_NAME(hl_vulkan_renderer_get_last_error) () { return hl_copy_bytes ((const vbyte*)lastVulkanRendererError.c_str (), (int)lastVulkanRendererError.size () + 1); @@ -10334,6 +10847,76 @@ namespace lime { } + 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) { + +#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 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) { + +#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 + + } + + 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) { @@ -10348,18 +10931,52 @@ namespace lime { VkImageBlit blit; memset (&blit, 0, sizeof (blit)); - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[1].x = packed[0]; - blit.srcOffsets[1].y = packed[1]; - blit.srcOffsets[1].z = 1; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[1].x = packed[0]; - blit.dstOffsets[1].y = packed[1]; - blit.dstOffsets[1].z = 1; - vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)packed[2], - (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)packed[3], 1, &blit, (VkFilter)packed[4]); + int sourceLayout = packed[2]; + int destinationLayout = packed[3]; + int filter = packed[4]; + if (packed.size () >= 21) { + + 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]; + sourceLayout = packed[12]; + destinationLayout = packed[13]; + 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]; + + } else { + + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.layerCount = 1; + blit.srcOffsets[1].x = packed[0]; + blit.srcOffsets[1].y = packed[1]; + blit.srcOffsets[1].z = 1; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.layerCount = 1; + blit.dstOffsets[1].x = packed[0]; + blit.dstOffsets[1].y = packed[1]; + blit.dstOffsets[1].z = 1; + + } + 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"; @@ -10383,18 +11000,52 @@ namespace lime { VkImageBlit blit; memset (&blit, 0, sizeof (blit)); - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[1].x = packed[0]; - blit.srcOffsets[1].y = packed[1]; - blit.srcOffsets[1].z = 1; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[1].x = packed[0]; - blit.dstOffsets[1].y = packed[1]; - blit.dstOffsets[1].z = 1; - vkCmdBlitImage (commandBuffer, (VkImage)(uintptr_t)CombineVulkanHandle (sourceHigh, sourceLow), (VkImageLayout)packed[2], - (VkImage)(uintptr_t)CombineVulkanHandle (destinationHigh, destinationLow), (VkImageLayout)packed[3], 1, &blit, (VkFilter)packed[4]); + int sourceLayout = packed[2]; + int destinationLayout = packed[3]; + int filter = packed[4]; + if (packed.size () >= 21) { + + 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]; + sourceLayout = packed[12]; + destinationLayout = packed[13]; + 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]; + + } else { + + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.layerCount = 1; + blit.srcOffsets[1].x = packed[0]; + blit.srcOffsets[1].y = packed[1]; + blit.srcOffsets[1].z = 1; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.layerCount = 1; + blit.dstOffsets[1].x = packed[0]; + blit.dstOffsets[1].y = packed[1]; + blit.dstOffsets[1].z = 1; + + } + 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"; @@ -10403,6 +11054,58 @@ namespace lime { } + + 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) { + +#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; + + 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 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_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 + + } + + bool lime_vulkan_renderer_set_overlay (value handle, value bytes, int width, int height, int x, int y) { if (val_is_null (handle)) return false; @@ -10570,7 +11273,8 @@ namespace lime { } - value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow) { + value lime_vk_create_pipeline_cache (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value bytes, int byteOffset, + int byteLength) { return LimeVulkanUnavailableValue (); @@ -10578,7 +11282,7 @@ namespace lime { HL_PRIM vdynamic* HL_NAME(hl_vk_create_pipeline_cache) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, - int deviceLow) { + int deviceLow, Bytes* bytes, int byteOffset, int byteLength) { return HLLimeVulkanUnavailableValue (); @@ -10601,6 +11305,22 @@ namespace lime { } + 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 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) { + + return LimeVulkanUnavailableBool (); + + } + + 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) { @@ -10717,6 +11437,22 @@ namespace lime { } + 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 LimeVulkanUnavailableBool (); + + } + + + 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) { + + return LimeVulkanUnavailableBool (); + + } + + 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) { @@ -10846,6 +11582,38 @@ namespace lime { } + 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 LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + + 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) { + + return LimeVulkanUnavailableBool (); + + } + + 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) { @@ -10878,6 +11646,22 @@ namespace lime { } + 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) { + + return LimeVulkanUnavailableBool (); + + } + + + 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) { + + return LimeVulkanUnavailableBool (); + + } + + 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) { @@ -10894,6 +11678,22 @@ namespace lime { } + 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) { + + return LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + value lime_vulkan_renderer_create (value window, HxString applicationName) { lastVulkanRendererError = "Lime was built without lime-vulkan support"; @@ -11810,6 +12610,7 @@ namespace lime { 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_PRIME8 (lime_vk_create_buffer); DEFINE_PRIME7v (lime_vk_destroy_buffer); DEFINE_PRIME7 (lime_vk_get_buffer_memory_requirements); @@ -11838,13 +12639,15 @@ namespace lime { 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_PRIME8 (lime_vk_create_pipeline_layout); DEFINE_PRIME7v (lime_vk_destroy_pipeline_layout); - DEFINE_PRIME5 (lime_vk_create_pipeline_cache); + 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); @@ -11852,6 +12655,7 @@ namespace lime { 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_PRIME12 (lime_vk_cmd_bind_vertex_buffer); DEFINE_PRIME12 (lime_vk_cmd_bind_index_buffer); DEFINE_PRIME13 (lime_vk_cmd_set_viewport); @@ -11860,9 +12664,13 @@ namespace lime { DEFINE_PRIME12 (lime_vk_cmd_draw_indexed); DEFINE_PRIME12 (lime_vk_cmd_copy_buffer); DEFINE_PRIME14 (lime_vk_cmd_copy_buffer_to_image); + 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_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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index f36431e453..4965f04ed3 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -424,6 +424,9 @@ class NativeCFFI @: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_create_buffer(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, sizeHigh:Int, sizeLow:Int, usage:Int):Dynamic; @@ -511,6 +514,9 @@ class NativeCFFI @: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; @@ -528,11 +534,14 @@ class NativeCFFI 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):Dynamic; + 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; @@ -557,6 +566,9 @@ class NativeCFFI 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_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; @@ -582,14 +594,28 @@ class NativeCFFI deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, imageHigh:Int, imageLow:Int, width:Int, height:Int, layout:Int):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_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; @@ -971,6 +997,8 @@ class NativeCFFI "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_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", @@ -1027,6 +1055,8 @@ class NativeCFFI "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>( @@ -1037,10 +1067,12 @@ class NativeCFFI "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>(cpp.Prime._loadPrime("lime", - "lime_vk_create_pipeline_cache", "oiiiio", 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", @@ -1055,6 +1087,8 @@ class NativeCFFI "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_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>( @@ -1071,12 +1105,20 @@ class NativeCFFI cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer", "oiiiiiiiiiiob", false)); private static var lime_vk_cmd_copy_buffer_to_image = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer_to_image", "oiiiiiiiiiiiiib", 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_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)); @@ -1322,6 +1364,7 @@ class NativeCFFI 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_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); @@ -1350,6 +1393,7 @@ class NativeCFFI 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); @@ -1357,6 +1401,7 @@ class NativeCFFI 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); @@ -1364,6 +1409,7 @@ class NativeCFFI 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_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); @@ -1372,9 +1418,13 @@ class NativeCFFI private static var lime_vk_cmd_draw_indexed = CFFI.load("lime", "lime_vk_cmd_draw_indexed", -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 = CFFI.load("lime", "lime_vk_cmd_copy_buffer_to_image", -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_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); @@ -2166,6 +2216,13 @@ class NativeCFFI 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_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 { @@ -2314,6 +2371,12 @@ class NativeCFFI @: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 { @@ -2345,7 +2408,7 @@ class NativeCFFI 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):Dynamic + instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, bytes:Bytes, byteOffset:Int, byteLength:Int):Dynamic { return null; } @@ -2353,6 +2416,12 @@ class NativeCFFI @: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, @@ -2398,6 +2467,13 @@ class NativeCFFI 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_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 @@ -2454,6 +2530,20 @@ class NativeCFFI 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 @@ -2468,12 +2558,26 @@ class NativeCFFI 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_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 diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx index 149ef3e60f..93e9a0137b 100644 --- a/src/lime/graphics/vulkan/VK.hx +++ b/src/lime/graphics/vulkan/VK.hx @@ -59,6 +59,8 @@ class VK 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; @@ -122,6 +124,12 @@ class VK 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; diff --git a/src/lime/graphics/vulkan/VKBuffer.hx b/src/lime/graphics/vulkan/VKBuffer.hx index d173be9ab9..2fbeb81a73 100644 --- a/src/lime/graphics/vulkan/VKBuffer.hx +++ b/src/lime/graphics/vulkan/VKBuffer.hx @@ -120,4 +120,9 @@ class VKBuffer { 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 index b3fe89118b..375748ca99 100644 --- a/src/lime/graphics/vulkan/VKCommandBuffer.hx +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -69,11 +69,23 @@ class VKCommandBuffer } public function bindDescriptorSet(layout:VKPipelineLayout, descriptorSet:VKDescriptorSet, firstSet:Int = 0, - bindPoint:Int = VK.PIPELINE_BIND_POINT_GRAPHICS):Bool + 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); @@ -138,7 +150,41 @@ class VKCommandBuffer 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 { - var state = [width, height, sourceLayout, destinationLayout, filter]; + 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()) @@ -167,6 +213,24 @@ class VKCommandBuffer 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 copyBuffer(source:VKBuffer, destination:VKBuffer, size:Int64, sourceOffset:Int64 = null, destinationOffset:Int64 = null):Bool { if (sourceOffset == null) sourceOffset = Int64.ofInt(0); @@ -188,12 +252,75 @@ class VKCommandBuffer 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(device.instance.context.__windowHandle, device.instance.handle.high, + 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, width, height, layout); + 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 @@ -292,6 +419,31 @@ class VKCommandBuffer 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) diff --git a/src/lime/graphics/vulkan/VKDescriptorPool.hx b/src/lime/graphics/vulkan/VKDescriptorPool.hx index 3ec009bca9..e754efbb31 100644 --- a/src/lime/graphics/vulkan/VKDescriptorPool.hx +++ b/src/lime/graphics/vulkan/VKDescriptorPool.hx @@ -59,4 +59,17 @@ class VKDescriptorPool { 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/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx index 1107c728ea..6897091794 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -308,13 +308,18 @@ class VKDevice return null; } - public function createPipelineCache():VKPipelineCache + 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); + handle.high, handle.low, bytes, byteOffset, byteLength); var pipelineCacheHandle = VK.__makeHandle(data); if (!VK.__isZero(pipelineCacheHandle)) { diff --git a/src/lime/graphics/vulkan/VKDeviceMemory.hx b/src/lime/graphics/vulkan/VKDeviceMemory.hx index 5a739ec646..101b09ad20 100644 --- a/src/lime/graphics/vulkan/VKDeviceMemory.hx +++ b/src/lime/graphics/vulkan/VKDeviceMemory.hx @@ -82,4 +82,34 @@ class VKDeviceMemory 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/VKGraphicsPipelineInfo.hx b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx index c0733351b5..2763dcb000 100644 --- a/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx +++ b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx @@ -4,18 +4,34 @@ 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 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; @@ -53,6 +69,22 @@ class VKGraphicsPipelineInfo dstAlphaBlendFactor, alphaBlendOp, dynamicStateFlags, + colorWriteMask, + stencilTest ? 1 : 0, + frontFailOp, + frontPassOp, + frontDepthFailOp, + frontCompareOp, + frontCompareMask, + frontWriteMask, + frontReference, + backFailOp, + backPassOp, + backDepthFailOp, + backCompareOp, + backCompareMask, + backWriteMask, + backReference, vertexBindings.length ]; diff --git a/src/lime/graphics/vulkan/VKPipelineCache.hx b/src/lime/graphics/vulkan/VKPipelineCache.hx index 69ea68dbe5..e690940e26 100644 --- a/src/lime/graphics/vulkan/VKPipelineCache.hx +++ b/src/lime/graphics/vulkan/VKPipelineCache.hx @@ -1,6 +1,7 @@ package lime.graphics.vulkan; import haxe.Int64; +import haxe.io.Bytes; #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; @@ -41,4 +42,21 @@ class VKPipelineCache { 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; + } } From b91b9ea5abb8b0781206e7d4db4922e823b0d1be Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 22 May 2026 16:37:58 -0400 Subject: [PATCH 015/251] Vulkan: Pack Vulkan render-pass params into state array Change the Vulkan render-pass/native bindings to accept a packed integer state array instead of many individual parameters. C/C++ and HL CFFI signatures updated to parse the state vector (including a new depthInitialLayout entry) and set attachment initial layouts accordingly. Also, I simplified VkImageBlit handling to require the full packed layout (21 ints) and removed the old fallback parsing. Removed the legacy lime_vk_cmd_copy_buffer_to_image bindings/definitions (use the region variant instead). Updated NativeCFFI prime/load signatures and VKDevice to build and pass the packed state array. --- project/src/ExternalInterface.cpp | 258 ++++++------------ .../_internal/backend/native/NativeCFFI.hx | 24 +- src/lime/graphics/vulkan/VKDevice.hx | 21 +- 3 files changed, 102 insertions(+), 201 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 45fd23893d..607f8590da 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -7690,9 +7690,7 @@ namespace lime { } - value lime_vk_create_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int colorFormat, - int depthStencilFormat, int samples, int colorLoadOp, int colorStoreOp, int colorInitialLayout, int colorFinalLayout, int depthLoadOp, - int depthStoreOp, int depthFinalLayout) { + value lime_vk_create_render_pass (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value state) { #ifdef LIME_VULKAN Window* targetWindow = (Window*)val_data (window); @@ -7701,6 +7699,20 @@ namespace lime { PFN_vkCreateRenderPass vkCreateRenderPass = (PFN_vkCreateRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateRenderPass"); if (!vkCreateRenderPass) return alloc_null (); + std::vector packed = GetVulkanIntVector (state); + if (packed.size () < 11) 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]; std::vector attachments; VkAttachmentDescription colorAttachment; @@ -7733,7 +7745,7 @@ namespace lime { depthAttachment.storeOp = (VkAttachmentStoreOp)depthStoreOp; depthAttachment.stencilLoadOp = (VkAttachmentLoadOp)depthLoadOp; depthAttachment.stencilStoreOp = (VkAttachmentStoreOp)depthStoreOp; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.initialLayout = (VkImageLayout)depthInitialLayout; depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; attachments.push_back (depthAttachment); depthReference.attachment = 1; @@ -7786,8 +7798,7 @@ namespace lime { HL_PRIM vdynamic* HL_NAME(hl_vk_create_render_pass) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, - int deviceLow, int colorFormat, int depthStencilFormat, int samples, int colorLoadOp, int colorStoreOp, int colorInitialLayout, - int colorFinalLayout, int depthLoadOp, int depthStoreOp, int depthFinalLayout) { + int deviceLow, hl_varray* state) { #ifdef LIME_VULKAN Window* targetWindow = (Window*)window->ptr; @@ -7796,6 +7807,20 @@ namespace lime { PFN_vkCreateRenderPass vkCreateRenderPass = (PFN_vkCreateRenderPass)GetManagedVulkanDeviceProc (targetWindow, instance, device, "vkCreateRenderPass"); if (!vkCreateRenderPass) return 0; + std::vector packed = GetHLVulkanIntVector (state); + if (packed.size () < 11) 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]; std::vector attachments; VkAttachmentDescription colorAttachment; @@ -7828,7 +7853,7 @@ namespace lime { depthAttachment.storeOp = (VkAttachmentStoreOp)depthStoreOp; depthAttachment.stencilLoadOp = (VkAttachmentLoadOp)depthLoadOp; depthAttachment.stencilStoreOp = (VkAttachmentStoreOp)depthStoreOp; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.initialLayout = (VkImageLayout)depthInitialLayout; depthAttachment.finalLayout = (VkImageLayout)depthFinalLayout; attachments.push_back (depthAttachment); depthReference.attachment = 1; @@ -10479,68 +10504,6 @@ namespace lime { } - - bool lime_vk_cmd_copy_buffer_to_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, - int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, int height, int layout) { - -#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); - if (!vkCmdCopyBufferToImage || !commandBuffer) return false; - - VkBufferImageCopy region; - memset (®ion, 0, sizeof (region)); - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.width = (uint32_t)width; - region.imageExtent.height = (uint32_t)height; - region.imageExtent.depth = 1; - vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), - (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, 1, ®ion); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#endif - - } - - - HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, - int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, - int height, int layout) { - -#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); - if (!vkCmdCopyBufferToImage || !commandBuffer) return false; - - VkBufferImageCopy region; - memset (®ion, 0, sizeof (region)); - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.width = (uint32_t)width; - region.imageExtent.height = (uint32_t)height; - region.imageExtent.depth = 1; - vkCmdCopyBufferToImage (commandBuffer, (VkBuffer)(uintptr_t)CombineVulkanHandle (bufferHigh, bufferLow), - (VkImage)(uintptr_t)CombineVulkanHandle (imageHigh, imageLow), (VkImageLayout)layout, 1, ®ion); - return true; -#else - lastVKError = "Lime was built without lime-vulkan support"; - return false; -#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) { @@ -10927,53 +10890,33 @@ namespace lime { 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 () < 5) return false; + if (!vkCmdBlitImage || !commandBuffer || packed.size () < 21) return false; VkImageBlit blit; memset (&blit, 0, sizeof (blit)); - int sourceLayout = packed[2]; - int destinationLayout = packed[3]; - int filter = packed[4]; - if (packed.size () >= 21) { - - 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]; - sourceLayout = packed[12]; - destinationLayout = packed[13]; - 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]; - - } else { - - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[1].x = packed[0]; - blit.srcOffsets[1].y = packed[1]; - blit.srcOffsets[1].z = 1; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[1].x = packed[0]; - blit.dstOffsets[1].y = packed[1]; - blit.dstOffsets[1].z = 1; - - } + 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); @@ -10996,53 +10939,33 @@ namespace lime { 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 () < 5) return false; + if (!vkCmdBlitImage || !commandBuffer || packed.size () < 21) return false; VkImageBlit blit; memset (&blit, 0, sizeof (blit)); - int sourceLayout = packed[2]; - int destinationLayout = packed[3]; - int filter = packed[4]; - if (packed.size () >= 21) { - - 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]; - sourceLayout = packed[12]; - destinationLayout = packed[13]; - 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]; - - } else { - - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[1].x = packed[0]; - blit.srcOffsets[1].y = packed[1]; - blit.srcOffsets[1].z = 1; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[1].x = packed[0]; - blit.dstOffsets[1].y = packed[1]; - blit.dstOffsets[1].z = 1; - - } + 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); @@ -11564,24 +11487,6 @@ namespace lime { } - - bool lime_vk_cmd_copy_buffer_to_image (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, - int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, int height, int layout) { - - return LimeVulkanUnavailableBool (); - - } - - - HL_PRIM bool HL_NAME(hl_vk_cmd_copy_buffer_to_image) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, - int deviceLow, int commandBufferHigh, int commandBufferLow, int bufferHigh, int bufferLow, int imageHigh, int imageLow, int width, - int height, int layout) { - - 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) { @@ -12627,7 +12532,7 @@ namespace lime { DEFINE_PRIME10 (lime_vk_create_image_view); DEFINE_PRIME7v (lime_vk_destroy_image_view); DEFINE_PRIME14 (lime_vk_create_image_view_ex); - DEFINE_PRIME15 (lime_vk_create_render_pass); + 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); @@ -12663,7 +12568,6 @@ namespace lime { DEFINE_PRIME11 (lime_vk_cmd_draw); DEFINE_PRIME12 (lime_vk_cmd_draw_indexed); DEFINE_PRIME12 (lime_vk_cmd_copy_buffer); - DEFINE_PRIME14 (lime_vk_cmd_copy_buffer_to_image); 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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 4965f04ed3..d543f2f19f 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -478,8 +478,7 @@ class NativeCFFI layerCount:Int):Dynamic; @:cffi private static function lime_vk_create_render_pass(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, - colorFormat:Int, depthStencilFormat:Int, samples:Int, colorLoadOp:Int, colorStoreOp:Int, colorInitialLayout:Int, colorFinalLayout:Int, - depthLoadOp:Int, depthStoreOp:Int, depthFinalLayout:Int):Dynamic; + 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; @@ -590,10 +589,6 @@ class NativeCFFI @: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(handle:Dynamic, instanceHigh:Int, instanceLow:Int, deviceHigh:Int, - deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, bufferLow:Int, imageHigh:Int, imageLow:Int, width:Int, - height:Int, layout:Int):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; @@ -1031,8 +1026,8 @@ class NativeCFFI "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->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->cpp.Object>( - cpp.Prime._loadPrime("lime", "lime_vk_create_render_pass", "oiiiiiiiiiiiiiio", 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>( @@ -1103,8 +1098,6 @@ class NativeCFFI "lime_vk_cmd_draw_indexed", "oiiiiiiiiiiib", 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 = new cpp.CallableInt->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Int->Bool>( - cpp.Prime._loadPrime("lime", "lime_vk_cmd_copy_buffer_to_image", "oiiiiiiiiiiiiib", 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>( @@ -1417,7 +1410,6 @@ class NativeCFFI 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_copy_buffer = CFFI.load("lime", "lime_vk_cmd_copy_buffer", -1); - private static var lime_vk_cmd_copy_buffer_to_image = CFFI.load("lime", "lime_vk_cmd_copy_buffer_to_image", -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); @@ -2315,8 +2307,7 @@ class NativeCFFI } @: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, colorFormat:Int, depthStencilFormat:Int, samples:Int, colorLoadOp:Int, - colorStoreOp:Int, colorInitialLayout:Int, colorFinalLayout:Int, depthLoadOp:Int, depthStoreOp:Int, depthFinalLayout:Int):Dynamic + instanceLow:Int, deviceHigh:Int, deviceLow:Int, state:hl.NativeArray):Dynamic { return null; } @@ -2523,13 +2514,6 @@ class NativeCFFI return false; } - @:hlNative("lime", "hl_vk_cmd_copy_buffer_to_image") private static function lime_vk_cmd_copy_buffer_to_image(handle:CFFIPointer, - instanceHigh:Int, instanceLow:Int, deviceHigh:Int, deviceLow:Int, commandBufferHigh:Int, commandBufferLow:Int, bufferHigh:Int, - bufferLow:Int, imageHigh:Int, imageLow:Int, width:Int, height:Int, layout:Int):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 diff --git a/src/lime/graphics/vulkan/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx index 6897091794..46103482d9 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -368,15 +368,28 @@ class VKDevice 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, - depthLoadOp:Int = VK.ATTACHMENT_LOAD_OP_CLEAR, depthStoreOp:Int = VK.ATTACHMENT_STORE_OP_DONT_CARE, - depthFinalLayout:Int = VK.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL):VKRenderPass + 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):VKRenderPass { #if (!macro && lime_cffi && lime_vulkan) if (isValid()) { + var state = [ + colorFormat, + depthStencilFormat, + samples, + colorLoadOp, + colorStoreOp, + colorInitialLayout, + colorFinalLayout, + depthInitialLayout, + depthFinalLayout, + depthLoadOp, + depthStoreOp + ]; var data:Dynamic = NativeCFFI.lime_vk_create_render_pass(instance.context.__windowHandle, instance.handle.high, instance.handle.low, - handle.high, handle.low, colorFormat, depthStencilFormat, samples, colorLoadOp, colorStoreOp, colorInitialLayout, colorFinalLayout, - depthLoadOp, depthStoreOp, depthFinalLayout); + handle.high, handle.low, state); var renderPassHandle = VK.__makeHandle(data); if (!VK.__isZero(renderPassHandle)) { From d129177b082105336e609c471e3f19dd4c5d8d1c Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Sun, 24 May 2026 23:49:10 -0400 Subject: [PATCH 016/251] Add Vulkan bootstrap logging and vk error details --- project/src/ExternalInterface.cpp | 72 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 607f8590da..81fdf8ad8a 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -60,6 +60,7 @@ #include #include +#include #include #include @@ -76,6 +77,28 @@ namespace lime { static std::string lastVKError; + static void LogVulkanNativeBootstrap (const char* message) { + +#ifdef LIME_VULKAN + ::FILE* file = ::fopen ("lime-vulkan-native.log", "a"); + if (file) { + + ::fprintf (file, "%s\n", message ? message : ""); + ::fclose (file); + + } +#endif + + } + + + static void LogVulkanNativeBootstrap (const std::string& message) { + + LogVulkanNativeBootstrap (message.c_str ()); + + } + + static uint64_t CombineVulkanHandle (int high, int low) { return ((uint64_t)(uint32_t)high << 32) | (uint32_t)low; @@ -343,9 +366,11 @@ namespace lime { static bool CreateManagedVulkanDevice (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const std::vector& requestedExtensions, VkDevice* outDevice, VkQueue* outQueue) { + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: begin"); if (!targetWindow || !instance || !physicalDevice || !outDevice || !outQueue) { lastVKError = "Missing Vulkan instance, physical device, or output device"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing input"); return false; } @@ -354,9 +379,11 @@ namespace lime { *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; } @@ -367,19 +394,23 @@ namespace lime { (PFN_vkEnumerateDeviceExtensionProperties)vkGetInstanceProcAddr (instance, "vkEnumerateDeviceExtensionProperties"); PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)vkGetInstanceProcAddr (instance, "vkGetPhysicalDeviceQueueFamilyProperties"); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: loaded device creation procs"); if (!vkCreateDevice || !vkGetDeviceProcAddr || !vkEnumerateDeviceExtensionProperties || !vkGetPhysicalDeviceQueueFamilyProperties) { lastVKError = "Missing required Vulkan device creation functions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: missing required procs"); return false; } uint32_t queueFamilyCount = 0; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: query queue family count"); vkGetPhysicalDeviceQueueFamilyProperties (physicalDevice, &queueFamilyCount, 0); if (queueFamilyIndex >= queueFamilyCount) { lastVKError = "Invalid Vulkan queue family index"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: invalid queue family index"); return false; } @@ -400,10 +431,12 @@ namespace lime { } uint32_t extensionCount = 0; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: enumerate device extension count"); VkResult extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, 0); if (extensionResult != VK_SUCCESS) { lastVKError = "Could not enumerate Vulkan device extensions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: extension count enumeration failed"); return false; } @@ -411,10 +444,12 @@ namespace lime { std::vector availableExtensions (extensionCount); if (extensionCount > 0) { + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: enumerate device extensions"); extensionResult = vkEnumerateDeviceExtensionProperties (physicalDevice, 0, &extensionCount, availableExtensions.data ()); if (extensionResult != VK_SUCCESS) { lastVKError = "Could not enumerate Vulkan device extensions"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: extension enumeration failed"); return false; } @@ -444,6 +479,7 @@ namespace lime { if (!extensionSupported) { lastVKError = std::string ("Vulkan physical device does not support ") + requestedExtensions[i]; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: requested extension missing"); return false; } @@ -490,24 +526,29 @@ namespace lime { createInfo.ppEnabledExtensionNames = deviceExtensions.empty () ? 0 : deviceExtensions.data (); VkResult result = vkCreateDevice (physicalDevice, &createInfo, 0, outDevice); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: returned from vkCreateDevice"); if (result != VK_SUCCESS) { lastVKError = "vkCreateDevice failed"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: vkCreateDevice failed"); return false; } PFN_vkGetDeviceQueue vkGetDeviceQueue = (PFN_vkGetDeviceQueue)vkGetDeviceProcAddr (*outDevice, "vkGetDeviceQueue"); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: loaded vkGetDeviceQueue"); if (!vkGetDeviceQueue) { 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; } + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: get device queue"); vkGetDeviceQueue (*outDevice, queueFamilyIndex, 0, outQueue); if (!*outQueue) { @@ -515,11 +556,13 @@ namespace lime { if (vkDestroyDevice) vkDestroyDevice (*outDevice, 0); *outDevice = VK_NULL_HANDLE; lastVKError = "Failed to get Vulkan device queue"; + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: device queue was null"); return false; } lastVKError.clear (); + LogVulkanNativeBootstrap ("CreateManagedVulkanDevice: success"); return true; } @@ -5097,23 +5140,36 @@ namespace lime { 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"; @@ -6223,7 +6279,9 @@ namespace lime { VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); if (result != VK_SUCCESS) { - lastVKError = "vkQueueSubmit failed"; + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; return false; } @@ -6260,7 +6318,9 @@ namespace lime { VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); if (result != VK_SUCCESS) { - lastVKError = "vkQueueSubmit failed"; + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; return false; } @@ -9794,7 +9854,9 @@ namespace lime { VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); if (result != VK_SUCCESS) { - lastVKError = "vkQueueSubmit failed"; + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; return false; } @@ -9842,7 +9904,9 @@ namespace lime { VkResult result = vkQueueSubmit (queue, 1, &submitInfo, fence); if (result != VK_SUCCESS) { - lastVKError = "vkQueueSubmit failed"; + char error[64]; + ::snprintf (error, sizeof (error), "vkQueueSubmit failed: %d", (int)result); + lastVKError = error; return false; } From 01789c0ce0912464ed319ac1009555ac6d3b74ae Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Mon, 25 May 2026 03:17:34 -0400 Subject: [PATCH 017/251] Vulkan: MSAA/resolve support Add multisampling and color-resolve support across the Vulkan backend and tests. Expose framebuffer sample count limits from the native ExternalInterface, parse and store them on VKPhysicalDevice, and add helper methods (getMaxUsableSampleCount, supportsSampleCount). Extend render-pass creation to accept resolve attachment parameters and construct a resolve attachment/subpass pResolveAttachments when needed, and propagate resolveFormat into VKRenderPass. Add multisample state fields to VKGraphicsPipelineInfo and wire rasterizationSamples, sample shading, sample mask, and alpha-to-coverage/one into pipeline creation. Update the example test (vulkan-smoke) to request MSAA, create transient MSAA color attachments, include them in framebuffers, and handle resource creation/disposal. Also increase packed data size checks where appropriate. --- project/src/ExternalInterface.cpp | 90 ++++++++++++++++++- src/lime/graphics/vulkan/VKDevice.hx | 14 ++- .../graphics/vulkan/VKGraphicsPipelineInfo.hx | 12 +++ src/lime/graphics/vulkan/VKPhysicalDevice.hx | 46 ++++++++++ src/lime/graphics/vulkan/VKRenderPass.hx | 6 +- tests/vulkan-smoke/Source/Main.hx | 71 +++++++++++++-- 6 files changed, 225 insertions(+), 14 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 81fdf8ad8a..59a2978fd9 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -4914,6 +4914,10 @@ namespace lime { 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_queueFamilies = val_id ("queueFamilies"); const int id_index = val_id ("index"); @@ -4972,6 +4976,10 @@ namespace lime { 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_queueFamilies, queueFamilyArray); val_array_set_i (devices, i, deviceObject); @@ -5062,6 +5070,10 @@ namespace lime { 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_queueFamilies = hl_hash_utf8 ("queueFamilies"); const int id_index = hl_hash_utf8 ("index"); @@ -5122,6 +5134,10 @@ namespace lime { 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_setp (deviceObject, id_queueFamilies, &hlt_array, queueFamilyArray); } @@ -7760,7 +7776,7 @@ namespace lime { "vkCreateRenderPass"); if (!vkCreateRenderPass) return alloc_null (); std::vector packed = GetVulkanIntVector (state); - if (packed.size () < 11) return alloc_null (); + if (packed.size () < 16) return alloc_null (); int colorFormat = packed[0]; int depthStencilFormat = packed[1]; @@ -7773,6 +7789,11 @@ namespace lime { 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; @@ -7795,6 +7816,7 @@ namespace lime { VkAttachmentReference depthReference; memset (&depthReference, 0, sizeof (depthReference)); bool hasDepth = depthStencilFormat != VK_FORMAT_UNDEFINED; + bool hasResolve = resolveFormat != VK_FORMAT_UNDEFINED; if (hasDepth) { VkAttachmentDescription depthAttachment; @@ -7813,11 +7835,32 @@ namespace lime { } + 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; @@ -7868,7 +7911,7 @@ namespace lime { "vkCreateRenderPass"); if (!vkCreateRenderPass) return 0; std::vector packed = GetHLVulkanIntVector (state); - if (packed.size () < 11) return 0; + if (packed.size () < 16) return 0; int colorFormat = packed[0]; int depthStencilFormat = packed[1]; @@ -7881,6 +7924,11 @@ namespace lime { 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; @@ -7903,6 +7951,7 @@ namespace lime { VkAttachmentReference depthReference; memset (&depthReference, 0, sizeof (depthReference)); bool hasDepth = depthStencilFormat != VK_FORMAT_UNDEFINED; + bool hasResolve = resolveFormat != VK_FORMAT_UNDEFINED; if (hasDepth) { VkAttachmentDescription depthAttachment; @@ -7921,11 +7970,32 @@ namespace lime { } + 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; @@ -9492,7 +9562,7 @@ namespace lime { static VkPipeline CreateManagedVulkanGraphicsPipeline (Window* targetWindow, VkInstance instance, VkDevice device, VkRenderPass renderPass, VkPipelineLayout layout, VkShaderModule vertexShader, VkShaderModule fragmentShader, const std::vector& state) { - if (state.size () < 35 || !renderPass || !layout || !vertexShader || !fragmentShader) { + if (state.size () < 41 || !renderPass || !layout || !vertexShader || !fragmentShader) { lastVKError = "Invalid Vulkan graphics pipeline state"; return VK_NULL_HANDLE; @@ -9534,6 +9604,12 @@ namespace lime { 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) { @@ -9635,7 +9711,13 @@ namespace lime { VkPipelineMultisampleStateCreateInfo multisample; memset (&multisample, 0, sizeof (multisample)); multisample.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + 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)); diff --git a/src/lime/graphics/vulkan/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx index 46103482d9..2d20ab4d0d 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -370,7 +370,10 @@ class VKDevice 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):VKRenderPass + 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()) @@ -386,14 +389,19 @@ class VKDevice depthInitialLayout, depthFinalLayout, depthLoadOp, - depthStoreOp + 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); + return new VKRenderPass(this, renderPassHandle, colorFormat, depthStencilFormat, samples, resolveFormat); } } #end diff --git a/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx index 2763dcb000..527a44ada0 100644 --- a/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx +++ b/src/lime/graphics/vulkan/VKGraphicsPipelineInfo.hx @@ -29,6 +29,12 @@ class VKGraphicsPipelineInfo 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; @@ -85,6 +91,12 @@ class VKGraphicsPipelineInfo backCompareMask, backWriteMask, backReference, + rasterizationSamples, + sampleShading ? 1 : 0, + Std.int(minSampleShading * 1000000), + sampleMask, + alphaToCoverage ? 1 : 0, + alphaToOne ? 1 : 0, vertexBindings.length ]; diff --git a/src/lime/graphics/vulkan/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx index 7958b2ce5a..fd390ae95f 100644 --- a/src/lime/graphics/vulkan/VKPhysicalDevice.hx +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -23,6 +23,10 @@ class VKPhysicalDevice 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 supportsPresent(default, null):Bool; public var queueFamilies(default, null):Array; @@ -39,6 +43,10 @@ class VKPhysicalDevice vendorID = data.vendorID; deviceID = data.deviceID; deviceType = data.deviceType; + framebufferColorSampleCounts = data.framebufferColorSampleCounts; + framebufferDepthSampleCounts = data.framebufferDepthSampleCounts; + framebufferNoAttachmentsSampleCounts = data.framebufferNoAttachmentsSampleCounts; + framebufferStencilSampleCounts = data.framebufferStencilSampleCounts; deviceTypeName = switch (deviceType) { case 1: "integrated-gpu"; @@ -123,4 +131,42 @@ class VKPhysicalDevice { 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/VKRenderPass.hx b/src/lime/graphics/vulkan/VKRenderPass.hx index bcbf0ec83f..8a7ddfe95c 100644 --- a/src/lime/graphics/vulkan/VKRenderPass.hx +++ b/src/lime/graphics/vulkan/VKRenderPass.hx @@ -14,16 +14,20 @@ class VKRenderPass 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) + 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 diff --git a/tests/vulkan-smoke/Source/Main.hx b/tests/vulkan-smoke/Source/Main.hx index 3e65452a09..fd63e61ba6 100644 --- a/tests/vulkan-smoke/Source/Main.hx +++ b/tests/vulkan-smoke/Source/Main.hx @@ -43,7 +43,10 @@ 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; @@ -82,6 +85,7 @@ class Main extends Application 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; @@ -187,6 +191,7 @@ class Main extends Application 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); @@ -485,9 +490,22 @@ class Main extends Application private function createOnscreenPass():Bool { - 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 || !createDepthResources() || !createFramebuffers()) + 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; @@ -511,6 +529,7 @@ class Main extends Application 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)); @@ -526,11 +545,33 @@ class Main extends Application 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); + 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; @@ -553,7 +594,8 @@ class Main extends Application return false; } - var framebuffer = device.createFramebuffer(renderPass, [imageView, depthView], swapchain.width, swapchain.height); + 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(); @@ -692,12 +734,13 @@ class Main extends Application return false; } - return createDepthResources() && createFramebuffers(); + return createColorResources() && createDepthResources() && createFramebuffers(); } private function disposeSwapchainResources():Void { disposeSwapchainFramebuffers(); + disposeColorResources(); disposeDepthResources(); } @@ -722,6 +765,20 @@ class Main extends Application 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) @@ -792,6 +849,8 @@ class Main extends Application commandBuffer = null; commandPool = null; + colorImage = null; + colorView = null; cubeDescriptorSet = null; cubeDescriptorSetLayout = null; cubeFragmentShader = null; From 0c3d568df9837b8ea6dcc2abcc3f9628bb880605 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 26 May 2026 02:23:22 -0400 Subject: [PATCH 018/251] Enable Vulkan by default for Windows/Linux builds Add Vulkan support to C++ Windows and Linux builds and CI. CI: install libvulkan-dev and adjust workflow steps to build the default Vulkan-enabled Lime (remove explicit -D lime-vulkan flags). Build/config: add lime-vulkan defines in include.xml and set LIME_VULKAN for windows/linux in project/Build.xml (respecting no-vulkan/apple/winrt exclusions). Tests: remove the explicit lime-vulkan haxedef from tests/vulkan-smoke/project.xml. README: document that native Vulkan is included in standard Windows and Linux C++ Lime builds and note Apple still requires explicit Vulkan builds/MoltenVK. --- .github/workflows/main.yml | 10 +++++----- README.md | 4 ++-- include.xml | 2 ++ project/Build.xml | 1 + tests/vulkan-smoke/project.xml | 1 - 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7965bbfae6..5aa78cd755 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 @@ -218,9 +218,9 @@ jobs: haxelib run lime rebuild tools -nocolor -verbose -nocffi haxelib run lime setup -alias -y -nocffi - - name: Rebuild Lime (Linux Vulkan) + - name: Rebuild Lime (Linux default Vulkan) run: | - lime rebuild linux -64 -release -nocolor -verbose -nocffi -D lime-vulkan + lime rebuild linux -64 -release -nocolor -verbose -nocffi - name: Build Vulkan smoke test app working-directory: tests/vulkan-smoke @@ -242,7 +242,7 @@ jobs: - name: Build HelloWorld Vulkan sample run: | lime create HelloWorld -verbose -nocolor - lime build HelloWorld linux -release -verbose -nocolor -D lime-vulkan --window-render-type=vulkan + lime build HelloWorld linux -release -verbose -nocolor --window-render-type=vulkan macos: runs-on: macos-14 diff --git a/README.md b/README.md index a703f9140a..3585d2f17b 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ Lime does not include a renderer, but exposes the current context: * Vulkan The GL context is based upon the WebGL standard, implemented for both OpenGL and OpenGL ES as needed. -Native Vulkan support currently focuses on window/bootstrap helpers and a minimal validation renderer for backend verification, not a full high-level renderer. -The native Vulkan bootstrap and validation renderer are currently opt-in and require building Lime with the `lime-vulkan` define plus Vulkan headers available to the native toolchain. +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, set `` in project XML, or use `--window-render-type=vulkan`. The in-repo `tests/vulkan-smoke` project is used as the current Vulkan CI smoke app. 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 a1a5b48d2c..8924eb073d 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -36,6 +36,7 @@ + diff --git a/tests/vulkan-smoke/project.xml b/tests/vulkan-smoke/project.xml index 47c1e61a7a..d23af8f962 100644 --- a/tests/vulkan-smoke/project.xml +++ b/tests/vulkan-smoke/project.xml @@ -8,7 +8,6 @@ - From 0e4b7d4c974204047c8f1b30fbcc3be282fedfb9 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 26 May 2026 04:23:39 -0400 Subject: [PATCH 019/251] Vulkan: mapped memory & descriptor helpers Introduce managed Vulkan mapped memory support and several Vulkan convenience helpers. Tracks mapped memory in a ManagedVulkanMappedMemory map, prevents double-mapping, automatically unmaps on vkFreeMemory, and exposes map/unmap/write/flush/invalidate operations. Add UpdateManagedVulkanDescriptorSets to batch-update descriptor sets, plus command helpers (dynamic descriptor set bind, draw indirect, draw indexed indirect, clear attachments). Export new device limit fields (maxPushConstantsSize, minStorageBufferOffsetAlignment, minUniformBufferOffsetAlignment, nonCoherentAtomSize) and update Haxe NativeCFFI bindings/primes for new functions. --- project/src/ExternalInterface.cpp | 844 ++++++++++++++++++ .../_internal/backend/native/NativeCFFI.hx | 127 +++ src/lime/graphics/vulkan/VKBuffer.hx | 28 + src/lime/graphics/vulkan/VKCommandBuffer.hx | 60 ++ src/lime/graphics/vulkan/VKDescriptorWrite.hx | 115 +++ src/lime/graphics/vulkan/VKDevice.hx | 33 + src/lime/graphics/vulkan/VKDeviceMemory.hx | 142 +++ src/lime/graphics/vulkan/VKPhysicalDevice.hx | 8 + src/lime/graphics/vulkan/VKUploadRing.hx | 106 +++ src/lime/graphics/vulkan/VKUploadSlice.hx | 23 + 10 files changed, 1486 insertions(+) create mode 100644 src/lime/graphics/vulkan/VKDescriptorWrite.hx create mode 100644 src/lime/graphics/vulkan/VKUploadRing.hx create mode 100644 src/lime/graphics/vulkan/VKUploadSlice.hx diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 59a2978fd9..e5673f0ea0 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #ifdef LIME_SDL_SOUND @@ -136,6 +137,34 @@ namespace lime { } + struct ManagedVulkanMappedMemory { + + VkDevice device; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; + void* data; + + }; + + + static std::unordered_map mappedVulkanMemory; + + + static uint64_t GetManagedVulkanMappedMemoryKey (VkDeviceMemory memory) { + + return (uint64_t)(uintptr_t)memory; + + } + + + static VkDeviceSize NormalizeVulkanRangeSize (uint64_t size) { + + return size == 0 ? VK_WHOLE_SIZE : (VkDeviceSize)size; + + } + + static bool CreateManagedVulkanInstance (Window* targetWindow, const char* applicationName, VkInstance* outInstance) { if (!targetWindow || !outInstance) { @@ -363,6 +392,88 @@ namespace lime { } + static bool UpdateManagedVulkanDescriptorSets (Window* targetWindow, VkInstance instance, VkDevice device, const std::vector& packed) { + + 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; + + std::vector bufferInfos; + std::vector imageInfos; + std::vector descriptorWrites; + bufferInfos.reserve ((size_t)writeCount); + imageInfos.reserve ((size_t)writeCount); + descriptorWrites.reserve ((size_t)writeCount); + + 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; + + if (kind == 0) { + + 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) { + + 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]; + + 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; + + } else { + + lastVKError = "Invalid Vulkan descriptor write kind"; + return false; + + } + + if (!write.dstSet) return false; + descriptorWrites.push_back (write); + + } + + vkUpdateDescriptorSets (device, (uint32_t)descriptorWrites.size (), descriptorWrites.empty () ? 0 : descriptorWrites.data (), 0, 0); + lastVKError.clear (); + return true; + + } + + static bool CreateManagedVulkanDevice (Window* targetWindow, VkInstance instance, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const std::vector& requestedExtensions, VkDevice* outDevice, VkQueue* outQueue) { @@ -4918,6 +5029,10 @@ namespace lime { 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"); @@ -4980,6 +5095,12 @@ namespace lime { 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); @@ -5074,6 +5195,10 @@ namespace lime { 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"); @@ -5138,6 +5263,13 @@ namespace lime { 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); } @@ -6452,6 +6584,16 @@ namespace lime { 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 (); @@ -6475,6 +6617,16 @@ namespace lime { 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 (); @@ -6652,6 +6804,392 @@ namespace lime { } + 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 @@ -9144,6 +9682,37 @@ namespace lime { } + bool lime_vk_update_descriptor_sets (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value writes) { + +#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 bool HL_NAME(hl_vk_update_descriptor_sets) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* writes) { + +#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 + + } + + value lime_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, int pushConstantStages, int pushConstantSize) { @@ -10296,6 +10865,56 @@ namespace lime { } + 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) { + +#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 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) { + +#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 + + } + + value lime_vulkan_renderer_get_info (value handle) { if (val_is_null (handle)) return alloc_string (""); @@ -10590,6 +11209,99 @@ namespace lime { } + + 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) { + +#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 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) { + +#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 + + } + + + 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) { + +#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 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 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 () { return alloc_string (lastVulkanRendererError.c_str ()); @@ -11026,6 +11738,128 @@ namespace lime { } + bool lime_vk_cmd_clear_attachments (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, value state, value clear) { + +#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++; + + } + + if (packed[1] != 0 || packed[2] != 0) { + + 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 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) { + +#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++; + + } + + if (packed[1] != 0 || packed[2] != 0) { + + 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 + + } + + 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) { @@ -12662,6 +13496,11 @@ namespace lime { 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); @@ -12694,6 +13533,7 @@ namespace lime { 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); @@ -12707,18 +13547,22 @@ namespace lime { 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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index d543f2f19f..a706695109 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -427,6 +427,21 @@ class NativeCFFI @: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; @@ -526,6 +541,9 @@ class NativeCFFI @: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; @@ -568,6 +586,10 @@ class NativeCFFI @: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; @@ -586,6 +608,13 @@ class NativeCFFI @: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; @@ -606,6 +635,9 @@ class NativeCFFI @: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; @@ -994,6 +1026,16 @@ class NativeCFFI "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", @@ -1058,6 +1100,8 @@ class NativeCFFI 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", @@ -1084,6 +1128,8 @@ class NativeCFFI 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>( @@ -1096,6 +1142,10 @@ class NativeCFFI "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>( @@ -1108,6 +1158,8 @@ class NativeCFFI 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>( @@ -1358,6 +1410,11 @@ class NativeCFFI 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); @@ -1390,6 +1447,7 @@ class NativeCFFI 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); @@ -1403,18 +1461,22 @@ class NativeCFFI 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 @@ -2215,6 +2277,37 @@ class NativeCFFI 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 { @@ -2388,6 +2481,12 @@ class NativeCFFI 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 @@ -2465,6 +2564,13 @@ class NativeCFFI 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 @@ -2507,6 +2613,20 @@ class NativeCFFI 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 @@ -2549,6 +2669,13 @@ class NativeCFFI 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 diff --git a/src/lime/graphics/vulkan/VKBuffer.hx b/src/lime/graphics/vulkan/VKBuffer.hx index 2fbeb81a73..de31962199 100644 --- a/src/lime/graphics/vulkan/VKBuffer.hx +++ b/src/lime/graphics/vulkan/VKBuffer.hx @@ -116,6 +116,34 @@ class VKBuffer 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); diff --git a/src/lime/graphics/vulkan/VKCommandBuffer.hx b/src/lime/graphics/vulkan/VKCommandBuffer.hx index 375748ca99..12638f2e2a 100644 --- a/src/lime/graphics/vulkan/VKCommandBuffer.hx +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -95,6 +95,21 @@ class VKCommandBuffer 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) @@ -231,6 +246,23 @@ class VKCommandBuffer 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); @@ -353,6 +385,34 @@ class VKCommandBuffer 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) 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 index 2d20ab4d0d..28e375114e 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -151,6 +151,12 @@ class VKDevice 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); @@ -224,6 +230,33 @@ class VKDevice 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) diff --git a/src/lime/graphics/vulkan/VKDeviceMemory.hx b/src/lime/graphics/vulkan/VKDeviceMemory.hx index 101b09ad20..39dc6ad5ee 100644 --- a/src/lime/graphics/vulkan/VKDeviceMemory.hx +++ b/src/lime/graphics/vulkan/VKDeviceMemory.hx @@ -17,6 +17,9 @@ 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; @@ -32,6 +35,11 @@ class VKDeviceMemory public function dispose():Void { + if (mapped) + { + unmap(); + } + #if (!macro && lime_cffi && lime_vulkan) if (isValid() && device != null && device.isValid()) { @@ -52,6 +60,140 @@ class VKDeviceMemory 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 diff --git a/src/lime/graphics/vulkan/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx index fd390ae95f..c05a23fc4f 100644 --- a/src/lime/graphics/vulkan/VKPhysicalDevice.hx +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -28,6 +28,10 @@ class VKPhysicalDevice 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; @@ -47,6 +51,10 @@ class VKPhysicalDevice 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"; 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; + } +} From 9fe4452ca93e2c3a7a0d836132d5a4691467b325 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 26 May 2026 08:01:53 -0400 Subject: [PATCH 020/251] Vulkan: cache device proc addresses Add managedVulkanDeviceProcCache to store PFN_vkVoidFunction lookups per VkDevice and a ClearManagedVulkanDeviceProcCache helper. --- project/src/ExternalInterface.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index e5673f0ea0..dc906f4c13 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -149,6 +149,7 @@ namespace lime { static std::unordered_map mappedVulkanMemory; + static std::unordered_map > managedVulkanDeviceProcCache; static uint64_t GetManagedVulkanMappedMemoryKey (VkDeviceMemory memory) { @@ -165,6 +166,13 @@ namespace lime { } + static void ClearManagedVulkanDeviceProcCache (VkDevice device) { + + if (device) managedVulkanDeviceProcCache.erase ((uint64_t)(uintptr_t)device); + + } + + static bool CreateManagedVulkanInstance (Window* targetWindow, const char* applicationName, VkInstance* outInstance) { if (!targetWindow || !outInstance) { @@ -356,13 +364,24 @@ namespace lime { static PFN_vkVoidFunction GetManagedVulkanDeviceProc (Window* targetWindow, VkInstance instance, VkDevice device, const char* name) { - if (!targetWindow || !instance || !device) { + if (!targetWindow || !instance || !device || !name) { lastVKError = "Missing Vulkan window, instance, or device"; return 0; } + 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; + + } + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)targetWindow->GetVulkanInstanceProcAddr (); if (!vkGetInstanceProcAddr) { @@ -379,14 +398,15 @@ namespace lime { } - PFN_vkVoidFunction proc = vkGetDeviceProcAddr (device, name); + PFN_vkVoidFunction proc = vkGetDeviceProcAddr (device, procName.c_str ()); if (!proc) { - lastVKError = std::string ("Missing Vulkan device function: ") + name; + lastVKError = std::string ("Missing Vulkan device function: ") + procName; return 0; } + managedVulkanDeviceProcCache[deviceKey][procName] = proc; return proc; } @@ -5376,6 +5396,7 @@ namespace lime { PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (device, "vkDestroyDevice"); if (vkDestroyDevice) { + ClearManagedVulkanDeviceProcCache (device); vkDestroyDevice (device, 0); } @@ -5402,6 +5423,7 @@ namespace lime { PFN_vkDestroyDevice vkDestroyDevice = (PFN_vkDestroyDevice)vkGetDeviceProcAddr (device, "vkDestroyDevice"); if (vkDestroyDevice) { + ClearManagedVulkanDeviceProcCache (device); vkDestroyDevice (device, 0); } From c653ae33be5a3f1bec62e24b6f9a891ee5973ff8 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 27 May 2026 03:22:23 -0400 Subject: [PATCH 021/251] Vulkan: Android support First pass --- .github/workflows/main.yml | 5 +++++ project/Build.xml | 2 +- src/lime/tools/ProjectXMLParser.hx | 8 +++++++- .../android/template/app/src/main/AndroidManifest.xml | 4 ++++ tools/platforms/AndroidPlatform.hx | 3 +++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5aa78cd755..24efa86ab4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -538,6 +538,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: diff --git a/project/Build.xml b/project/Build.xml index 8924eb073d..28a39cd0b6 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -36,7 +36,7 @@ - + diff --git a/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index 63ca4d5bb6..faa9d6ae10 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1985,7 +1985,13 @@ class ProjectXMLParser extends HXProject Reflect.setField(windows[id], name, Std.string(value)); case "render-type", "context-type": - Reflect.setField(windows[id], "renderType", Std.string(value).toLowerCase()); + 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/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/tools/platforms/AndroidPlatform.hx b/tools/platforms/AndroidPlatform.hx index ebdad5f110..91057bc452 100644 --- a/tools/platforms/AndroidPlatform.hx +++ b/tools/platforms/AndroidPlatform.hx @@ -441,6 +441,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, From 88769f618053a05b33206149a96601fa7a7944b7 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 29 May 2026 14:00:18 -0700 Subject: [PATCH 022/251] Window: updated gamepad mappings from: https://github.com/gabomdq/SDL_GameControllerDB/ Seems to have been a while. Last commit for mappings in Lime that I found was: 314e0204283dfebe463ec909b28b6c26f2ca93a0 --- src/lime/ui/Window.hx | 2412 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 2230 insertions(+), 182 deletions(-) diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index b53f65b2af..b9ce4fdd22 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -241,203 +241,2251 @@ class Window 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,", ]; From ea029fb253ab728adc7344e5d6f33cbd18997723 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 29 May 2026 14:15:29 -0700 Subject: [PATCH 023/251] Missed a comma --- src/lime/ui/Window.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index b9ce4fdd22..7fe8d2a1c3 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -2485,7 +2485,7 @@ class Window "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," + "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,", ]; From 17d95bd7c1df7433a668447f836b14c3a3ad3b46 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 03:43:17 -0400 Subject: [PATCH 024/251] Fix GL cleanup and skip invisible windows --- project/src/backend/sdl/SDLWindow.cpp | 46 +++++++++++++++---- .../backend/native/NativeApplication.hx | 1 + 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index 522556fcf8..5d42c30bc3 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -475,6 +475,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) @@ -486,16 +504,6 @@ namespace lime { } - if (sdlRenderer) { - - SDL_DestroyRenderer (sdlRenderer); - - } else if (context) { - - SDL_GL_DeleteContext (context); - - } - } @@ -544,6 +552,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; diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 1be8e8df77..a6478bba2d 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -462,6 +462,7 @@ class NativeApplication for (window in parent.__windows) { if (window == null) continue; + if (!window.visible) continue; // parent.renderer = renderer; switch (renderEventInfo.type) { From e5273f49884a226a693174c88e682f85971d7acd Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 03:44:39 -0400 Subject: [PATCH 025/251] Use renderer window attribute; update parser Standardize the window attribute name to renderer. ProjectXMLParser now recognizes "renderer" and sets the window renderType. README and tests/vulkan-smoke/project.xml updated to use . --- .github/workflows/main.yml | 9 --------- README.md | 2 +- src/lime/tools/ProjectXMLParser.hx | 2 +- tests/vulkan-smoke/project.xml | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 24efa86ab4..60e98fe5be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -235,15 +235,6 @@ jobs: fi SDL_AUDIODRIVER=dummy xvfb-run -a Export/linux/bin/LimeVulkanSmoke - - name: Install samples - run: | - haxelib git lime-samples https://github.com/openfl/lime-samples --quiet - - - name: Build HelloWorld Vulkan sample - run: | - lime create HelloWorld -verbose -nocolor - lime build HelloWorld linux -release -verbose -nocolor --window-render-type=vulkan - macos: runs-on: macos-14 steps: diff --git a/README.md b/README.md index 3585d2f17b..167628b285 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Lime does not include a renderer, but exposes the current context: 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, set `` in project XML, or use `--window-render-type=vulkan`. +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/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index faa9d6ae10..e535b37f5e 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1984,7 +1984,7 @@ class ProjectXMLParser extends HXProject case "parameters", "title": Reflect.setField(windows[id], name, Std.string(value)); - case "render-type", "context-type": + case "renderer": var renderType = Std.string(value).toLowerCase(); Reflect.setField(windows[id], "renderType", renderType); if (renderType == "vulkan") diff --git a/tests/vulkan-smoke/project.xml b/tests/vulkan-smoke/project.xml index d23af8f962..ef66f4b29a 100644 --- a/tests/vulkan-smoke/project.xml +++ b/tests/vulkan-smoke/project.xml @@ -9,6 +9,6 @@ - + From 2ac936ce29584a473d0f013b42a73827cddaa6b1 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 04:39:51 -0400 Subject: [PATCH 026/251] Vulkan: Keep non-Vulkan native builds isolated --- project/Build.xml | 6 +-- project/src/ExternalInterface.cpp | 82 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/project/Build.xml b/project/Build.xml index 28a39cd0b6..84ef070811 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -35,15 +35,13 @@ - + - - - + diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index dc906f4c13..43ff2ea8a3 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -12166,6 +12166,21 @@ namespace lime { } + bool lime_vk_update_descriptor_sets (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value writes) { + + return LimeVulkanUnavailableBool (); + + } + + + HL_PRIM bool HL_NAME(hl_vk_update_descriptor_sets) (HL_CFFIPointer* window, int instanceHigh, int instanceLow, int deviceHigh, + int deviceLow, hl_varray* writes) { + + return LimeVulkanUnavailableBool (); + + } + + value lime_vk_create_pipeline_layout (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, value setLayouts, int pushConstantStages, int pushConstantSize) { @@ -12378,6 +12393,24 @@ namespace lime { } + 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 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) { + + return LimeVulkanUnavailableBool (); + + } + + 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) { @@ -12474,6 +12507,39 @@ namespace lime { } + 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 LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + 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) { @@ -12569,6 +12635,22 @@ namespace lime { } + bool lime_vk_cmd_clear_attachments (value window, int instanceHigh, int instanceLow, int deviceHigh, int deviceLow, int commandBufferHigh, + int commandBufferLow, value state, value clear) { + + return LimeVulkanUnavailableBool (); + + } + + + 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 LimeVulkanUnavailableBool (); + + } + + 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) { From 9524adbc5f200c6e9459f97b4d6dcbc32ff119dd Mon Sep 17 00:00:00 2001 From: dPavlenko Date: Thu, 16 Apr 2026 11:22:17 +0300 Subject: [PATCH 027/251] ios template: added identity settings and 'update to recommended settings' changes to xcode project --- .../{{app.file}}.xcodeproj/project.pbxproj | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) 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; From 2e1d2217c5769e4fc53980d815b049acb6a63031 Mon Sep 17 00:00:00 2001 From: ACrazyTown <47027981+ACrazyTown@users.noreply.github.com> Date: Thu, 14 May 2026 18:57:31 +0200 Subject: [PATCH 028/251] Add support for VAOs on macOS --- .../src/graphics/opengl/OpenGLBindings.cpp | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/project/src/graphics/opengl/OpenGLBindings.cpp b/project/src/graphics/opengl/OpenGLBindings.cpp index dbcc4f1aec..d571b3d87d 100644 --- a/project/src/graphics/opengl/OpenGLBindings.cpp +++ b/project/src/graphics/opengl/OpenGLBindings.cpp @@ -531,6 +531,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 +548,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 +1212,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 +1231,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 +1425,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 +1442,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 +3916,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 +3937,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 From 3b861489fa34356c2d7809dc76d647b7aa0aa697 Mon Sep 17 00:00:00 2001 From: ACrazyTown <47027981+ACrazyTown@users.noreply.github.com> Date: Thu, 14 May 2026 19:21:05 +0200 Subject: [PATCH 029/251] Fix GC not picking up some GL objects on desktop --- .../src/graphics/opengl/OpenGLBindings.cpp | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/project/src/graphics/opengl/OpenGLBindings.cpp b/project/src/graphics/opengl/OpenGLBindings.cpp index d571b3d87d..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 From 07c2c7ce17c403dc3fc0a0bc89af56e4e9506b62 Mon Sep 17 00:00:00 2001 From: MAJigsaw77 <77043862+MAJigsaw77@users.noreply.github.com> Date: Thu, 17 Jul 2025 20:43:42 +0300 Subject: [PATCH 030/251] Don't use `ReplaceVistaIcon` on windows `cpp` target anymore. --- templates/windows/resource/ApplicationMain.rc | 2 ++ tools/platforms/WindowsPlatform.hx | 13 +++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/templates/windows/resource/ApplicationMain.rc b/templates/windows/resource/ApplicationMain.rc index 2d12ca8ef6..23139f7fc4 100644 --- a/templates/windows/resource/ApplicationMain.rc +++ b/templates/windows/resource/ApplicationMain.rc @@ -1,5 +1,7 @@ #include "winres.h" +IDI_ICON1 ICON "ApplicationMain.ico" + LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK VS_VERSION_INFO VERSIONINFO diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index f9f9aa58fd..8db17eff27 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); - } } } } From 13a9b79ec7e586bec11aedf1ab545514b5fd4273 Mon Sep 17 00:00:00 2001 From: ACrazyTown <47027981+ACrazyTown@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:56:12 +0200 Subject: [PATCH 031/251] Implement OpenAL audio capture extension (#1965) * Implement OpenAL audio capture extension * OpenALAudioContext: wrap import in conditional * Fix OpenAL capture default-device handling The follow-up change makes the capture API accept a null device name for the default input device and fixes the ALC string path for capture/default-device queries. --------- Co-authored-by: Chris Speciale --- project/src/media/openal/OpenALBindings.cpp | 113 +++++++++++++++++- .../_internal/backend/native/NativeCFFI.hx | 41 +++++++ src/lime/media/OpenALAudioContext.hx | 41 ++++++- src/lime/media/openal/ALC.hx | 48 ++++++++ 4 files changed, 238 insertions(+), 5 deletions(-) diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index a26c5c679a..2bf26d5a6f 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 @@ -3379,7 +3380,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 +3389,13 @@ namespace lime { HL_PRIM vbyte* HL_NAME(hl_alc_get_string) (HL_CFFIPointer* device, int param) { +<<<<<<< HEAD + ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : NULL; +======= ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : 0; +>>>>>>> origin/develop 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 +3518,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); @@ -3628,6 +3729,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) @@ -3752,6 +3858,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/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index a706695109..af16f05912 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -3092,6 +3092,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; @@ -3259,6 +3269,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)); @@ -3379,6 +3399,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); @@ -3735,6 +3760,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/media/OpenALAudioContext.hx b/src/lime/media/OpenALAudioContext.hx index d731f72397..c0eeb6b4e6 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 @@ -587,5 +595,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..7e2cc43ef7 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,9 @@ 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 function closeDevice(device:ALDevice):Bool { @@ -202,5 +206,49 @@ class ALC NativeCFFI.lime_alc_suspend_context(context); #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 From b1e2671f84f860defadfa063f2b0f7ed9b8c34b6 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 12:04:36 -0400 Subject: [PATCH 032/251] Fix leftover OpenAL merge markers --- project/src/media/openal/OpenALBindings.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index 2bf26d5a6f..50fac5b710 100644 --- a/project/src/media/openal/OpenALBindings.cpp +++ b/project/src/media/openal/OpenALBindings.cpp @@ -3389,11 +3389,7 @@ namespace lime { HL_PRIM vbyte* HL_NAME(hl_alc_get_string) (HL_CFFIPointer* device, int param) { -<<<<<<< HEAD ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : NULL; -======= - ALCdevice* alcDevice = device ? (ALCdevice*)device->ptr : 0; ->>>>>>> origin/develop const char* result = alcGetString (alcDevice, param); if (!result) return 0; int length = strlen (result); From f220607d5730911d0de532035a03bb2555d87fbc Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 12:25:29 -0400 Subject: [PATCH 033/251] Fix Windows cpp icon resource handling 07c2c7ce switched Windows cpp builds from post-link icon patching with ReplaceVistaIcon to embedding ApplicationMain.ico through ApplicationMain.rc. That introduced two separate regressions. The resource template referenced ApplicationMain.ico unconditionally, so builds failed with RC2135 when icon generation did not produce a file. Static cpp builds also dropped the resource at the final Main link step, so the generated icon and metadata never made it into the executable. Generate the Windows icon before copying the resource template, set HAS_ICON from createWindowsIcon, gate the ICON stanza in ApplicationMain.rc, and include the rc file group in the static cpp Main link. --- templates/cpp/static/BuildMain.xml | 1 + templates/windows/resource/ApplicationMain.rc | 2 +- tools/platforms/WindowsPlatform.hx | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) 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/windows/resource/ApplicationMain.rc b/templates/windows/resource/ApplicationMain.rc index 23139f7fc4..2b36d4781f 100644 --- a/templates/windows/resource/ApplicationMain.rc +++ b/templates/windows/resource/ApplicationMain.rc @@ -1,6 +1,6 @@ #include "winres.h" -IDI_ICON1 ICON "ApplicationMain.ico" +::if (HAS_ICON)::IDI_ICON1 ICON "ApplicationMain.ico"::end:: LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index 8db17eff27..3bc28d3110 100644 --- a/tools/platforms/WindowsPlatform.hx +++ b/tools/platforms/WindowsPlatform.hx @@ -1016,6 +1016,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")) From ad09934eacfb6067c0ca213f7d7b85719321c9da Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 12:25:29 -0400 Subject: [PATCH 034/251] Rebuild tools --- run.n | Bin 141709 -> 142270 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/run.n b/run.n index deae46fd3a0e9af590e7ea899b554b6db46fd883..1436727e319e0e8446f9709a519888e51b356224 100644 GIT binary patch delta 22977 zcmaic2S5~87w(=}dhcb2zJP!Thzi(tvA4CCSV2@!EU1XRpwSqk(Wn!>iJHV-6HS7O zvG?A4)YuXgdyk1mec#z#WS8If-k;wy-zoRpb9#3nsS@$8t6Eak=&H6=6$~8Me+Za_1f`nobjeYr z9Ja0FZ*P((YqC*TS^U8k#tL$VHaQ6F-#>%4&f>lvW~&Oc>If%wBahE^tJ`PRMK-m z$u^06;2h(GO9Z?Mg>2O!**P8D#@!N98{=?jGHrBT2ZBz-ZJru2b&oWv|Gt`NQ-&I{MVIKlG;O+R5`gy z)oLlJY1Ql0tyjN6L)1o+v_An(ViJ{o4#R@GCBpb2h+3`cm7A}&QRU?J&z7Q-Aikn> zbkqjDWZ14UNDh+`AgHU6h$tjk5stATm6K81_NpP-1(`jE_mUbX!x^cZq>cbmo^sVO zAaW$b`E2KG^q)DTpjUQ&zOlo30=DiYhN+STiyHDrjihB;eRySk_W zN^duEP_~MUR64ILa;j0-zM3(s1nEBj$v*`omPxY|RA+k-8d#&MO6r<|y7>(RY&8y{ zH$okdJ!D8$?`-K$PEf+O>5Y<9$gSm|4q5q7eAr*CN zqiSgw)Felml&Vsz9ieMDFh4u1XCG+;YwaLtFk(=?^k-?(y8Q?C>?gUUA-C#j2(K-Z zEM^BY5z2DsRC=Xcbq=Jd%0JH0l2)gLxm1pENQd3PbOfMQW#{!mzS;eUWFs1WH+`T04bsyA_|P1?14Etv_`nJTDj_?FWlb{y7NqKGx?i|T_X@b zCech%m^5V4fk_UNVN517Q5qqK_Dw=hD=&8>D3al z?-;FQa-7LcCihtJf=N&-#89ObWPO;706`#OSq1F6hV(snbcQr#xSLyqOKZe500c8j zi-84UxdR6E&mNGSSCHLH`j&Nvlof7`>|VBpqZP^vw+hj=T@kCRs!853%s;)tdiKf6 z50h$jg?=iNf1s8ex+!(seG3!1A&_R>AqdGrB1zS?2a^IOc}#McIL+3FJ%4%bC%?v4U(P>-(47u$2gF_Ve&JxJDJ>NtzQmEG!sJ(v`cclp*g{@874NV zK_56QP)gjZMgG(W!naHs=fb>sE;K80!ERyp0F%o~9gheX>I>-3#HX(^&?DZrMqiY} zUS;ghsG)3DDay|t$$ba(2i(>lPRCFRvW4O;aRn|-zb&6)OfVYR>~NI6n3hf z1M_lndrRw>b5Zrl8j;;Uw?{(XAp`TI`C}ooQ4Pu}=!4_y}oHx9LT<}-v- zFd3xP=OBZW4DXgCl(pWKJjP5xo^!tdS<7U%z9!~|Yng-%I4T&Nd4F*EY ziHXu&mL2&LvKLHjr$eE}0-7kb29zevfN&0zi%d$GwEN0f>T!t(vvJGj4Ww+7plcY{ zMFo(IcqUu z)+kH;D!A-jsB)0zFIL$}=}VOhei^h@N%4=iKeG%;X65)MJCvD=<0OPL-8EU|3pzj2Wyu+__LpL(3M8GV3;Jr_2fLCJoxC zya@bg2uB?(8?Ev4ENzM-Ct)`ANW`~k4$4LuzDgEX8lG`5TSGl@$ZJ+W`u4cdf06Z@| zsKf?kyVO1eJmU}&o;#$>3kr|>a|D9+M}USfnSK;xI}@*CAh}Go9#d`wMHRXn z2cF2}=y9aE&g2ENvrYhQXR`Gqh{I{fWG0bJ;+a%sQin+kCRwLpC!GPQ%jATD zUXYz{X?6RK5*!wq=ve{-7gdA7L$msqI;h1mdsUshUdC*Cm!KqbO353fdzfC^Q8)Rm1|*P?b_Uh&DTt}f?&|*_rS=>mu|2~dk<-K zAlQ5GjxBTGpzJ)XNk)uLR)FVDSXg}`}$M;C7A5qKx z&Lb%O9xIK%cs_eQLA(jkv=+I3Q$P9joWXpy%*9^rE^PCM%E-FJ1>=u>igxowQSfzw_0~zr<)fS zsnd1VE#9ol(cRYR)SDM?R(?ziY_rf-Wfz|xhsWd;Cd1>>FZ zJ5^jer%iS$UFT6cT?hVu2L6lw8It-s-QT(%I^F7bOq2gn7x`7c?=I;wilip}sL}`r zmCmjelNb=UgZ8S)IxkRTH8}w!F9f60oU~K99aQEu4eq@XPIWCp2H|1nVW*mBtfBoO zKijBuzs}vLi$*zS>sriMozN~i%~mxd1!S_$4%Dt{{=FKJt96@oSEFI=H3BK@Vr*1> zb-(Jq4?&garl5Irx*5lr6a_ZhO7`jTDxF_IymG}5?J)^rU0)`7x>34&x+2f!HPGvl zl;*9f74}I~aqUh<-evR>@a?z}@v6niTa%~6tL(NWe+f|wT|-^dobPpOQIFffBRBkO zW0Yo~QX_Ty(KeAfJ0w99wt>%5Q=`};QS}-LuEsgIsrbLOYjs5rTh()Neeu$SKN z1!9Mq)^|y9$QtCJa!Uf=*!&DLKX=-j*HVDZ*;uYKM?>z&OOlHb;;REyg;fz{8H$S^)!NB~HyrQ(iW~8W9{sliN@kvqa7nS`ZBDC(# z!z&m{wCQy3zTttvPcmp`7&MUvZTFLHRT~VNufzlgDL`a)B2VvktMUlg7I@vvX)fw zno}lP-@_dag|cmNFr4jO^8azRv@E5;=qx_YmQ*UZm{q1R`J7!|pePHM2GcTS`_j;m z@)0j9GdB1+D{q!2(oCcIayGYNb0ul128xQxFUzVZ50|>wa_z2EUM`E0m!VbAE>jKK zZqo~P{(|Pb{k46lA$)7jMy2a=tqsCkExK1Fjeic8c6C{1n|cI5u*RsAastJKR0>GW z7`5?oXX$8;U%26c$y3yqhFF8P@?$4WXDJH_!nJE|`X4rEuLNJ$Z^-d45sNY@+-H4` zlO{sD(<~5~O(<9yvCyA>Qf4l!WSjiJpjiu~vCRfznWkS>tSJ{S zX={#W>=T1!2U!ov3mBG#yuPsYeddF5)2(M(Qgc57MFlfiqq63}P zn)PK#3@Uh4JXXbFwc4Ou-x%N1+iW5BvoUD4pmJm{Yq7mSvz5h4^6DW<>|z(C&6)t)We9#Zr13UAG@3mM ztqS!)HnE7atN@h^50sO8{gkvdZnRiwv?j{UwvFwLl9L86yG=QsntjTsHG0~oY+jQ| z`xVWPJ?Vfl?#Dn70eMV)@$Y)dzk zlSjgosvDcob1}<-v^MA&??if-6rmj0ScBf9jzg93VsBc_wO!P_I1jr+m6EkRz-d{A z?5B?CfiA2(-R@WPY*P#JkHz1Q;!1c2px- z$=Fe!f|MmYzVxsd&+BvCG^-W;&i5Y^CMn}~`TE9M6>oiy2*e+!tlahUN0StNv%4Kp zP30l_)l6l=-dNcpH&nY-MHTJayM`QFB7-XigWO6Pxj&2=DmM=Ke2}$Kip?@_<^F!( zmJMO6ox82m^II9+Wh3)u(oD}=86C~c&)ZUOWwbIeD<^HQcq^l^iTS?ocaFC*(o3{y z^RC@9luY7@O>U^PJP;JlZVcL?t-o>Jkgv{gFxgkRclA-edfBoJCs=)X;8W_TxF7Ua zbO#e9xeK75GT@*qbrYGNlfN?i;1|?W2|6?ubl#zm57GBib{z_(zE&j~pu9U2R!%lh zsdYF4vdqK2AJPt1#vYCd>&xX`JoxAhL*m=r;{rNJCCl>Fa%qhXA(6V8!c8fiN~J?d z6t1EWQyw3r!%5UxMW$%Hi-sMUFWHQPbBx_Ek?Ty(Md`=)6ULeS$*NSS)H)dyJ)Y~O zY=ZK0m}1aeC=*OEJV5WBpo}{iOus7&PNvdC2z)ieWBbuS0A*(`R_sZpBFw;t@G#HrYVCj zbo#jB>V*{N8Avfq%C~8wzNJ*Y>8&JR4ELXDj!_hJOiE}DLEGC6(? zlZQ_Y@*E}TQa6Pz`zpU&@>P~x@}^lz@uf6n<0Us+OnS0Vq{~_KjneCKrnj|Q)_$v; zzr3HiDc@bmr}>JH?CTNed&X99$XI|?s**uoUCPfe@oP%?@h1MqQa<0r|5VEN zGVyCm`3@$2T`Aw##Q$8%*D&&}`OZgBJUsTF_nE3UjytJ&1O@=1c;9}6$ zd$y(ehNsv(${UoY*H_afWx>uV!%UqsfIlzLjMRB{i7+34R+>DZJ zNF*)7{QTf%L)uwXlh@hX{&Y9jBrLB~>_mM6sF4`)4 znyPp$<25@_iGA-ZsU-1>2l*E@e;-cf4Cc(D?Iu{?tpgWAyZiIR7_6rqiWd__*?y=j zKXKBILL`4l>3-LT0>mz7s$866PpL$aBF}*ueV8LFO3Hgo*fGV|9B8TZ!9fx`@O7@H z|6@YL-{=vQO`ejA;pq^$TdZjrF4#DK>q_xh8TPxa z&>GRli-N?@p5z6*$CILHwYcj^!M>bHS)VYSIo660FV4jx?G%Lm)Qf(nmg0yv>8WM0 zvk&dJgLHBOs!WT;rUukibeCzI-!&_bQw*`=bKK;eVr&p4i|8P#^M5fYh5_n+aq)&= z8p6-mP%2T=wPG(VjUqZ(JUtSxYiv=`Jtc8ND@BS$QPiAziN{eCWP11&M?{l7*2g0&~qDf|o6%{Br#Ny1v+a8Mp7;L^4H!F}np|@4q>oTXMfxR)Ge&8wt-e@)JL&kzMi7 zN>qn@###kssDx<7iNgt`^)09IlZ+}UkrtqRen=!g&+*o248eQCF(@g_YWv{ZuQ_l&p*pd7707vmip5TAY$h-O0^j&>9cB z)k))v6Q(@dIt`zL|KBPRRFxc1hkRTX`l=LW!jWkfqjO3&4xPq}6Ybv99nRnky1cA@ z*XIO8@o71CiUf0Cds_4ttimzA2&h8^|$`XPywpe-!)ea~(ta0O#p~XzIR(z9! zK_kTN6q+CQ|IA*4Jd+wA`h_*f#?A)k6E1aCbct_M$r-Z@Qzc1WYIH|SId6aV;3S-DP(Kfg=+@_iTa+vSk^NQ! zHM?5;Q3K(w5$|e{3{F!M!)J|1tx3t?`qreGSXJKCL|%46Q;Xsdbc0${yU@ zKDOc3E#taxk__K@;@{3vKK?`0CXw-Ack33PsbfoJ;Y-&Y>5N;Ke6^L>bWCLNhtw_V zHT@4+Sefb42j3T$V}TDaFHzZg??Q7axMSjS{oH$TP{li9j?ZJHqkk!YHpzWeiM-}l{qoZK&?N+UV%N99KT-K3J z+94T_%pzTnxqYV?p~teaQ>@ZcKJ6Ak>D19-50cI_$h*aubkyx`F+ZKAOZz2(Gk&aS zTZdXAk0o^|Kh!!8TnbJ}w#(4^NjU+y_f>(VE(X~i$reCx|AzOiW*U+;VdOgFK- zE``_}LU!WY+9ZoV>rx6G6`Fd~L|RN@VHmo4VLfWXN^{g+J$lw5BXv_iL?w|$vWZs9I?7FMbq!%RAa1I)@$07Ecp^w7H-~>>9VNY z1oNZu5s!-%`HI-xgeuS<;$9O96Std?XO&Gk{{N2&Wm8U~eAOx>p44hIrKVy*Q%baz zZ$gRtT0e2TDJ`PE#Gqz0hi(BRU}{;<&?I?$AUUE53{ZLCx?LhHy*7NYDoW6dz+_qc;cro|0g{=5`2g+k_ zEj!X)EQ&szC|<1VM3qCAmakUJK9W;U+~`C}VrM5x_x-P2m}-OUNh16`x_eS*LWdK> zJ5v?UcUETE@_SxtWp$S3N8_#uyZlT^r52xbL8UAcE4omqSko1wbG5kDg`z}kH}Vv6 zSE|9tU6Lh{)0G;~f8xik6bz%oT`3da7oqG6KekYb=iMkM*rE=Mw@qa$Ul!Jx_zbE< z*F@(Gs)k8;W(L(J8*w}Xe!Gc;OiJ~(NWLk@3kNnN8j(p|L`-)|5a_BEFw$bX(-ABr zFPU=^!C9Eto%!J}T4h1ht$0KhttQ!3tx|2}>8;Y&2H6eF-W(U)+=6izwR=(p&lP3C z8DB;i`;7RyC(W~7Si)p4aiSmGx9^3DSR{t@LKBwsB6qR27i#ODUgUUE+%l=|~HZ>6EvMB*gD2w!eDOh;t&^$cW=1@Z)i%CJR85vzUW3pzE z_$7zx`B+RSCQUufGS*bD=v~^4Eaw=b&9Y^h0*fNbA!1K&>eNh&swhok-l1SVvdF-6 zTCj}0_wSf<nCX7)uqi~<^$8mB6~$R13|AD^#y|KG}2uJyl3YZrUw(;W&=hl(!}>fou@ zHgWt90n}yOBTyd$Tu%fRU=n%#hTQFVlEw6Rwt%{!t0oVn_0ZfIN@vC9;p8EX45PN5 zjjgkin~22WIC@H^4jtDO^T@>E*cmhvTZYpr(_C#JL-DU8=rak@w9!~2jkCRhT8Q{D zG!^I1;xS~PR>Ed1rBh?kXDmff8`Gn$m^PMl)J|+2M&aWASj-{qiv!1Dvqs%T{X#0h z=F5CUS~Old;LGG>OtoI7CdEM6H3( zPePM+7y8d=uT36Gh*umT4iECxZKPXr_hO`~Oz?s$;EA>{`}0fcfd_o2xY}Y@PRtTrbQI3l`sU5>z;vEY`ifF~m-7~<>@v1Y6&n!& zRf+LU-jnhde-imPnjSksq}Xy7?p*e>#`iO4!~$`j*Cc zY~Prq*^q3T*#KXcqmM5&O2yT0$sHlVVjB828;ZZ@QPqz+Er!#163s6D{X3dMA2ks} zf1t3BYmitY_WXd|s3KnfK>yaVZtqPw9=I*FZs<)p5%Sm8<@d9Bg7G**zytEHKt)!&h{sfvKm8cq3E=lPJej0vc=?KGsoa9 z`m7;Oubozvli?!o64Tbu2CseP<@;HlRQ&0WlxatI#m!%-89f#WMbwv`h;NJNS>b=0 z{|x$dHeb1`uB0~Nb&rWbKVi+QN@lood5G2wpDLNvVaM--WhMr_QE7r+^L=z?Y3I)P zfapppPb$Wl#h~YR_hx9cW0gVQxpSe>uqPWbG3X2Z+8;H;#=V_w;3bEZObq&~bDYB< znamO<23>#ibCCHt1nMtX&BUM^WPY-k@1tcV2K|!RwXc|oBX zN$f^tCI)@44Hr(EA>W9YVKY_HYk1|wNoHcu^YPdWd6hClUZh~xp6!^RZVi|2nBfqY z)-L4XWtOg5pMD!oJF-(I2K{HLU%xZMvA=iy&kTRP zvZtaM&J5hQ-weOJ;Ca*xLwl;o3^&Idj)u?f?6Z3fqtk@T_iD&2FzB`2+e2)G0e7DM z2g7!lnPesgJ--NtPJf4F1x0F!W-Oc}w5=*`1p}xApwR2*4fvrF(f)Vo>S% zyA%jY^xkj#`U2e5A8NegI>0^s-?!UU1Gul}i!*=+diRwJUIRSTf0kQp1Mo;sZKI!w z%BRRTtR#htextNpkM;aA1d=WWO@%22%@Z+k2Ss#ws=ts~o83Rt^Y=`e8(4Bn%M_`9 zx?t}?6|bFmw-? zC==7k?a_>vWqC#;j41{$$&l#Xc;H2Y_RHQ;Cp$~}F(nl__zE24*+07+1&(2y+P?@l zt8zug?QS@7$>WVSdD&OR&OHcWE9aG9&iMKsvX4q+1ODm>#z~AD{pf)6r(Buw?y9R! z11AfYy||aGB9iu^qgG*!Y4pie8DF~i>8rAstBGtFODX0|zTb-+Q%y|J??>0~g}*eT zhv*0PWvQy0EUKQlzAF$GHQ0hbdjhV-`0?c`7%*~e#+5owJ6M)dXU?d`KJ-<+XtIxj z3e(x_RjnYdjXI3^!>Y0*bs?I98$|0`Z7|q?@g~<}`;b?`dw}aRZZ>!TM!MX9v2jJ? z3cz<+rNeHj{$VfERFc{d8hoAMuTqslSQ?j6KFTx{tq)U#I~y5{YbFbui1_^&cMV1J z{S;76*Hjch7t0CCePW^KuRo06fs}b_Mxy)gxEg6FuE3Rtbv6bPyDm~l%*TAa!8a-8 zd^HzM5By(p{_=8-sB+dVNNl-Ap-n#KoWF4~o3}+Y zW#&hSONS}QbtH?QPm&HH)=@%zgc`e!W|6soV?@Uzq%R!HqN87T41?9DjGNu*z}5d5 z;|E^d?*LC>{BV!f75FR04lVZ{238nrw*GMycpl>_Guzh&Uck8M(&L@L8ySD)u!-%9 z8S{4zz*`y586^CU;)UQg5r341xo&5fIlLWW-BIf3y30beTlgG9EA3&?(3Au&*IqIH z7&W4O;@~mdpAZtW$cM$N5(fcZ{h}YVmx%I5)O=yEJxA7?1l`a~HTO<9Hm{UZ9OOzFr${PPo-<^Oajj^r&Y3#=F!!Y1) zUGDP&QKR_CC2S+8k+^gj?*|(fJ71w&R6UL-$i?3`@(`>fD!gRc8OCwK&SuKEs9K8rsL&)o5c4f7Dag2P3uRJdH87CW5+r zjhgrta(No|cy^qN|LKL_o}&1liR#z!9%C}A%$v5)Mb>rlcAdhaytFO*VD+V#aGeGf zPG^z1NoFuMH_2Cw%}p|sapD0j*Y_;O=JSBUIJN$59CYNb8Mlj#vX#?!7C_iu9< z=ROT}fczWAhp*M+wf|ej(^Cr<@u6WJGxw@w?+2dG`26vSI3URj7*DufUkCgh<3h#b z7VtvGogd}%PIj5mrrxDXz{?pAcvjy7c!kkEE`j^kO2*gE8zEGF1ElwF?R7ig>CEWkMW?tHa`MBz&N$n3~sf9j4u{WAI)R+Ff%vzujIYK5yqQB zt8pzHWn8OgYbW4ij7_I9mHt@2nf$5SahBPR{Ed%-Cm09+wL69T_b4U9KGJe8ed7ktZuq^BA496t^YvKa9<1z<(K=r^mO9 z_id}j9Yu}H9DUB3SAPN9GhSyXax5_v$_~u@aPJ`x6&J>Hg#jl~*@JQMtnT-KJsD42 zy0IE?5My&ig)%l*R6Jv2Md1v|ICbhzd##UB7^*tUio~=O5+$T`uD>oBb*P_htO#LA@y8 zevHqBE#Mx|pK;weKP3VWVBGLR_c-8zjEk$SMZAUbAZBX5OvEB54`%$yit9W|^BH%} ztjdiwgz-jA0Qd6(#vN*I;VwLsapJ~9-1UYr9=)q6_p0HH%@s9*vALo~GB#J#D8@6p za7`KH(ae}@c?@H7ON?b~Zi#V>@4uSDB`ajCfAoy6HO4a@dCfBxcmiXaxkGsXe=63N zP|b*m5b^5FPyH81|JZ9pWvlZ6Ptw@x zTBH6?%vMX8=XXYCemV1t_9mS-^DCKui?5f={A%Xw#-*#x{Ey84wd(XaGryMkwuNWT zqQh&{_{m$$)e-388e6gX9@TeU$7*v~eiqL6aW45q)OmqBv7GyOL-nf|b{~hTB9mwx zi`E-)8-16=@wdyaUpBzcM{cz~zmUycW+Uffx>c2n83*j!!Bgob#^$B-Hxc!K!Ygcs z2*2DrylzpDL1sqpG5LLUBPy%H&88|0V?B8NY;=LMXoOE9W1b+k-;Ivl7kr+C zxw$m%ayeYG$l+oyrKN2Tm?vuXyx;a&N z(Yj&b@g{qmd5r2i`yAE!K>Yn25j`~3ZsH5_q(_XSU7uPwdnO8AP#e$Z5LvuH zmtTk%FR4cSNo~7-wD+q_sf7(ed5d!V-(v3H6e7C3qzd8xf7?4|+aUjKoj3mZ5$~e; zD+(6P|3zsAy~M#h;cv40NR-`PQNo;^lC8<85Jo;9%Us-hMH&llCt>*ijq*SKJR@Z8 zJF*p;SCnkSjz#Bx2(y!nA5@m=X1*fV@a^SlV_P|Xi_uw3gYtfvmcXWVTCvL#}m3 zWBX{?FGrQ*$CTqol;cN=&)y)cSC%>9mghgR^*PgYRI>HY^X0~3(p##=YG*gg-|a(j znib>zqpt2&3O5^(@t&&t?DMRM7kgH!7vjwuq`Cec{b$fyva|O1Lacd@Z{fCoMDg!? zNC|0at#zIX1$}Nav9EPB(Yl;f4)?KKAR%=cvP+ib+X zlmFvE#N*G=%o!tDSGi`p7(-HWVCq*h-fA0VCq!ANgSs~U7?H`h2mVkQzKJ=^nSCNj z9v`Ik_BFrMR!2&cuD2w43U}^#KO%*7^#qCQl2lEs#UDiz_CVH!3Br435w4ah^8Ds2 zrsI$5;I}@7_{sW*KJ67^Rdt-gvg3yH_|UqAY3sPQb=0;UGwvFP^@Ke%vXNq3jN*6Q z_MZ44{>-MdB_;N?AvzJ1J z-cGW$=hry~xtW+|CxwQ$C>Kh*a(q+K1!kUY%86Tv(RNa>xM(K@Qlc>{vBN>KE&VGF z|Fcjgl|^ggVEPFJ-br(a#&nKh+DD6W&T&gdJ4lH(N&L$5gVrVzC)P5Sa>YUi{NyXx zL2|HON2-}~X$1`~9m^a{z-iWk9f1Sw2i5_fQGT!#cOCF1xQ2xw$+3JcH7&{_dOJ!U zR7;F-lqykevD{H=EM_`M?&7VZR6*=BBkyqjtBBa5q;p3z(y#UNC)H$89g|4(c9LR6 zwzCv2esPj~#5_i~8J%E+t9BoJS()UF;aS}Ug2@nwJVsj>En)P8(M3j4E}7VHs}v^waglsQFkY#PO0Ga(GU@?@?<$dBIDV`s`B7^z%LyIm zgsap7Us#snFwxCTN~E?Hf}=?8$ls^%k-fdCBK7W);|E!X4>Eh_Q!;Ibs&zhX z{Itb*+P5$}@j=?TOj_@Z>PpI4jau90=NA>VlYijf?BmZx=uhlTIjpYewUXN9+i)Da(w5B8V5i`_k?5hT`lN&Q7lZz)o`EQwhj z*dt_mOZ}zBY7=wBTN*D4JuoYE@j(R|QQ-%)q!bk&@R2^3#6W*3%&sJ&k3s&N^9V8F zDHiyPGK{}$(hBx8wHT&;MANud!^Fw}G{u)Dd^JG&i>8~J<*z{LGki{VN+X4cDH=3f znk>19%OPmnEnxAv2vk+XNe!A!D?{)~EQ*2cC&1!64Qzv4VLMfp{4sSHTXdH!jlzeV zLxYfRV31^M!*_QgHdsm$D}yk7t_?=-8OS;O2^JqKXN4fZkYK3p1*4~QVzfI5=xZP; z8sB(2!{8)~qe38d4gng%rVSarWzz{Ei05cXspn#_lAgp9N5uLd1Qk);l#MnNifU#> z$51FzO^UCe5P6|+wU15enoVAZViR>S48t%n3`^roF*r<$c01Lh-wV9qF|Hf(ES6QF z*+!K(!e)vIzYmjoh{fS({fXgHsI=c)lD*;hdC=FQcLYAD7$<&+z>vMBMGlW6q?$BW zRMg@jL~pHBOZvu!f3{RX9MwwR_(bx$R!WoRmC0O1i%87b^G(@}jzo2>SBq25XsnH3 zXoENvDbZkZG#8Q*4{j&m1> VFgF%19*VG7H0UGIJyxppe*n%60c!vN delta 22694 zcmaic2V9iL^Y_gjz4vkt<=`kHND~B6@36PCpvEMKAP6Xmh}cU+lW4HS_NZ&@4SNkL z_TI(bjj_do1$!*9y)(}pa!2z1{>jIAzEgH~p6$EO9=k7F{CeKPu5HuS?S3bag#%755W^QH`J~Ci) z#EE8Mg?36AW4o0y89J_k|HANJ2)nA30VH-DkSSv;{m^y?k!M7l{n0+aU#Bj}$?G9w zjs4MaF_Be7Y*c8`he&V$CKwWc$SDxX!9Zls5vdo1qyv$tRH8$X$Zcf(2av_tLxki5~rY#F-~B=$6KZ)P8i8TpF4&7+~A_`R`cHBZ0mN zF*4><2TP$Z5@cg3gdP}bpRE4<(|csG-|Aq3`DB~eJW__awaf3EUck1XSYohR*ll9W zQPU>9dqH1j6DMO>Q0=t&EwfodoJ=maL|wDK1zG9cd$Qi7HA6wuA^8RDw>W*$M!9{v z_htu?WzXU;Jj-|_?(xV56KNwZwT^?e;&p3JNEF{#2eGRSL?4@|8oM=U7nq1%1 zOw2bcw|^E!Lyw$nC5vx_$*(pN2ivstYTFp``lguTdQ*%7J4IICY&F(~AL}Mwx6u@i zXok9pMCKA%Lu4nBG9uTBJR$Oth)r`OUPQu()F;xiIp$#93W>56vcW{ciNq3VN{SDy zus&P2Ml=rz2AnrAH<#^ejg?^iiDZH(GF!D38fPGnaC_63rVqx$hmeH!$Xq!v_}$-1Ori~41dPfS6wE(K%Rog!-NU2X2BU`Wsn z1sA%B-R%7eo24V(oPpBjnTWD8F@t3|7O|5=-eh8W$1Fs3u+_7+M6!t;L}Wo0YRiaR zC&IE(`#p{vYz!g5@rr%uf&Oat#FufD^-Ld<6_L|7qTRp&`2z=p_Z%X(lTC9F0=oA^ z>k=ZLd!ie84kqcEgKWPXWPczsRn$26+msSKMC5pm*vBEv^*LH$Ba~V-mX6R1RV~GJ z4$&P{xd{8`qLYbz5KSfWtPiqwc}QyIVQ6g-VLgY3v)Lq@l8x!CP|VH^LDR=W#7mAbab-hg=Irw@nJIG_fho*n-TUTc=k#D%#MwxNmYb6i-m8D# zJeKqW%1mVW=>vL}Gmk`-B9uplQ#e-SY1RcZz9S#krfkBA*WfAy++7_C!sK& z$Z#SPh#WwIiAP3YfGyg!Y05545~sSj7dD%W%CS?B@F|$|_*6uH5P40+V;YhOBF(0u zb_}6ugccE6Hw`1*PvjD@e-V01S~C$@8zP<}vNedriP*hBRu})J^W zr=X=tbW}`SOnmJ+F>&FMGLxt}@sR{r=nQmfHxq-mkacNTD><@O-LC9AKH3iLl~r8wI?f~{OBo^bbO zD^`h*+*8eC*P{Bsda<2{yVv>kG82=?@VYW2kx{Yqh?TK(8_*(7{Ly1I+xWW};Tg^L zZxXwEMvEn$DeTN<(NW=V6T1~{UTwve=eSMOC;}Ygw_%0{w_(e>wH<@lv_l-AP_jom z#F>hoUVV4cJMNO1;RqEKC1Y21Azwk{?JiLvG-S5B#jZk4R%@>~PH4gw>=RE5by@yF z(aI~Ih=rqnI%Js95UdSF`*m#&PZ#3hp06WO5vd&j}>$h%6!U z50N%yBJ&O`oL7d}CoxSwB4dd4KZU3rkv6B1{B{OqYlv(nvWv(eBIk(QB=YhM z+KFe8oF`I#7G+=31Raq;r%9`+e~nHFdGPCe7}I%gI1&%rM2cOPB2 zeHFJWXxeXJdTymwdtX#4J=oy;VuI2)Vlmm;$c!vblFVGzFfUWe<=uUJk)Q`yshS63 zk+OY2#|Icr<^z-tAv7Hc28PQ6Gg^+p$Ed0x=)sf_ylnZk)NNS>eUl5)IY*Jw1T3j5YzqZn-8f#_{i%;%4K#n_7)ap8j zd^&B}eSh5}pYLQcJDg+3tJSIM#oN_EBh>hxRls~PJYFcg0y47!1tb|uL>*0nr8-(& z+(Z)VX@PpNl)wxVj2&daINjYsnrO_{DbYkWU#(uJ&Xa80s#mG6snxUZ4;!!kT|Jw! z6feX(B;}jR%)$z4;$v(bB7uGVuhK^ZlSoNm3IdDRJZkMfe*8CQ<)T~`mj%tiA??b%q{Am0L)9>cG9ZwPC*W) zvPpH2j8&Tm-WabrKFBW`I1Wc86149siXw@;t+ zyiD;-zc~(r`xf-ZZCR6?f~@WX`W6f=nNV=qjqQC}k~uEQ9VUslmc_tiF=cg_S+?Sd zRxt&kLY1!YSJ_(+4%U{d65-Kf?GtS+tzxQH5ujCdJJV6NS*w`FZ}$R$x5IhKJftk! zR8}At?G`0^YZbE$&3-dvW{XW0)puc9#T)}^NRd`CSDe16w)k|B2PU6npi?X`WEP4a z7uAGCV(?;B=wbuK6Rql+WBT#UA=+}Sf>$XvW!R(OH!*dIH!Kmw#a&D+w2GzTm&G3T zisC9Wt(&#zxumv}LEO5Ov-K%QEHO;Eta{2YF?^}H*nP31(~K&W&cjUcyQSW+T!dm@ zUEWiQJ(!!7s4fnLfnuknez1acJ``6~TCHM*0VA2GI<7PjQIV|@*A@ph>L8chyQdhh zRdxM!z}}5mTlc4%`)Zxo&TNPB=UT=5szjSm@>;8yY#`~;gvn%LMX}0`JS6N@s5W9n zE7tIh0=Rgm4%_laGRw9nNmZh)86GHDE1B5nO*~PuPLf3FBxTv|e%cUSEP)fT>8PTf zSt*iP78?4gR^M?yu2o(4zNOim?au8-LqJ_?RA30}T)IEoj4f}^jk6aeffSQwghSKk zCR#r&ODxyA$tAZ3dqjXt=Eh1MFE;^LC_Z1|3X4Uvl~LF{;#UUSmTMK`w5n0C=*VWp zCUN3wUvbJxguc0*Ote}RnTDRW8CV%N z&+Ud9gQC?cj5Iq8&5SfV#nY=i#Z#-YV5%6iIzXwIXJ~3vR%ICq#eOM#Zr=xoL2Fsn zJ7SRYs6Tp&g@?@T6$1>NEEVsr4zyz(*zNK&S|_uu*^Y{XqWc;R92CD@lLm*x(ly=T zuqdnzfTJaeYt;ZJ#KLv+;FRdS-q-u|)@*C^er8hvOEon?GK9FT*+ ztu43!R$$e8-YeG%40vCEJg@QCVe5>`5d$qYYe6oq+~pf(N^(_9iyEQH@*)%(nHAk5 zH#(C}yEi`HjEq>cqZ62lf9|*>QFrmg&Xax)M#;2-V>Mnb{Hx+fMC;^#e0 zKoA@6o#?Qp>XkQT+bPzFH}`(|FJYwUv)|RVhEZIbGW_xNLc|vPH~eRklK2Ci05^ZX z9uz?o{SJi)2DxF`S7nXmQj&FOHCVRA46bXnLOap(h!UELqmR3Ml_iPa>SfO2gd?u) znxd_0=C1Ew-AnBzNX&G`d#NpS%=}*SEbpZzmaF1t z-+ZJk|2Z3nb)l*F?1+~ixzVZyCe5yNsN z>y9=TZI9VP3ZF6#+{Nf);~+!adF%(I3CDfDhTTg{Kkf@TMz4}9&OffKCd(7AANNPu zm*cKq)8>obCu%5j=tURzE4!_Y__TkdM`u=ETp$-Ji>d&4&o$tuOKDXp9RPg8YVgtJ z;aVvjgq}3X$=}J!wN56y-&$<-6qs{~TiG0D@&jtI_bN*+o;nNI$(Emqfsx|%GhRW3 zR4i3Po0~^!i=mitS_ZN$xNc{0q6QoBj%}1JjnY)ZL&Ym(G zFFIcN{=XF?uhg;r6;lji1tuNj_r$YzoW*lj{M;uSdD)cVSni*%6{d(*SN&mXNv*46 z!BRw%iWgd8y14UNS7C-x0&PT4*D3aEpHQO7V$2`@Fh%_Kk9cQew>TUMGsVS!qyraC zuBZKnc9uBk`e8^B8~j-Sv&9X6o`tzs9Ihh2;R*A^jW?WekUMmv4$K!n-e`@*+2Upg zq;qb1HCSL2&!&vs*lZV8lkGy;qH408C|fMPz8O$x(Em1NY(ue2HPfvqTT)F{in68E zWLr??R!z1UWyRHGn^3mwtIU#?dYdvzgyrJGTmFSBP=S?Xkvi9n;iN9CtmG%@_*Iqs zC>_7Lk}uHlYbyCn9ly4c@2un3Rq`!#{Q62hLE_sB8!821I)jasypN9my^?p(@gQihb@xI&MSziUL+_^8zOfoHDkH z>+URuabnV6flLlOeF?aT6aQ)kdrHp#We0G$ zZ=nqht+&P7nC`at<)JH5*GE0zZpjaid>K3_nfD|Me9Mh|Y4Ode2=)RCm>3Cp96nO z{Q38G`1^h}++LiaS4kgm)#|J|zPDgO;AyBc6Q@u=&|WRr^3I z8O?7WNi25#Vl6iQqJZ{d>X!hUI$zb&T<<29eX)iwWLWazixPBM@fd*Jdg#i)-|icF z6V?7-B5L3q{Y`0827#tuOU#u=*nq2bgyzrD{%^3N-Pp88F5q6e!W?=6sJNpgH2*qe z*W~GzpoHMkA1z@i`|2ZteE6_PDQOhPq*0|aY+x4H8%%?#Hn>=>ZwFyGr{vf{h2gA9 zdy%y~+a9`^3JJK*=11)zNDrUeLno6Id0pXtEvRo_EhG5k^e^)UfjnSa`ELSIKx$F%d=cS18qx-UEr`8N^=Fk^*Em| zz%{oUM%ff;Lq=uW348b?FX;b2bkV$R7})a8-tZ2VmbUYO{(#Q|zECcQ8>MShFbrT< zX>cHZcVR*T?<;~k?-B$}p*vp`1YWv_Tj_-$FbBxw*Mp%ktl-KT5bTtNbyD@-Sd$|E zz6N;vEUyyM0&98|i#D83uK}9yY@@VUsSZMqY7$nA14vOcuDXSu974duHOI(8Hv{+L z;UTE(O@aBDWGjW<{D%;zWzrjMX$@@V-MS`1Cp>bMa6ypu8 znS#HkV}x~)kOrfH#f4(^aQD^0dS1hE$&rMeEHVyU z^}|Z@IA{Yi`HVQ2Bc?C&uo=Af^!sF%;USGgQh+Psp{dh~sw&=^-J)D8%;R6;aR{7G zh3tu*6Y4^QtC7_dv|5N|!=Vrx*G>Uj(9r~NfQ6LO9UF+1(<0-d!=07B?O2)6CX27C z3!!eQlhDy(V@t(lDm=jiqrA-R5+KwZZI=8yGd?T<{5VcVxef-gZOZn;;%XlcK3uGa z%i}eCMLjIKHN31IzS3G=Q4a*r=W0k@a@`}!~iO!=ewxZpPBmJOgLB=DF9 z(4f$ihAGvZx$={n@7(@!B-U*= zN&Gc++s3UvVirbbJyPtp9?>P&Wz9b~0Jj>t>;jipgd4}CT|cKrGDcLu^w#y&FbVt8 z2{pd!c3zGTwuA99HOfph;L46>a6yAiM-9#|yLg@k`~5CHTLa$CyNv2&6E2EF_;C%W z*={E7sd;!J#KRumBM~C;F)I-YU>~<`2;W)k$D~uV!am-+Ar|L8KE5IR$__E!I*0}H z#75XickyYBpupES4{b|g?4^p|TxnvLYGd)OI!7ZCWOSTAfgG*i$XysOIeVuJ;QD7=8qDG_O zb(=x774pTYzhK=M&RGpPZwdwfPHbY7xSr8Gm%{fp#reviIgaY4JfS(%#p!B5b65t2 zOR9R^ri?&r?1mFfMgR&7TXlv?RzPF+MWcGj!g1|VHHm|8xtfF(K+?36KYl&mi z6~4D6&PB$vRZ+Td6-5ju8Gdiit+F2CbnL+~f;egFD=k9((~}eyTMrg}-=zEzE$srIu|V0N@@EZwomv zmCtGm)8PSk7zt|LyB+-GT5jyu&87%XLU~jO`0};BU{xB{9z4Jxg$)90 zgVOawwP560!2x*sKiH{jbp=P>qzlAi@?l+|w$mpg+brR;ZoZYLE7sxK!kfSE0%`0E z_#bZBt8P?08}(1poWQUDwWdCd@XTfs}$HZ}FO5NuS!vK5K z#=%+e#jvVsQY$FsUl(=XF~N^3dqFgJ=mnN0sY?ZaV(YQg;oPSe__GWJ?}ksF*bAKO zhMgIz(rj0km!-zzVw(H)f+&8gHw3#JDmNY(vsVg%RN5X)2$G(1VYtrTz(;4j4_{u9 z3+4HZr6S3^A@j51j7Mr@Lu-YLHM~xNJOOk6-aeJ_3D8Ad1A-LB2Fce#xGz@Eb=x4AmeK8CM zGo5b855V<0XvMpZgz?atmyZN3XnAZQBtjGZTOs)4?ofKP<2wsM4ecomKkhXOyM0n= zt5LWD!=65HGz`GUqtUp}OW~Lwxf+i9#2pco_VXDVn)V zh75dQ26b#ragMJ%gB``UPX=F~LUd5=Q1{+fn;-f5)!2UuOWmj70Oo3Z(x!c)+v}!J zg*vXqw4|vznXOWV`1_-(T>6mry!t_(fr}d4cN$o`8Xx)@>3dAWCGQ>%A_Vdk)36~( zIDp@phAUzT2f2+ks(+k_bRl9I$Q+Kh~EkUJaak@|>jahE|nF!8K z2AXJw>)>(vK`VYb9Eb7z%L)vl#tfM1GQlWEY5O{{^yCbf#^6`pZ59Olrv>jj4}{W^ zSH*D$Wxt=ay<6ysNRGkIR56{hlT zOR$Yh<};VTKln~kTI1TJw9~4kwRnwbMM~>tVv0vv{Qgp0T)J>&F|>r~yjL-_f*BM~ zBJZ*sr@$>s!JgM$jFVogWpD;K7nb7+V-`JvN;fQrwgA7CV(mPFub&|1$;Cg9`?0z5 zX(wF13Kz)51;>4T=3+Si-`2l~_gf9h|828G>LLHzrkFqZKm9D%^~V1h&r0574URZ- z`S>+(?(0EcspK8D@Ud$lz-gyZ`KH?7{$uA_*zB~gx_m#$BTGxxL7EvZOr1AFYk17l zHbXCX!jEr;mxUh`AGDhFCX?-D*W;Seq)0@o8NK>#Ej`@3%txh%FT}LEXxE(Vh-fvE zQU{&pxTy6~`sjmpGzdwfj8;Qm`1Me-Bb63E4i!p<8DvOAt0{E*rc4i8^sqKTFIl7{ zqSf4(VXZ{T7?Kdts&nx%+-Sv>tV&&{~hB@O0_Aj^p?A(v_PM@1xUBP&PfdpEOs@pdx zmY~Oj7a!3OZ#u~YB3cc7IY&uHl5{N1+y=jxS*_O41qNLI9N>TN0d3+DP4hs<1IQoK zJWPHWg5bC&yZ2fr1Z7e)LU2-(H=xWO!3B-YiPf~Nyr_wsU-BBkRX%zzC=0J4G?mP8 zEm2-42ia>H`dW$L4-M_75nR`da4Wck;7?7C&5$qzH#8q!9wBg3^US8bOmPjj-x~TL z8%yA)ZW>t!CON!?Hn%l#k)Prb+|jH#lSkk$O=oQ;fwa4tq?ZrwAiAfaTOkPUYpy-Y zgL17*L$_B@@IXT+*$B!t$6D+mhYvMx?stks@JK^vWC$K>>{rbF2f-7~n4D5NJ*v<^ z$Do&d^a*fPme-+Izg78OPc`&C1SMUxir^xx;u-I^3s*Qt_JMtu=bFoD4JeNn8oJt~ zxP{Ym<%Vr5%Ix&Hyyj8+amxLhci0a#;0+)B z67!t2AMD_*F8>XL-$}S8#g0DSS4Q)XE}EBGMWhss0?`Lt{3$;2kNY9XR)*bB^QL5{ z3(kRNJox~q3e8bu6jhw5BoRoVk4>;3OfxyAvm{JMTZpX))0q}xYr=Gvh1iBL^-ILI zgz4l8u^r(aDO<693igCYXd<6@BjZ5~omL_CBuwX2h`k8^(Wo7UD0ma5yFwVQuCN3j z;4dn0LTh&rj~MD61UHY}v7c{Aq3cf9^mQVb@(Bl_F;nX79mf83=zNtIKfM==L+Irt zdf{P&+zugXPbdMAlikxve^;dm#9*X4NE}ffN>K+j=?J&4`T`k*m5S_(I$%CGl zS0#zp*~Xl|wa*hR>XHRrw?bTx@UuT^V;>Ug6R!2$grij{8|ZWCeFPh;nh!eyUWFPm zdt2X&N+ppnUDT>d(hx;OcwsBTxkcYATGhlJfoGDLrfEMdc0r*L+55cpK7hC};nw~7 zVCNT_5SAu6dV9S7RoMy0Ybr8zqf1;<)ZiTt51FhIqNOym(zd86@O{_7&z`Kb(mYDi z7QE|G?1fGF$fMv=n{!^outZBE8tWAz(bFw-1ZoFI2dQs8u-np z;8Wwje0{*HE!BK!`S4>>RCE9Bstxcbx52mNf4QQIF?v_+F=`E6ebMtBh;I@%>P5Az zIs!j+3wI|?x%N0H3dyTx_4sb}Xta*&gdA2})kqdchpt#1q^N9yoe3wssdE|ST?hw6 z@Cw9TB^x}RMVv~Q&TSE=5vGr`k{8`MZe{m{Z}|P=kZRkFY;==@kj|4%K$>lL66pqG zA(QVq0fClTD56Tt=8sQ6W7{5NaUyRkPI>rUtzH@U1=D34g;KR`&g7F?ff&ttwxpJX zs#->lu4VKfy;kT=RzdAw9M)U)A^y4Nvr4`%@z&3})Yj|!5kJ!X*BCwDpZJ!;jvUhS z1BrKAV!2Px59Zbp8 zKj=*5|1;qyPTd|L{)KSG0To_r6ebb2Xm{{9;%S5xJO9K%NcfF#?J3_hKs<+V$+c&D z5pO0u*M@BjFXm#b!V|)O-Wh`HDd8Dm<-^B8 zh+h!yv-T9O}{RN1(eMKUD_^-M8BGmVLOQM^(-=Cq9*nQ8<1Fhea?AMoPEfLH3 zoQt5c1zc!rYL<15K@sC8E<&Ow{w||(Fc(Y+>m8f&fJ;yx%y{}GXd7itnie@xxL^`+ z+b`4H-oBNp){^kRrJ^5VD}&V5{1&CQ;ghc5U5doZps=+yP}}hym!W>TJ&AlKSkQdx zK-gh;2)(l-;b*_zp*hcq@ao++2|E-1;XyV<;X>F(o=kEN!oN6QrieTV>qik^)fK^rsx{j`H)Ee*1l}!Ydi>keFYi^DN&At#(n&mBc553(W@3#RuZZjG?aYr zHSo75b=4f;$EW;(W2urm{sGP|N#1?q^{JX;mC#7#&tF{oYQQb7;rECD?spBFW}rbZ zLA>uZ2n`B0jDr}>ihAFg352TR2-d}+6INzZLzhi3#o=LZtPA0fZ{yq|>6`7Xn_z;IQE-DJH*k1N4{4)L|mJ2?*#|w zn`jKTxsF{smJhlP>49}f@NYJcY4WIB`tdrhD4-d)zJVVV zo0rzV0r#M8KQieuv>8-RfRc7SD2)(s?@=B2gsS*({V$85x=PU*@F};!)ZRFwVY-6Wdq{aQR8=jH;kv5Rd+@!3Cx#>GO`2uAJVh`5 zOU0kmD1PI$s~X+<}KaLx-~3zT!h z$8R>K<-sh%zs40VqJ6|~#5}5yk9ct{|*$BP$tK-i1kpt4MaQZ3hL~ zt|t6xTNhKrYY5x8p2c;uu$HiXpR|s!t`Km(U2R44>Uxst_e&cH>-S3=3G4SuzZ2H) zmr4lh_DhArCSpeD_Dh=yzYK4^51noytlvA864vjXwi4FwowgCaQ*S=4nfDS-ZeY6~ z@d3im3wtRMA0(WAcl%SshY81JPNG^nLikGIufwU!9wX+?;T5!cI8J!0Z!DF<3BvWe zCs`pbBdpt~$uuW>Poe8{CrM^HbQ|psPZ9RMyT1-K&QnEesAHSbbLWKAnVLCV}FV?(zJ%V2AJc+{gt-Xl& z0%83maffg_w?Jy=_X%$)*-4Q+B%B$21h<*OBf|7sCd7{s;~u8>jN8aOCxv3yDryWb z36J}=`&q=V2rqhD2lrjV--MgT{7s|Y8^WsPFYri3cuQEnJA6l2KT3Wid}voJH57&? zKAP;+Z|@>DBfMT)Vp*;&6wHZP@Th{iiZ$VxT#MUM!JcsG)NYRuI}rY9>6Tc;0%3hY z`4H9@6#kG=Ur<`17U8(@Yw1)Vobb6b53z292*Lv!G!YO-5gt`&{SCEAO_S;VfijMF?&hh+M_E1hm>hUW)gMR`5Kq0@H1L)?h)*_dP+ewq

rmqI#@qn7avspu#URhL;$*^fN{6@$VLH64YDry5v}fFFnb#9V7n6z*)*4itW3g#3(9DnmqmEQcDG=}*@T}zX&i{S2jPp# zxzqyi7p5{zqZw->5a$qXcDY+k#JvfZ#;(J73x!-_>ir#obDhwK@VCovQ7_FSoSYUz zmDQK<7KI13^L)ac>+PT>+>da?mSfcP@S-PH(!N&Is`?Yw7t{d4`hprrSYJ?s2v6xk zC8ZSx6QeKXA%yicF_f^rCWaAy{I-bRY&c=f)0cG0F@o^Wn~oufe;{l!b0Br#k^JT( zsOL}L(rA*Vr)FH)p9dvWHAxrBrH#Bh>2X&?R$)7?#pgOQi?{8HjSWkZObUq*bRnu&5fzk>L?E6-ij^Q(yOSa|*dHh6_x z`$SXY#t>}c3RC|02{f@?O=|tS;7#KS+@GxF&nv){&#C}BlXa-pZM$|M3+pA7{Q~b} z*Q(B9Hjq$dva!-M?3c?~)J}dU*Shmop@guPo1p+_vb-&6o6AVJlgUVaq=2tt!`0+xU&AxP;omKR?A26rF9QZo6DM zUTH+q>ZdXL9nFs5@%Ro@VI;bBJ29Hf)6w<N z0yXQ?lv-aGXSn)r+;6RZ0c||bl3YLcog=K@Af2ZinwwlekuJ!-FVW{k$-n*FUm|gU zu6z;Wj4l~ubeVs7g&9422_5Li*IzTbT9uJZosZF7<7uz(V>@0Adxe*_uInOilwF(V ztv?MM-XMoR+ukIRzF2PYDX$?FZtEhO5UZ6{MRrFLx^!A{{U3Dnmw}_ZR0MNf?~|za zjv^Z79}wQ^-u)=|dx>Re`UdY&m!nMg`VHRT>pzqNbNu8Kfs2=3ipm0bL}C{{_6<1M zRv2XRlo!8&4*t(jWbmC{cwUWvA>EYl=IuY?MZbD)!71whO7XIqhgW>$TZr}hKa=sc zZ^4^SAY%6p%pCuffLpx9Ye8xMtxKhJcxA{@7wO7(VEZ2)^4{Y8Ss%JsB)!i+X!U=V zz&oh~{CVs55dANg@A;s2_!WBRdvNmKUhT!VRpU$bMQQsFZoiiDp*n(qgl8X%KVrvD`wZsp=UWYnHvU1s&;;L&pZbUe5pK#n zLT*1zk*R71n8JUU8AfEu`_YSp12gCAKjZ!Usa*XDa4r+9xt}RsLQ7-J)cufSD1Ik2 z`~w0~kK*&F;3+@J%;iz-)@Q4m@vzT$tUzA)voBy~XY7OzL#-E02r4={!RuMoN}$G! zCae~9AIBNfn3Jz@>T1=gVs!nmi5ER9DW#KVXMSbH0`_Yoo$Y z?B-K}MSI3gp7cr8JS#lVI4P=cqS~fOY>c;R@3&#cQO#>He5Wz^N04;ldJ|Q3zlzVG znBT-dd4^T$C`Y^RZ-QT-^r{?EmCA9LnfMl0C%a9U1$N~;6HG;2ng1zg z=H???Or%Dqb7pFSnKrcTXsPNrV&qK{k2GPSJi?TDnSbtj@U&jy1xl$Ix$L$}*PzU> z>G@HY@wZf}l9#^6TeMU8Let9p+M6+3eM{uIruZHU&7}9(fEL&^0}UGOQ`DsQ!ab{@ z>jBmH{Azq|HGWVvzMvYP$CJ%jC`ROG#-hw4p65QMc=M=5N##>vjs-TAuh9!!EOd9@ z@mgY{HB;(-*Nh(^iSy$57TBZcGmchhRV|;^e5VETg^v7*1@q?PESQsDQZ@ONeWMIhc>x3OW)I3+4=7@kMc-P>9= z%*F3L{#8L-GSsL0780GVne%f!5;f3?_$(V1!hLO+J-4@GPW%q0;@^B_-EEl*UatZ> zrsP_}4SBjP=CIF(`SDT|@Hd2>5DK+LORau`A=&}jvJ5ec1&C0~AytvL;p*{C;WTEm?2($2u^9zj%4GmUvW<3Q9gz~@}K8ToY;5p zE#K$FRPded@xAVmtb25k9;JJoSWjTr7@zNi6LSq0mdl#Rb?;0Dwr!2>9D=P?qbW7 zirCeQje%!;ufTlxHZSJN=Xo<5ZsUh-;t8>_-sni_jVQ;P+43?06`hDZ<%M=B3g*m< zkj38tGz`XWxWk*d<6TH>IKKR)Hyh?6btzhie*NPkf)5|%gALx4_wix1`Bfhr7?%2C zZM*m)nyN(9j?h*gMB@o{CfOlGc){|PFRRCM$h^K1Rrp21j}Jz~@JhlW%Jp|8b7lA; zUt-FU;YXC%EW>SZ!1nfIZVaynNV-mbXcza9ZknH@~vdHyVjck{<#cOv21c&k$q9VO8u9sY=z*Y(HW1x2b@1{|co{rDyoMmSA{ zwf(n>Eruz4Rsf5GANZL77DDq&5IR-{vU)I$r_e*>vjSOty!6;Ah{c-Ey7-M!E6gCX zc>M7j%Ie{5M=9$yL0CE)cv2|V{R6~oqnzLNMMf2jiuF20Dq^-yub54WwK~PcU>rz~ z=&)-I=F1N2jXEQPo3_(6F?LS4OlNeN@F^X352=PP>g;EsoL$g6x*Ea)aQh@V@~w&Z hx-M}h;oCa-D#CXNCqg-Q2*t-kveLjKJ~fop`hTn9r?3D3 From f34a0a5a230dea4a119afebfacb752d93b855f15 Mon Sep 17 00:00:00 2001 From: Rafi Date: Mon, 1 Jun 2026 16:20:26 +0100 Subject: [PATCH 035/251] Remove the old hxcpp compile cache + bump Haxe from 4.3.6 to 4.3.7 --- .github/workflows/main.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 60e98fe5be..b37d7d7c2a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 }} @@ -786,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 @@ -940,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 From 42785a2ea1be40320b633b387a54b0f377a0913a Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 13:15:01 -0400 Subject: [PATCH 036/251] Expose input event timestamps without breaking listeners This follows the direction discussed in #1802 without changing existing input callback signatures or adding a second set of precise events. Store the current dispatch timestamp on lime.app.Event, add an internal timestamped dispatch path for backends, and forward native and HTML5 key/gamepad timestamps through the existing event objects so callers can read values like window.onKeyDown.timestamp inside the current callback. Add unit coverage for dispatch-time fallback, explicit timestamp injection, and nested dispatch restoration. Closes #1802. --- project/include/ui/GamepadEvent.h | 3 +- project/include/ui/KeyEvent.h | 3 +- project/src/ExternalInterface.cpp | 4 +- project/src/backend/sdl/SDLApplication.cpp | 6 ++ project/src/ui/GamepadEvent.cpp | 7 +- project/src/ui/KeyEvent.cpp | 7 +- .../backend/html5/HTML5Application.hx | 17 ++-- .../backend/native/NativeApplication.hx | 23 +++-- src/lime/_internal/macros/EventMacro.hx | 99 ++++++++++++++++--- src/lime/app/Event.hx | 14 +++ tests/unit/src/TestMain.hx | 3 +- tests/unit/src/app/EventTest.hx | 68 +++++++++++++ 12 files changed, 216 insertions(+), 38 deletions(-) create mode 100644 tests/unit/src/app/EventTest.hx 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/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index c2ddcc6867..0e52b3da2a 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -13597,9 +13597,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) 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/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/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/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index a6478bba2d..ba9ba37d72 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) @@ -777,19 +778,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); } } @@ -844,18 +847,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/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/Event.hx b/src/lime/app/Event.hx index ed4a799279..fa8043d63c 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,9 @@ class Event __repeat.splice(0, len); #end } + + private function get_timestamp():Int + { + return (__timestamp != -1) ? __timestamp : lime.system.System.getTimer(); + } } 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); + } +} From d5ee2a5437b09191901f09292c32034ba45a04e1 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 13:30:14 -0400 Subject: [PATCH 037/251] Fix Event.timestamp in doc generation Use a neutral fallback timestamp under lime_doc_gen instead of calling System.getTimer() outside of a live runtime context. This keeps the docs compile path working for the input timestamp change added in 42785a2e. --- src/lime/app/Event.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lime/app/Event.hx b/src/lime/app/Event.hx index fa8043d63c..f7fb92e030 100644 --- a/src/lime/app/Event.hx +++ b/src/lime/app/Event.hx @@ -181,6 +181,10 @@ class Event private function get_timestamp():Int { + #if lime_doc_gen + return (__timestamp != -1) ? __timestamp : 0; + #else return (__timestamp != -1) ? __timestamp : lime.system.System.getTimer(); + #end } } From 8c5a870e8663481fd90c3c639a6a177f442cdaf2 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Mon, 17 Mar 2025 18:04:43 +0000 Subject: [PATCH 038/251] Update pixman for llvm assembly fixes --- .../pixman/{config.h => pixman-config.h} | 41 ------------------- .../lib/custom/pixman/pixman/pixman-version.h | 6 +-- project/lib/pixman | 2 +- project/lib/pixman-files.xml | 1 + 4 files changed, 5 insertions(+), 45 deletions(-) rename project/lib/custom/pixman/{config.h => pixman-config.h} (86%) diff --git a/project/lib/custom/pixman/config.h b/project/lib/custom/pixman/pixman-config.h similarity index 86% rename from project/lib/custom/pixman/config.h rename to project/lib/custom/pixman/pixman-config.h index 0fa8ab453f..93286e08fb 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 */ @@ -316,9 +281,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 +298,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/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..3b902cafe7 100644 --- a/project/lib/pixman-files.xml +++ b/project/lib/pixman-files.xml @@ -73,6 +73,7 @@ + From ae54563cb0b798730f091956f729e1bbb4bab438 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Mon, 17 Mar 2025 18:09:46 +0000 Subject: [PATCH 039/251] Reenable pixman neon support for 32 bit arm Latest version of pixman has fixed support for compiling the neon assembly files with clang. Older android ndks required disabling the integrated assembler to build them but that workaround is no longer required. This also avoids the bug where older ndks didn't pass -march automatically to external assemblers. See: https://github.com/android/ndk/issues/906#issuecomment-462898046 --- project/lib/pixman-files.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/project/lib/pixman-files.xml b/project/lib/pixman-files.xml index 3b902cafe7..a318e8be49 100644 --- a/project/lib/pixman-files.xml +++ b/project/lib/pixman-files.xml @@ -3,15 +3,10 @@ - + -

- - -
- From 428e9459b294c8fbf3daa13adaeb40b6b818936f Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Mon, 17 Mar 2025 19:00:21 +0000 Subject: [PATCH 040/251] Fix pixman config for gcc android ndks GCC does not have syntax unified set explicitly, so pixman has to be able to set it. --- project/lib/custom/pixman/pixman-config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/lib/custom/pixman/pixman-config.h b/project/lib/custom/pixman/pixman-config.h index 93286e08fb..1270d937eb 100644 --- a/project/lib/custom/pixman/pixman-config.h +++ b/project/lib/custom/pixman/pixman-config.h @@ -217,6 +217,8 @@ /* #undef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR */ #endif +#define ASM_HAVE_SYNTAX_UNIFIED + /* use ARM A64_NEON assembly optimizations */ /* #undef USE_ARM_A64_NEON */ From 6051bc799450be26c0edc34510dc96312a08cc92 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Mon, 17 Mar 2025 19:25:40 +0000 Subject: [PATCH 041/251] Enable pixman neon support for arm64 Some older clang ndk's integrated assemblers have issues still with the arm64 assembly files. We can just continue disabling the integrated assembler there. The assembly is fine with the integrated assembler on versions r20 and above. --- project/lib/pixman-files.xml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/project/lib/pixman-files.xml b/project/lib/pixman-files.xml index a318e8be49..a580f14bc9 100644 --- a/project/lib/pixman-files.xml +++ b/project/lib/pixman-files.xml @@ -1,12 +1,13 @@ - - + + + @@ -17,6 +18,7 @@ + @@ -34,7 +36,9 @@ - + + + From 201b9e1ffe1c06937c902c46286123cc24e58d0d Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Sun, 11 Jan 2026 14:17:16 +0000 Subject: [PATCH 042/251] Fix pixman config for apple platforms --- project/lib/custom/pixman/pixman-config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/project/lib/custom/pixman/pixman-config.h b/project/lib/custom/pixman/pixman-config.h index 1270d937eb..02ffd50113 100644 --- a/project/lib/custom/pixman/pixman-config.h +++ b/project/lib/custom/pixman/pixman-config.h @@ -219,6 +219,10 @@ #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 */ From f34259b57c7ee765f11cf868ae951ed37c43d97a Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Sun, 11 Jan 2026 15:48:24 +0000 Subject: [PATCH 043/251] Disable neon on armv7 ios again ios still has errors --- project/lib/pixman-files.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/lib/pixman-files.xml b/project/lib/pixman-files.xml index a580f14bc9..cd266b1f0a 100644 --- a/project/lib/pixman-files.xml +++ b/project/lib/pixman-files.xml @@ -1,7 +1,7 @@ - + From f94a2d5d03ff2a82d82b093e27b57cf080247815 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Tue, 2 Jun 2026 14:47:40 -0400 Subject: [PATCH 044/251] Add polling AudioInput API Introduce Lime-level AudioInput and AudioInputDevice classes so frameworks can poll raw PCM capture data without changing existing event contracts. The native backend uses the existing OpenAL capture bindings to expose support checks, default device lookup, start/stop, sample availability, and Bytes reads. HTML5 and Flash compile as unsupported stubs for now, and the docs import list includes the new media types. --- docs/ImportAll.hx | 2 + .../backend/flash/FlashAudioInput.hx | 49 ++++ .../backend/html5/HTML5AudioInput.hx | 49 ++++ .../backend/native/NativeAudioInput.hx | 275 ++++++++++++++++++ src/lime/media/AudioInput.hx | 195 +++++++++++++ src/lime/media/AudioInputDevice.hx | 39 +++ 6 files changed, 609 insertions(+) create mode 100644 src/lime/_internal/backend/flash/FlashAudioInput.hx create mode 100644 src/lime/_internal/backend/html5/HTML5AudioInput.hx create mode 100644 src/lime/_internal/backend/native/NativeAudioInput.hx create mode 100644 src/lime/media/AudioInput.hx create mode 100644 src/lime/media/AudioInputDevice.hx diff --git a/docs/ImportAll.hx b/docs/ImportAll.hx index a5032842a4..d1fbcc89cf 100644 --- a/docs/ImportAll.hx +++ b/docs/ImportAll.hx @@ -122,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/src/lime/_internal/backend/flash/FlashAudioInput.hx b/src/lime/_internal/backend/flash/FlashAudioInput.hx new file mode 100644 index 0000000000..ec3e0a4fb2 --- /dev/null +++ b/src/lime/_internal/backend/flash/FlashAudioInput.hx @@ -0,0 +1,49 @@ +package lime._internal.backend.flash; + +import haxe.io.Bytes; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; + +class FlashAudioInput +{ + private var parent:AudioInput; + + public static function getDefaultDevice():AudioInputDevice + { + return null; + } + + public static function getDevices():Array + { + return []; + } + + public static function isSupported():Bool + { + return false; + } + + public function new(parent:AudioInput) + { + this.parent = parent; + } + + public function dispose():Void {} + + public function getSamplesAvailable():Int + { + return 0; + } + + public function read(buffer:Bytes, samples:Int):Int + { + return 0; + } + + public function start():Bool + { + return false; + } + + public function stop():Void {} +} diff --git a/src/lime/_internal/backend/html5/HTML5AudioInput.hx b/src/lime/_internal/backend/html5/HTML5AudioInput.hx new file mode 100644 index 0000000000..525a8033a4 --- /dev/null +++ b/src/lime/_internal/backend/html5/HTML5AudioInput.hx @@ -0,0 +1,49 @@ +package lime._internal.backend.html5; + +import haxe.io.Bytes; +import lime.media.AudioInput; +import lime.media.AudioInputDevice; + +class HTML5AudioInput +{ + private var parent:AudioInput; + + public static function getDefaultDevice():AudioInputDevice + { + return null; + } + + public static function getDevices():Array + { + return []; + } + + public static function isSupported():Bool + { + return false; + } + + public function new(parent:AudioInput) + { + this.parent = parent; + } + + public function dispose():Void {} + + public function getSamplesAvailable():Int + { + return 0; + } + + public function read(buffer:Bytes, samples:Int):Int + { + return 0; + } + + public function start():Bool + { + return false; + } + + public function stop():Void {} +} 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/media/AudioInput.hx b/src/lime/media/AudioInput.hx new file mode 100644 index 0000000000..8a7d604daf --- /dev/null +++ b/src/lime/media/AudioInput.hx @@ -0,0 +1,195 @@ +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. + **/ + public function start():Void + { + if (__disposed || running) + { + return; + } + + running = __backend.start(); + } + + /** + Stops audio capture. + **/ + public function stop():Void + { + if (__disposed || !running) + { + 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; + } +} From 1d813466b8aa1503fa222a630a58d821d5d7a523 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 01:02:46 -0400 Subject: [PATCH 045/251] Implement html5 audio input backend --- .../backend/html5/HTML5AudioInput.hx | 409 +++++++++++++++++- 1 file changed, 402 insertions(+), 7 deletions(-) diff --git a/src/lime/_internal/backend/html5/HTML5AudioInput.hx b/src/lime/_internal/backend/html5/HTML5AudioInput.hx index 525a8033a4..856ddd8aad 100644 --- a/src/lime/_internal/backend/html5/HTML5AudioInput.hx +++ b/src/lime/_internal/backend/html5/HTML5AudioInput.hx @@ -1,49 +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 { - return null; + if (!isSupported()) + { + return null; + } + + return new AudioInputDevice("Default Audio Input", null, true); } public static function getDevices():Array { - return []; + refreshDevices(); + + if (cachedDevices != null) + { + return cachedDevices.copy(); + } + + var defaultDevice = getDefaultDevice(); + return defaultDevice != null ? [defaultDevice] : []; } public static function isSupported():Bool { - return false; + 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 {} + public function dispose():Void + { + disposed = true; + stop(); + buffers.resize(0); + queuedBytes = 0; + } public function getSamplesAvailable():Int { - return 0; + if (frameSize <= 0) + { + return 0; + } + + return Std.int(queuedBytes / frameSize); } public function read(buffer:Bytes, samples:Int):Int { - return 0; + 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 {} + 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; + } + } } From e0bd462b5de57f0872b6024c2e04ce455de9c3bd Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 01:03:06 -0400 Subject: [PATCH 046/251] Implement flash audio input b ackend --- .../backend/flash/FlashAudioInput.hx | 255 +++++++++++++++++- 1 file changed, 247 insertions(+), 8 deletions(-) diff --git a/src/lime/_internal/backend/flash/FlashAudioInput.hx b/src/lime/_internal/backend/flash/FlashAudioInput.hx index ec3e0a4fb2..59f0012252 100644 --- a/src/lime/_internal/backend/flash/FlashAudioInput.hx +++ b/src/lime/_internal/backend/flash/FlashAudioInput.hx @@ -1,49 +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 { - return null; + 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 { - return []; + 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 false; + return Microphone.isSupported; } public function new(parent:AudioInput) { this.parent = parent; + + buffers = []; + frameSize = getFrameSize(); + queuedBytes = 0; } - public function dispose():Void {} + public function dispose():Void + { + stop(); + buffers.resize(0); + queuedBytes = 0; + } public function getSamplesAvailable():Int { - return 0; + if (frameSize <= 0) + { + return 0; + } + + return Std.int(queuedBytes / frameSize); } public function read(buffer:Bytes, samples:Int):Int { - return 0; + 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 { - return false; + 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); } - public function stop():Void {} + 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; + } + } } From 3593e6183033ab12f4c87775cd13aedc2af72044 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 01:04:03 -0400 Subject: [PATCH 047/251] account for async permissions in html5 --- src/lime/app/Event.hx | 2 +- src/lime/media/AudioInput.hx | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lime/app/Event.hx b/src/lime/app/Event.hx index f7fb92e030..5c4b0a9daa 100644 --- a/src/lime/app/Event.hx +++ b/src/lime/app/Event.hx @@ -181,7 +181,7 @@ class Event private function get_timestamp():Int { - #if lime_doc_gen + #if (lime_doc_gen || macro) return (__timestamp != -1) ? __timestamp : 0; #else return (__timestamp != -1) ? __timestamp : lime.system.System.getTimer(); diff --git a/src/lime/media/AudioInput.hx b/src/lime/media/AudioInput.hx index 8a7d604daf..17446ff888 100644 --- a/src/lime/media/AudioInput.hx +++ b/src/lime/media/AudioInput.hx @@ -135,6 +135,9 @@ class AudioInput /** Starts audio capture. + + On backends that require asynchronous permission, such as HTML5, + `running` may become true after this method returns. **/ public function start():Void { @@ -151,7 +154,7 @@ class AudioInput **/ public function stop():Void { - if (__disposed || !running) + if (__disposed) { return; } From ebcd7c52e15ed92577c51bb26c8119d1ea9d2bf0 Mon Sep 17 00:00:00 2001 From: Sergei Sergeev Date: Sun, 11 Jan 2026 20:47:32 +0300 Subject: [PATCH 048/251] Fix perspective camera In a perspective projection matrix, the bottom-right element must be 0 to ensure correct perspective division. --- src/lime/math/Matrix4.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } /** From a23712a4033580a439913456cbe22d72854b0490 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 05:03:25 -0400 Subject: [PATCH 049/251] Add ALC extension presence support Expose alcIsExtensionPresent --- project/src/media/openal/OpenALBindings.cpp | 2 ++ src/lime/_internal/backend/native/NativeCFFI.hx | 10 ++++++++++ src/lime/media/OpenALAudioContext.hx | 9 +++++++-- src/lime/media/openal/ALC.hx | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index 50fac5b710..73a4052cc0 100644 --- a/project/src/media/openal/OpenALBindings.cpp +++ b/project/src/media/openal/OpenALBindings.cpp @@ -3684,6 +3684,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); @@ -3813,6 +3814,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); diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index af16f05912..bbb081e3d8 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -3016,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; @@ -3212,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)); @@ -3361,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); @@ -3647,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; diff --git a/src/lime/media/OpenALAudioContext.hx b/src/lime/media/OpenALAudioContext.hx index c0eeb6b4e6..9d7b7d21a7 100644 --- a/src/lime/media/OpenALAudioContext.hx +++ b/src/lime/media/OpenALAudioContext.hx @@ -431,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 diff --git a/src/lime/media/openal/ALC.hx b/src/lime/media/openal/ALC.hx index 7e2cc43ef7..80194c9afa 100644 --- a/src/lime/media/openal/ALC.hx +++ b/src/lime/media/openal/ALC.hx @@ -207,6 +207,20 @@ class ALC #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) From 2592aefabde82f43069c0284bd80e47a1632eb8e Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 05:03:49 -0400 Subject: [PATCH 050/251] including bindings --- project/src/media/openal/OpenALBindings.cpp | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/project/src/media/openal/OpenALBindings.cpp b/project/src/media/openal/OpenALBindings.cpp index 73a4052cc0..cd682d444d 100644 --- a/project/src/media/openal/OpenALBindings.cpp +++ b/project/src/media/openal/OpenALBindings.cpp @@ -2318,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 From 88d151efa97b99e72962a01d87ac9e8456861c8a Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 05:47:54 -0400 Subject: [PATCH 051/251] Recover OpenAL audio after output device changes Recover native OpenAL playback when the active output device is disconnected. Some OpenAL implementations expose ALC_EXT_disconnect without newer device event or reopen extensions. In that case, active sources could stop producing audio after a headset or output device was unplugged, and they would not recover when another output became available. Track the current OpenAL context generation, poll ALC_CONNECTED as a low-cost compatibility fallback, and recreate the OpenAL context when the active device is lost. Active native AudioSource instances snapshot their playback state before recovery and restore their source handles, buffers, gain, pitch, position, time, loop count, and playing state afterward. Also remember the startup default output device and reopen it when it becomes the default again, so playback can move back from a fallback output to the original headset/device. If we migrate to a a higher version of OpenAL, we can make polling a pure fallback for MojoAL. --- .../backend/native/NativeAudioSource.hx | 116 ++++++++++ src/lime/media/AudioBuffer.hx | 1 + src/lime/media/AudioManager.hx | 215 ++++++++++++++++++ src/lime/media/openal/ALC.hx | 1 + 4 files changed, 333 insertions(+) diff --git a/src/lime/_internal/backend/native/NativeAudioSource.hx b/src/lime/_internal/backend/native/NativeAudioSource.hx index 363aa63117..1c19e1e757 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; @@ -48,6 +49,15 @@ class NativeAudioSource private var queuedBufferCount: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 +74,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(); @@ -195,8 +226,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; @@ -505,6 +543,84 @@ class NativeAudioSource queuedBufferCount = 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; + + 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 { if (length <= 0) diff --git a/src/lime/media/AudioBuffer.hx b/src/lime/media/AudioBuffer.hx index 8d3756d268..409739d212 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; diff --git a/src/lime/media/AudioManager.hx b/src/lime/media/AudioManager.hx index 8a085f253d..023bf13696 100644 --- a/src/lime/media/AudioManager.hx +++ b/src/lime/media/AudioManager.hx @@ -2,6 +2,7 @@ package lime.media; import haxe.Timer; import lime._internal.backend.native.NativeCFFI; +import lime._internal.backend.native.NativeAudioSource; import lime.media.openal.AL; import lime.media.openal.ALC; import lime.media.openal.ALContext; @@ -18,6 +19,14 @@ import js.Browser; class AudioManager { public static var context:AudioContext; + @:noCompletion public static var __contextGeneration(default, null):Int; + private static inline var OUTPUT_DEVICE_POLL_TIME:Int = 1000; + private static var outputDevice:ALDevice; + 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 +48,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 +88,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 +133,206 @@ 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 (outputDeviceRecovering || context == null || context.type != OPENAL) + { + return; + } + + outputDeviceRecovering = true; + NativeAudioSource.prepareAudioContextRecovery(); + closeOpenALContext(); + + if (openOpenALContext(deviceName)) + { + refreshOutputDeviceRecovery(); + NativeAudioSource.restoreAudioContextRecovery(); + } + + outputDeviceRecovering = false; + } + + 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/openal/ALC.hx b/src/lime/media/openal/ALC.hx index 80194c9afa..a897a232a8 100644 --- a/src/lime/media/openal/ALC.hx +++ b/src/lime/media/openal/ALC.hx @@ -37,6 +37,7 @@ class ALC 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 { From 8d9a49e6955cc0c733fa62db9b1accbb15f56bb0 Mon Sep 17 00:00:00 2001 From: ACrazyTown <47027981+ACrazyTown@users.noreply.github.com> Date: Fri, 23 May 2025 13:57:51 +0200 Subject: [PATCH 052/251] AudioBuffer: Don't force HTML5 audio when using fromBytes()/fromBase64() --- src/lime/media/AudioBuffer.hx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/lime/media/AudioBuffer.hx b/src/lime/media/AudioBuffer.hx index 409739d212..1cf584c5d8 100644 --- a/src/lime/media/AudioBuffer.hx +++ b/src/lime/media/AudioBuffer.hx @@ -136,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 @@ -182,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) From 01a9171aa1461cf000c634ff05dd951e7a7bced8 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 10:21:29 -0400 Subject: [PATCH 053/251] compilation checks --- src/lime/media/AudioManager.hx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lime/media/AudioManager.hx b/src/lime/media/AudioManager.hx index 023bf13696..5001f7ab72 100644 --- a/src/lime/media/AudioManager.hx +++ b/src/lime/media/AudioManager.hx @@ -1,12 +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 @@ -19,9 +23,13 @@ import js.Browser; class AudioManager { public static var context:AudioContext; - @:noCompletion public static var __contextGeneration(default, null):Int; + @: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; @@ -230,6 +238,7 @@ class AudioManager private static function recoverOutputDevice(deviceName:String = null):Void { + #if (lime_cffi && !macro && lime_openal) if (outputDeviceRecovering || context == null || context.type != OPENAL) { return; @@ -246,6 +255,7 @@ class AudioManager } outputDeviceRecovering = false; + #end } private static function refreshOutputDeviceRecovery():Void From e090825667b3d2718e7b8ff4e59616f6f88471e5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 3 Jun 2026 10:39:02 -0400 Subject: [PATCH 054/251] Fix HashLink layout mismatch --- project/include/media/AudioBuffer.h | 3 ++- project/src/ExternalInterface.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) 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/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 0e52b3da2a..9e800f3772 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -13613,7 +13613,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) From bf2704d7216a1e1c37012001607bc1f30af38562 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 5 Jun 2026 05:54:53 -0400 Subject: [PATCH 055/251] Support inline stream looping and loop counts Add handling for inline looping audio streams by tracking per-buffer and per-stream loop counts. --- .../backend/native/NativeAudioSource.hx | 159 +++++++++++++++++- 1 file changed, 152 insertions(+), 7 deletions(-) diff --git a/src/lime/_internal/backend/native/NativeAudioSource.hx b/src/lime/_internal/backend/native/NativeAudioSource.hx index 1c19e1e757..e881c5166e 100644 --- a/src/lime/_internal/backend/native/NativeAudioSource.hx +++ b/src/lime/_internal/backend/native/NativeAudioSource.hx @@ -47,6 +47,8 @@ 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; @@ -131,6 +133,8 @@ class NativeAudioSource streamExhausted = false; streamPosition = 0; queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; ownsVorbisStream = false; clearVorbisStream(); clearSDLSoundStream(); @@ -525,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) @@ -541,6 +618,8 @@ class NativeAudioSource } queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; } private function prepareAudioContextRecoverySource():Void @@ -578,6 +657,8 @@ class NativeAudioSource buffers = null; bufferTimeBlocks = null; queuedBufferCount = 0; + queuedBufferLoopCounts = []; + queuedStreamLoopCount = 0; if (parent.buffer != null) { @@ -738,10 +819,12 @@ class NativeAudioSource if (buffers != null) { queuedBufferCount -= buffers.length; + consumeProcessedStreamLoopCounts(buffers.length); } else { queuedBufferCount -= buffersProcessed; + consumeProcessedStreamLoopCounts(buffersProcessed); } if (queuedBufferCount < 0) @@ -770,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; @@ -803,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; } } @@ -823,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 @@ -1014,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; From b8d06e088d60cbcf08cb4e311445194ea65145af Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 5 Jun 2026 06:50:45 -0400 Subject: [PATCH 056/251] Add transparent window support --- project/include/ui/Window.h | 3 +- project/src/ExternalInterface.cpp | 15 +++++- project/src/backend/sdl/SDLWindow.cpp | 53 ++++++++++++++++++- project/src/graphics/vulkan/VKRenderer.cpp | 15 +++++- .../_internal/backend/html5/HTML5Window.hx | 3 +- .../_internal/backend/native/NativeWindow.hx | 9 +++- src/lime/system/System.hx | 2 + src/lime/tools/WindowData.hx | 2 + src/lime/ui/Window.hx | 2 + src/lime/ui/WindowAttributes.hx | 1 + templates/haxe/ApplicationMain.hx | 1 + 11 files changed, 97 insertions(+), 9 deletions(-) diff --git a/project/include/ui/Window.h b/project/include/ui/Window.h index 8af2651c4a..81afa74fae 100644 --- a/project/include/ui/Window.h +++ b/project/include/ui/Window.h @@ -114,7 +114,8 @@ namespace lime { WINDOW_FLAG_MAXIMIZED = 0x00004000, WINDOW_FLAG_ALWAYS_ON_TOP = 0x00008000, WINDOW_FLAG_COLOR_DEPTH_32_BIT = 0x00010000, - WINDOW_FLAG_VULKAN = 0x00020000 + WINDOW_FLAG_VULKAN = 0x00020000, + WINDOW_FLAG_TRANSPARENT = 0x00040000 }; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 9e800f3772..008dd4c5fb 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -1152,14 +1152,25 @@ namespace lime { } VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - const VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = { + 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 < sizeof (compositeAlphaFlags) / sizeof (compositeAlphaFlags[0]); ++i) { + for (size_t i = 0; i < compositeAlphaFlagCount; ++i) { if (capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index 5d42c30bc3..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 @@ -241,6 +278,14 @@ 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) { if (useVulkan) { @@ -304,7 +349,7 @@ namespace lime { } - if (flags & WINDOW_FLAG_COLOR_DEPTH_32_BIT) { + if (flags & (WINDOW_FLAG_COLOR_DEPTH_32_BIT | WINDOW_FLAG_TRANSPARENT)) { SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); @@ -345,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) diff --git a/project/src/graphics/vulkan/VKRenderer.cpp b/project/src/graphics/vulkan/VKRenderer.cpp index dfe41d9553..a8b9069a0d 100644 --- a/project/src/graphics/vulkan/VKRenderer.cpp +++ b/project/src/graphics/vulkan/VKRenderer.cpp @@ -1031,14 +1031,25 @@ namespace lime { } VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - const VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = { + 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 < sizeof (compositeAlphaFlags) / sizeof (compositeAlphaFlags[0]); ++i) { + for (size_t i = 0; i < compositeAlphaFlagCount; ++i) { if (capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index 8e7b662b08..2d30cb33e7 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) + || (Reflect.hasField(attributes, "transparent") && attributes.transparent); var colorDepth = Reflect.hasField(contextAttributes, "colorDepth") ? contextAttributes.colorDepth : 16; var options = diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index ecadbb89c1..f548ae1c5f 100644 --- a/src/lime/_internal/backend/native/NativeWindow.hx +++ b/src/lime/_internal/backend/native/NativeWindow.hx @@ -68,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; @@ -92,6 +95,7 @@ class NativeWindow 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; @@ -757,4 +761,5 @@ class NativeWindow 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/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/WindowData.hx b/src/lime/tools/WindowData.hx index 92f101feb1..1f74f090ad 100644 --- a/src/lime/tools/WindowData.hx +++ b/src/lime/tools/WindowData.hx @@ -26,6 +26,7 @@ abstract WindowData({ @: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 @@ -61,6 +62,7 @@ abstract WindowData({ 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 7fe8d2a1c3..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,6 +237,7 @@ 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); 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/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index 2fadafabb0..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::, From 6f124fcfa75b99b5fb6f08c9e949271a9e82a38c Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 5 Jun 2026 06:52:11 -0400 Subject: [PATCH 057/251] Fix HL Vulkan exports --- project/src/ExternalInterface.cpp | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 008dd4c5fb..2f6abcb4a8 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -13797,6 +13797,23 @@ namespace lime { 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); @@ -13804,6 +13821,55 @@ namespace lime { 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); From f53e224096462121158ccf6ebe7037dd844bf290 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 5 Jun 2026 06:57:27 -0400 Subject: [PATCH 058/251] Fix HTML5 transparent docs build --- src/lime/_internal/backend/html5/HTML5Window.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index 2d30cb33e7..e36aa53e34 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -321,7 +321,7 @@ class HTML5Window if (forceWebGL || (!forceCanvas && (!Reflect.hasField(contextAttributes, "hardware") || contextAttributes.hardware))) { var transparentBackground = (Reflect.hasField(contextAttributes, "background") && contextAttributes.background == null) - || (Reflect.hasField(attributes, "transparent") && attributes.transparent); + || parent.transparent; var colorDepth = Reflect.hasField(contextAttributes, "colorDepth") ? contextAttributes.colorDepth : 16; var options = From 7c2d7e2e08823994a20fe56b0ecfa3abcf00600e Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Fri, 12 Jun 2026 17:55:35 -0400 Subject: [PATCH 059/251] Gate invisible window optimization --- src/lime/_internal/backend/native/NativeApplication.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index ba9ba37d72..ad45bbaba0 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -463,11 +463,13 @@ class NativeApplication for (window in parent.__windows) { if (window == null) continue; - if (!window.visible) continue; // parent.renderer = renderer; switch (renderEventInfo.type) { case RENDER: + #if lime_skip_invisible_windows + if (!window.visible) continue; + #end if (window.context != null) { window.__backend.render(); From dd530ba3f532d8b0743de56371a36c0cd3a2d7ac Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 12:59:14 -0400 Subject: [PATCH 060/251] prepare for 8.4.0 --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) 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) ------------------ From e749e62e72b46e17319c0ca269d8852247b8e4c5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 13:54:10 -0400 Subject: [PATCH 061/251] Stop copying embedded assets --- src/lime/tools/PlatformTarget.hx | 36 +++++++++++++++++++------- tools/platforms/AndroidPlatform.hx | 2 ++ tools/platforms/IOSPlatform.hx | 2 ++ tools/platforms/LinuxPlatform.hx | 2 ++ tools/platforms/MacPlatform.hx | 2 ++ tools/platforms/TVOSPlatform.hx | 2 ++ tools/platforms/TizenPlatform.hx | 2 ++ tools/platforms/WebAssemblyPlatform.hx | 2 ++ tools/platforms/WindowsPlatform.hx | 2 ++ 9 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index fc5dc2a20f..11daa26e25 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -201,6 +201,22 @@ class PlatformTarget // Common functionality used by subclasses + 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; + } + } + } + private function copyProjectAssets(outputDirectory:String, assetDirectory:String = null) { if (assetDirectory == null) @@ -212,27 +228,27 @@ class PlatformTarget assetDirectory = Path.combine(outputDirectory, assetDirectory); } - var embedDirectory = Path.combine(targetDirectory, "obj/tmp"); + prepareEmbeddedAssets(); 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 + else if (asset.embed == true) { - if (asset.embed == true && 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); } - - var path = Path.combine(assetDirectory, asset.targetPath); + } + else + { System.mkdir(Path.directory(path)); AssetHelper.copyAssetIfNewer(asset, path); } diff --git a/tools/platforms/AndroidPlatform.hx b/tools/platforms/AndroidPlatform.hx index 91057bc452..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); 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 420594e8bc..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) { diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index 3bc28d3110..de9f8ec17b 100644 --- a/tools/platforms/WindowsPlatform.hx +++ b/tools/platforms/WindowsPlatform.hx @@ -954,6 +954,8 @@ class WindowsPlatform extends PlatformTarget // project = project.clone (); + prepareEmbeddedAssets(); + if (project.targetFlags.exists("xml")) { project.haxeflags.push("-xml " + targetDirectory + "/types.xml"); From 79e2cef701820fa6db8cdb2cbf3f103db4d6d946 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 14:39:10 -0400 Subject: [PATCH 062/251] Avoid duplicate embedded asset prep --- src/lime/tools/PlatformTarget.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index 11daa26e25..75768f0287 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -228,8 +228,6 @@ class PlatformTarget assetDirectory = Path.combine(outputDirectory, assetDirectory); } - prepareEmbeddedAssets(); - for (asset in project.assets) { var path = Path.combine(assetDirectory, asset.targetPath); From baaf478e60b294d9f499530857602c535cfd944a Mon Sep 17 00:00:00 2001 From: Joseph Cloutier Date: Thu, 18 Jun 2026 14:57:13 -0400 Subject: [PATCH 063/251] Document asset embedding functions. --- src/lime/tools/PlatformTarget.hx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index 75768f0287..49e5b17a95 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -201,6 +201,10 @@ 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"); @@ -217,6 +221,13 @@ class PlatformTarget } } + /** + 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) From ce2399729afd749e183b8435f9d297f203e42dc5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 16:03:05 -0400 Subject: [PATCH 064/251] Reduce Bytes resize mutex scope Move Bytes resize allocation, copy, and free work outside the shared ownership mutex, leaving the lock only around usingValue bookkeeping and pointer/length updates. This reduces observed contention in threaded compression paths while preserving Haxe Bytes ownership. closes https://github.com/openfl/lime/issues/1943 --- project/src/utils/Bytes.cpp | 64 ++++++++++++------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/project/src/utils/Bytes.cpp b/project/src/utils/Bytes.cpp index 83f028f2dd..e0136147f6 100644 --- a/project/src/utils/Bytes.cpp +++ b/project/src/utils/Bytes.cpp @@ -122,72 +122,50 @@ namespace lime { if (size != length || (length > 0 && !b)) { - mutex.Lock (); - - if (size <= 0) { - - if (b) { - - if (usingValue.find (this) != usingValue.end ()) { - - usingValue.erase (this); - - } else { + unsigned char* data = 0; + unsigned char* oldB = b; + bool freeOldB = false; - free (b); + if (size > 0) { - } - - } else if (usingValue.find (this) != usingValue.end ()) { - - usingValue.erase (this); - - } - - b = 0; - length = 0; - - } else { - - unsigned char* data = (unsigned char*)malloc (sizeof (char) * size); + data = (unsigned char*)malloc (sizeof (char) * size); if (!data) { - mutex.Unlock (); return false; } - if (b) { + if (b && length) { - if (length) { + memcpy (data, b, length < size ? length : size); - memcpy (data, b, length < size ? length : size); + } - } + } - if (usingValue.find (this) != usingValue.end ()) { + mutex.Lock (); - usingValue.erase (this); + if (usingValue.find (this) != usingValue.end ()) { - } else { + usingValue.erase (this); - free (b); + } else if (oldB) { - } + freeOldB = true; - } else if (usingValue.find (this) != usingValue.end ()) { + } - usingValue.erase (this); + b = data; + length = size > 0 ? size : 0; - } + mutex.Unlock (); - b = data; - length = size; + if (freeOldB) { - } + free (oldB); - mutex.Unlock (); + } } From aa6ce421236ee0856dac5c5d193fcbe97cbd238b Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 16:18:14 -0400 Subject: [PATCH 065/251] Fix FileDialog wildcard filter handling Normalize FileDialog filters so existing bare extensions like png still work while documented wildcard filters like *.png are accepted without becoming *.*.png. Also fixes save-dialog filter construction to use the full filter string with stable storage, and keeps save auto-extension from appending wildcard text into filenames. CLoses https://github.com/openfl/lime/issues/1945 --- project/src/ui/FileDialog.cpp | 90 +++++++++++++++++++++-------------- src/lime/ui/FileDialog.hx | 47 +++++++++++++++--- 2 files changed, 95 insertions(+), 42 deletions(-) diff --git a/project/src/ui/FileDialog.cpp b/project/src/ui/FileDialog.cpp index b740102696..ec561973b1 100644 --- a/project/src/ui/FileDialog.cpp +++ b/project/src/ui/FileDialog.cpp @@ -25,6 +25,45 @@ namespace lime { return str == nullptr || str[0] == 0; } + static string_t normalize_filter (const string_t& filter) { + + if (filter.empty () || filter.find (FD_STR('*')) != string_t::npos || filter.find (FD_STR('?')) != string_t::npos) { + + return filter; + + } + + if (filter[0] == FD_STR('.')) { + + return string_t (FD_STR("*")) + filter; + + } + + return string_t (FD_STR("*.")) + filter; + + } + + static std::vector normalize_filters (const char_t* filter) { + + std::vector filters; + + if (filter) { + + string_t line; + std::basic_stringstream ss (filter); + + while (std::getline (ss, line, FD_STR(','))) { + + filters.push_back (normalize_filter (line)); + + } + + } + + return filters; + + } + const char_t* FileDialog::OpenDirectory (const char_t* title, const char_t* filter, const char_t* defaultPath) { // TODO: Filter? @@ -44,27 +83,17 @@ namespace lime { const char_t* FileDialog::OpenFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - std::vector filters_vec; - if (filter) { - 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); - } - } + std::vector filters_vec = normalize_filters (filter); - const int numFilters = filter ? filters_vec.size() : 1; - const char_t **filters = new const char_t*[numFilters]; - if (filter && numFilters > 0) { + const int numFilters = filters_vec.size (); + const char_t **filters = numFilters > 0 ? new const char_t*[numFilters] : NULL; + if (numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = filters_vec[index].c_str(); } - } else { - filters[0] = NULL; } - const char_t* path = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 0); + const char_t* path = tinyfd_openFileDialog (title, defaultPath, numFilters, filters, NULL, 0); delete[] filters; @@ -82,27 +111,17 @@ namespace lime { std::vector FileDialog::OpenFiles (const char_t* title, const char_t* filter, const char_t* defaultPath) { std::vector files; - std::vector filters_vec; - if (filter) { - 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); - } - } + std::vector filters_vec = normalize_filters (filter); - const int numFilters = filter ? filters_vec.size() : 1; - const char_t **filters = new const char_t*[numFilters]; - if (filter && numFilters > 0) { + const int numFilters = filters_vec.size (); + const char_t **filters = numFilters > 0 ? new const char_t*[numFilters] : NULL; + if (numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = filters_vec[index].c_str(); } - } else { - filters[0] = NULL; } - const char_t* paths = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 1); + const char_t* paths = tinyfd_openFileDialog (title, defaultPath, numFilters, filters, NULL, 1); delete[] filters; @@ -133,10 +152,11 @@ namespace lime { const char_t* FileDialog::SaveFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - string_t temp(FD_STR("*.")); - const char_t* filters[] = { filter ? (temp + *filter).c_str () : NULL }; + std::vector filters_vec = normalize_filters (filter); + const int numFilters = filters_vec.size () > 0 ? 1 : 0; + const char_t* filters[] = { numFilters > 0 ? filters_vec[0].c_str () : NULL }; - const char_t* path = tinyfd_saveFileDialog (title, defaultPath, filter ? 1 : 0, filter ? filters : NULL, NULL); + const char_t* path = tinyfd_saveFileDialog (title, defaultPath, numFilters, numFilters > 0 ? filters : NULL, NULL); if (!is_null_or_empty(path)) { diff --git a/src/lime/ui/FileDialog.hx b/src/lime/ui/FileDialog.hx index 014c11b8b5..7004406412 100644 --- a/src/lime/ui/FileDialog.hx +++ b/src/lime/ui/FileDialog.hx @@ -82,14 +82,46 @@ class FileDialog public function new() {} + private static function __extensionFromFilter(filter:String):String + { + for (entry in filter.split(",")) + { + if (entry.length == 0) continue; + + var extension = entry; + + if (StringTools.startsWith(extension, "*.")) + { + extension = extension.substr(2); + } + else if (StringTools.startsWith(extension, ".")) + { + extension = extension.substr(1); + } + + if (extension.length == 0 + || extension.indexOf("*") != -1 + || extension.indexOf("?") != -1 + || extension.indexOf("/") != -1 + || extension.indexOf("\\") != -1) + { + continue; + } + + return extension; + } + + return null; + } + /** Opens a file selection dialog. If successful, either `onSelect` or `onSelectMultiple` will trigger with the result(s). This function only works on desktop targets, and will return `false` otherwise. @param type Type of the file dialog: `OPEN`, `SAVE`, `OPEN_DIRECTORY` or `OPEN_MULTIPLE`. - @param filter A filter to use when browsing. Asterisks are treated as wildcards. For example, - `"*.jpg"` will match any file ending in `.jpg`. + @param filter A filter to use when browsing. Use a bare extension such as `"jpg"` or + a wildcard pattern such as `"*.jpg"`. Multiple filters may be separated by commas. @param defaultPath The directory in which to start browsing and/or the default filename to suggest. Defaults to `Sys.getCwd()`, with no default filename. @param title The title to give the dialog window. @@ -137,7 +169,8 @@ class FileDialog // Makes sure the filename ends with extension if (type == SAVE && filter != null && path.indexOf(".") == -1) { - path += "." + filter; + var extension = __extensionFromFilter(filter); + if (extension != null) path += "." + extension; } onSelect.dispatch(path); @@ -239,8 +272,8 @@ class FileDialog Shows an open file dialog. If successful, `onOpen` will trigger with the file contents. This function only works on desktop targets, and will return `false` otherwise. - @param filter A filter to use when browsing. Asterisks are treated as wildcards. For example, - `"*.jpg"` will match any file ending in `.jpg`. + @param filter A filter to use when browsing. Use a bare extension such as `"jpg"` or + a wildcard pattern such as `"*.jpg"`. Multiple filters may be separated by commas. @param defaultPath The directory in which to start browsing and/or the default filename to suggest. Defaults to `Sys.getCwd()`, with no default filename. @param title The title to give the dialog window. @@ -293,8 +326,8 @@ class FileDialog This function only works on desktop and HMTL5 targets, and will return `false` otherwise. @param data The file contents, in `haxe.io.Bytes` format. (Implicit casting possible.) - @param filter A filter to use when browsing. Asterisks are treated as wildcards. For example, - `"*.jpg"` will match any file ending in `.jpg`. Used only if targeting deskop. + @param filter A filter to use when browsing. Use a bare extension such as `"jpg"` or + a wildcard pattern such as `"*.jpg"`. Multiple filters may be separated by commas. Used only if targeting deskop. @param defaultPath The directory in which to start browsing and/or the default filename to suggest. When targeting destkop, this defaults to `Sys.getCwd()` with no default filename. When targeting HTML5, this defaults to the browser's download directory, with a default filename based on the MIME type. From fcd53bd64a3d9569d2f9e77a71137fe341e796e1 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 16:31:55 -0400 Subject: [PATCH 066/251] Hide console for Windows HashLink app builds Patch the copied Windows HashLink launcher to use the GUI subsystem by default, matching Lime's other Windows app targets. The original bundled or user-provided hl.exe is left unchanged, and SHOW_CONSOLE keeps the old console behavior for users who need it. Closes https://github.com/openfl/lime/issues/1428 --- src/lime/tools/HashlinkHelper.hx | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/lime/tools/HashlinkHelper.hx b/src/lime/tools/HashlinkHelper.hx index 759f471493..efd1d29e5d 100644 --- a/src/lime/tools/HashlinkHelper.hx +++ b/src/lime/tools/HashlinkHelper.hx @@ -8,10 +8,52 @@ import lime.tools.HXProject; import lime.tools.Platform; import hxp.Path; import hxp.System; +import sys.io.File; class HashlinkHelper { public static inline var BUNDLED_HL_VER = "1.14.0"; + private static inline var IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; + + private static function readUInt32LE(bytes:haxe.io.Bytes, offset:Int):Int + { + return bytes.get(offset) | (bytes.get(offset + 1) << 8) | (bytes.get(offset + 2) << 16) | (bytes.get(offset + 3) << 24); + } + + private static function setWindowsGUISubsystem(executablePath:String):Void + { + try + { + var bytes = File.getBytes(executablePath); + + if (bytes.length < 0x100 || bytes.get(0) != 0x4D || bytes.get(1) != 0x5A) + { + Log.warn('Could not hide HashLink console: "$executablePath" is not a valid Windows executable'); + return; + } + + var peOffset = readUInt32LE(bytes, 0x3C); + var subsystemOffset = peOffset + 24 + 68; + + if (peOffset < 0 || subsystemOffset + 1 >= bytes.length + || bytes.get(peOffset) != 0x50 + || bytes.get(peOffset + 1) != 0x45 + || bytes.get(peOffset + 2) != 0 + || bytes.get(peOffset + 3) != 0) + { + Log.warn('Could not hide HashLink console: "$executablePath" has an unsupported PE header'); + return; + } + + bytes.set(subsystemOffset, IMAGE_SUBSYSTEM_WINDOWS_GUI); + bytes.set(subsystemOffset + 1, 0); + File.saveBytes(executablePath, bytes); + } + catch (e:Dynamic) + { + Log.warn('Could not hide HashLink console for "$executablePath": $e'); + } + } public static function copyHashlink(project:HXProject, targetDirectory:String, applicationDirectory:String, executablePath:String, ?is64 = true) { @@ -94,6 +136,11 @@ class HashlinkHelper } } + if (platform == WINDOWS && !project.targetFlags.exists("hlc") && !project.environment.exists("SHOW_CONSOLE")) + { + setWindowsGUISubsystem(executablePath); + } + // make sure no hxcpp hash files or MSVC build artifacts remain for (file in System.readDirectory(applicationDirectory)) From 70a41bff0bb15f3a6db8bd1edb9eec247a009fbb Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 17:11:37 -0400 Subject: [PATCH 067/251] CI fixes --- .github/workflows/main.yml | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b37d7d7c2a..3ea16a4a54 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -249,16 +249,27 @@ jobs: - name: Install HashLink dependencies run: | - arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - pushd project/lib/hashlink - arch -x86_64 /usr/local/bin/brew update - rm /usr/local/bin/2to3* - rm /usr/local/bin/idle3* - rm /usr/local/bin/pydoc3* - rm /usr/local/bin/python3* - rm /usr/local/bin/pip3* - arch -x86_64 /usr/local/bin/brew bundle - popd + set -euxo pipefail + + if [ ! -x /usr/local/bin/brew ]; then + NONINTERACTIVE=1 arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + fi + + rm -f /usr/local/bin/2to3* + rm -f /usr/local/bin/idle3* + rm -f /usr/local/bin/pydoc3* + rm -f /usr/local/bin/python3* + rm -f /usr/local/bin/pip3* + + for attempt in 1 2 3; do + if arch -x86_64 /usr/local/bin/brew update && arch -x86_64 /usr/local/bin/brew install jpeg-turbo libpng libuv libvorbis; then + break + fi + if [ "$attempt" -eq 3 ]; then + exit 1 + fi + sleep $((attempt * 30)) + done - name: Install Haxe dependencies run: | @@ -278,6 +289,9 @@ jobs: run: | lime rebuild macos -clean -release -64 -nocolor -verbose -nocffi lime rebuild macos -clean -release -arm64 -nocolor -verbose -nocffi + + - name: Rebuild Lime (HashLink macOS) + run: | lime rebuild hl -clean -release -nocolor -verbose -nocffi - uses: actions/upload-artifact@v7 From aec9d3f1e2e7e6f714fdbd33f730790e530bf98e Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 18 Jun 2026 20:06:36 -0400 Subject: [PATCH 068/251] Run formatter --- externs/air/flash/data/SQLCollationType.hx | 3 +- externs/air/flash/data/SQLColumnNameStyle.hx | 3 +- externs/air/flash/data/SQLMode.hx | 3 +- .../air/flash/data/SQLTransactionLockType.hx | 3 +- .../air/flash/desktop/InvokeEventReason.hx | 3 +- .../air/flash/desktop/NativeDragActions.hx | 3 +- externs/air/flash/desktop/NotificationType.hx | 3 +- externs/air/flash/desktop/SystemIdleMode.hx | 3 +- .../flash/display/NativeWindowDisplayState.hx | 3 +- .../flash/display/NativeWindowRenderMode.hx | 3 +- .../air/flash/display/NativeWindowResize.hx | 3 +- .../flash/display/NativeWindowSystemChrome.hx | 3 +- externs/air/flash/display/NativeWindowType.hx | 3 +- externs/air/flash/display/StageAspectRatio.hx | 3 +- externs/air/flash/display/StageOrientation.hx | 3 +- .../air/flash/display3D/Context3DProfile.hx | 3 +- externs/air/flash/errors/SQLErrorOperation.hx | 3 +- externs/air/flash/events/TouchEventIntent.hx | 3 +- externs/air/flash/filesystem/FileMode.hx | 3 +- externs/air/flash/media/AudioPlaybackMode.hx | 3 +- externs/air/flash/media/CameraPosition.hx | 3 +- externs/air/flash/media/MediaType.hx | 3 +- externs/air/flash/net/IPVersion.hx | 3 +- .../flash/notifications/NotificationStyle.hx | 3 +- externs/air/flash/printing/PaperSize.hx | 3 +- externs/air/flash/printing/PrintMethod.hx | 3 +- .../security/ReferencesValidationSetting.hx | 3 +- .../flash/security/RevocationCheckSettings.hx | 3 +- externs/air/flash/security/SignatureStatus.hx | 3 +- .../air/flash/security/SignerTrustSettings.hx | 3 +- externs/air/flash/text/AutoCapitalize.hx | 3 +- externs/air/flash/text/ReturnKeyLabel.hx | 3 +- externs/air/flash/text/SoftKeyboardType.hx | 3 +- .../flash/text/StageTextClearButtonMode.hx | 3 +- externs/air/sys/io/FileInput.hx | 4 +- externs/air/sys/io/FileOutput.hx | 4 +- src/lime/_internal/backend/air/AIRWindow.hx | 6 +- .../backend/emscripten/EmscriptenFetch.hx | 56 +- .../emscripten/EmscriptenHTTPRequest.hx | 447 ++++--- .../backend/flash/FlashHTTPRequest.hx | 2 +- .../_internal/backend/flash/FlashWindow.hx | 3 +- .../backend/html5/HTML5AudioSource.hx | 3 +- .../backend/html5/HTML5HTTPRequest.hx | 3 +- .../_internal/backend/html5/HTML5Thread.hx | 104 +- .../backend/native/NativeAudioSource.hx | 16 +- .../_internal/backend/native/NativeCFFI.hx | 1051 ++++++++--------- .../backend/native/NativeHTTPRequest.hx | 3 +- .../_internal/backend/native/NativeWindow.hx | 3 +- src/lime/_internal/graphics/ImageDataUtil.hx | 37 +- src/lime/_internal/macros/AssetsMacro.hx | 153 ++- src/lime/_internal/macros/CFFIMacro.hx | 16 +- src/lime/_internal/macros/EventMacro.hx | 11 +- src/lime/_internal/macros/HTTPRequestMacro.hx | 6 +- src/lime/app/Event.hx | 1 + src/lime/graphics/Image.hx | 4 +- src/lime/graphics/OpenGLES3RenderContext.hx | 1 - src/lime/graphics/VulkanRenderContext.hx | 1 - src/lime/graphics/WebGL2RenderContext.hx | 188 +-- src/lime/graphics/vulkan/VK.hx | 4 +- src/lime/graphics/vulkan/VKBuffer.hx | 1 - src/lime/graphics/vulkan/VKCommandBuffer.hx | 152 ++- src/lime/graphics/vulkan/VKCommandPool.hx | 1 - src/lime/graphics/vulkan/VKDescriptorPool.hx | 1 - src/lime/graphics/vulkan/VKDescriptorSet.hx | 16 +- .../graphics/vulkan/VKDescriptorSetLayout.hx | 5 +- src/lime/graphics/vulkan/VKDescriptorWrite.hx | 8 +- src/lime/graphics/vulkan/VKDevice.hx | 70 +- src/lime/graphics/vulkan/VKDeviceMemory.hx | 19 +- src/lime/graphics/vulkan/VKFence.hx | 1 - src/lime/graphics/vulkan/VKFramebuffer.hx | 1 - src/lime/graphics/vulkan/VKImage.hx | 14 +- src/lime/graphics/vulkan/VKImageView.hx | 1 - src/lime/graphics/vulkan/VKInstance.hx | 1 - src/lime/graphics/vulkan/VKPhysicalDevice.hx | 14 +- src/lime/graphics/vulkan/VKPipeline.hx | 1 - src/lime/graphics/vulkan/VKPipelineCache.hx | 5 +- src/lime/graphics/vulkan/VKPipelineLayout.hx | 1 - src/lime/graphics/vulkan/VKQueue.hx | 15 +- src/lime/graphics/vulkan/VKQueueFamilyInfo.hx | 3 +- src/lime/graphics/vulkan/VKRenderPass.hx | 1 - src/lime/graphics/vulkan/VKRenderer.hx | 1 - src/lime/graphics/vulkan/VKSampler.hx | 1 - src/lime/graphics/vulkan/VKSemaphore.hx | 1 - src/lime/graphics/vulkan/VKShaderModule.hx | 1 - src/lime/graphics/vulkan/VKSurface.hx | 1 - src/lime/graphics/vulkan/VKSwapchain.hx | 5 +- src/lime/math/Matrix3.hx | 30 +- src/lime/math/Matrix4.hx | 2 +- src/lime/media/AudioBuffer.hx | 30 +- src/lime/media/AudioInput.hx | 1 + src/lime/media/AudioInputDevice.hx | 1 + src/lime/media/AudioSource.hx | 6 +- src/lime/media/OpenALAudioContext.hx | 9 +- src/lime/net/HTTPRequest.hx | 7 +- src/lime/system/BackgroundWorker.hx | 7 +- src/lime/system/CFFI.hx | 5 +- src/lime/system/JNI.hx | 27 +- src/lime/system/Orientation.hx | 2 +- src/lime/system/System.hx | 23 +- src/lime/system/ThreadPool.hx | 74 +- src/lime/text/Font.hx | 210 ++-- .../text/harfbuzz/HBBufferSerializeFormat.hx | 1 + src/lime/tools/AIRHelper.hx | 15 +- src/lime/tools/ApplicationData.hx | 19 +- src/lime/tools/AssetHelper.hx | 66 +- src/lime/tools/CPPHelper.hx | 10 +- src/lime/tools/CSHelper.hx | 12 +- src/lime/tools/ConfigData.hx | 25 +- src/lime/tools/FlashHelper.hx | 17 +- src/lime/tools/HTML5Helper.hx | 20 +- src/lime/tools/HXProject.hx | 32 +- src/lime/tools/HashlinkHelper.hx | 21 +- src/lime/tools/IOSHelper.hx | 57 +- src/lime/tools/IconHelper.hx | 3 +- src/lime/tools/MetaData.hx | 23 +- src/lime/tools/PlatformTarget.hx | 11 +- src/lime/tools/ProjectXMLParser.hx | 2 - src/lime/tools/WindowData.hx | 69 +- src/lime/tools/XCodeHelper.hx | 5 +- src/lime/ui/FileDialog.hx | 9 +- src/lime/ui/Gamepad.hx | 15 +- src/lime/ui/KeyCode.hx | 3 +- src/lime/ui/ScanCode.hx | 3 +- src/lime/ui/Window.hx | 1 + src/lime/ui/WindowAttributes.hx | 1 + src/lime/utils/ArrayBufferView.hx | 10 +- src/lime/utils/AssetLibrary.hx | 10 +- src/lime/utils/Assets.hx | 2 +- src/lime/utils/ObjectPool.hx | 78 +- src/lime/utils/PackedAssetLibrary.hx | 17 +- src/lime/utils/Preloader.hx | 12 +- tests/unit/src/TestMain.hx | 6 +- tests/unit/src/utils/ArrayBufferTest.hx | 14 +- tests/unit/src/utils/DataViewTest.hx | 206 ++-- tests/unit/src/utils/UInt16ArrayTest.hx | 67 +- tests/unit/src/utils/UInt32ArrayTest.hx | 64 +- tests/unit/src/utils/UInt8ArrayTest.hx | 67 +- tests/vulkan-smoke/Source/Main.hx | 146 +-- tools/CommandLineTools.hx | 42 +- tools/RunScript.hx | 29 +- tools/SVGExport.hx | 2 +- tools/mpeg/audio/MpegAudioReader.hx | 4 +- tools/platforms/AndroidPlatform.hx | 81 +- tools/platforms/FlashPlatform.hx | 32 +- tools/platforms/HTML5Platform.hx | 3 +- tools/platforms/IOSPlatform.hx | 6 +- tools/platforms/LinuxPlatform.hx | 44 +- tools/platforms/MacPlatform.hx | 34 +- tools/platforms/TVOSPlatform.hx | 4 +- tools/platforms/WebAssemblyPlatform.hx | 68 +- tools/platforms/WindowsPlatform.hx | 60 +- tools/utils/PlatformSetup.hx | 37 +- 152 files changed, 2381 insertions(+), 2208 deletions(-) diff --git a/externs/air/flash/data/SQLCollationType.hx b/externs/air/flash/data/SQLCollationType.hx index fecbfc8382..0f93c36c1f 100644 --- a/externs/air/flash/data/SQLCollationType.hx +++ b/externs/air/flash/data/SQLCollationType.hx @@ -1,7 +1,6 @@ package flash.data; -@:native("flash.data.SQLCollationType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLCollationType(String) +@:native("flash.data.SQLCollationType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLCollationType(String) { var BINARY = "binary"; var NO_CASE = "noCase"; diff --git a/externs/air/flash/data/SQLColumnNameStyle.hx b/externs/air/flash/data/SQLColumnNameStyle.hx index 03cb7a5adf..c25b13fc07 100644 --- a/externs/air/flash/data/SQLColumnNameStyle.hx +++ b/externs/air/flash/data/SQLColumnNameStyle.hx @@ -1,7 +1,6 @@ package flash.data; -@:native("flash.data.SQLColumnNameStyle") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLColumnNameStyle(String) +@:native("flash.data.SQLColumnNameStyle") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLColumnNameStyle(String) { var DEFAULT = "default"; var LONG = "long"; diff --git a/externs/air/flash/data/SQLMode.hx b/externs/air/flash/data/SQLMode.hx index ebddf4c8c9..4b876d2d02 100644 --- a/externs/air/flash/data/SQLMode.hx +++ b/externs/air/flash/data/SQLMode.hx @@ -1,7 +1,6 @@ package flash.data; -@:native("flash.data.SQLMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLMode(String) +@:native("flash.data.SQLMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLMode(String) { var CREATE = "create"; var READ = "read"; diff --git a/externs/air/flash/data/SQLTransactionLockType.hx b/externs/air/flash/data/SQLTransactionLockType.hx index 36c24bc1a7..47a06a7a79 100644 --- a/externs/air/flash/data/SQLTransactionLockType.hx +++ b/externs/air/flash/data/SQLTransactionLockType.hx @@ -1,7 +1,6 @@ package flash.data; -@:native("flash.data.SQLTransactionLockType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLTransactionLockType(String) +@:native("flash.data.SQLTransactionLockType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLTransactionLockType(String) { var DEFERRED = "deferred"; var EXCLUSIVE = "exclusive"; diff --git a/externs/air/flash/desktop/InvokeEventReason.hx b/externs/air/flash/desktop/InvokeEventReason.hx index d06e591c1b..1c053ad26c 100644 --- a/externs/air/flash/desktop/InvokeEventReason.hx +++ b/externs/air/flash/desktop/InvokeEventReason.hx @@ -1,7 +1,6 @@ package flash.desktop; -@:native("flash.desktop.InvokeEventReason") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract InvokeEventReason(String) +@:native("flash.desktop.InvokeEventReason") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract InvokeEventReason(String) { var LOGIN = "login"; var NOTIFICATION = "notification"; diff --git a/externs/air/flash/desktop/NativeDragActions.hx b/externs/air/flash/desktop/NativeDragActions.hx index fe67ff9db7..544ad2f1bf 100644 --- a/externs/air/flash/desktop/NativeDragActions.hx +++ b/externs/air/flash/desktop/NativeDragActions.hx @@ -1,7 +1,6 @@ package flash.desktop; -@:native("flash.desktop.NativeDragActions") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeDragActions(String) +@:native("flash.desktop.NativeDragActions") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeDragActions(String) { var COPY = "copy"; var LINK = "link"; diff --git a/externs/air/flash/desktop/NotificationType.hx b/externs/air/flash/desktop/NotificationType.hx index b2b3dcfb09..c9461c33cf 100644 --- a/externs/air/flash/desktop/NotificationType.hx +++ b/externs/air/flash/desktop/NotificationType.hx @@ -1,7 +1,6 @@ package flash.desktop; -@:native("flash.desktop.NotificationType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NotificationType(String) +@:native("flash.desktop.NotificationType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NotificationType(String) { var CRITICAL = "critical"; var INFORMATIONAL = "informational"; diff --git a/externs/air/flash/desktop/SystemIdleMode.hx b/externs/air/flash/desktop/SystemIdleMode.hx index 7fda8df044..c129940766 100644 --- a/externs/air/flash/desktop/SystemIdleMode.hx +++ b/externs/air/flash/desktop/SystemIdleMode.hx @@ -1,7 +1,6 @@ package flash.desktop; -@:native("flash.desktop.SystemIdleMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SystemIdleMode(String) +@:native("flash.desktop.SystemIdleMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SystemIdleMode(String) { var KEEP_AWAKE = "keepAwake"; var NORMAL = "normal"; diff --git a/externs/air/flash/display/NativeWindowDisplayState.hx b/externs/air/flash/display/NativeWindowDisplayState.hx index 4fb63f10d7..56a073a2e0 100644 --- a/externs/air/flash/display/NativeWindowDisplayState.hx +++ b/externs/air/flash/display/NativeWindowDisplayState.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.NativeWindowDisplayState") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowDisplayState(String) +@:native("flash.display.NativeWindowDisplayState") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowDisplayState(String) { var MAXIMIZED = "maximized"; var MINIMIZED = "minimized"; diff --git a/externs/air/flash/display/NativeWindowRenderMode.hx b/externs/air/flash/display/NativeWindowRenderMode.hx index e2d182c5bd..51a135f715 100644 --- a/externs/air/flash/display/NativeWindowRenderMode.hx +++ b/externs/air/flash/display/NativeWindowRenderMode.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.NativeWindowRenderMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowRenderMode(String) +@:native("flash.display.NativeWindowRenderMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowRenderMode(String) { var AUTO = "auto"; var CPU = "cpu"; diff --git a/externs/air/flash/display/NativeWindowResize.hx b/externs/air/flash/display/NativeWindowResize.hx index b3cd1a1f9f..5974784f0f 100644 --- a/externs/air/flash/display/NativeWindowResize.hx +++ b/externs/air/flash/display/NativeWindowResize.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.NativeWindowResize") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowResize(String) +@:native("flash.display.NativeWindowResize") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowResize(String) { var BOTTOM = "bottom"; var BOTTOM_LEFT = "bottomLeft"; diff --git a/externs/air/flash/display/NativeWindowSystemChrome.hx b/externs/air/flash/display/NativeWindowSystemChrome.hx index e271969831..367e6d9c22 100644 --- a/externs/air/flash/display/NativeWindowSystemChrome.hx +++ b/externs/air/flash/display/NativeWindowSystemChrome.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.NativeWindowSystemChrome") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowSystemChrome(String) +@:native("flash.display.NativeWindowSystemChrome") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowSystemChrome(String) { var ALTERNATE = "alternate"; var NONE = "none"; diff --git a/externs/air/flash/display/NativeWindowType.hx b/externs/air/flash/display/NativeWindowType.hx index 90ff5bb41f..0ffd8af4bc 100644 --- a/externs/air/flash/display/NativeWindowType.hx +++ b/externs/air/flash/display/NativeWindowType.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.NativeWindowType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowType(String) +@:native("flash.display.NativeWindowType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NativeWindowType(String) { var LIGHTWEIGHT = "lightweight"; var NORMAL = "normal"; diff --git a/externs/air/flash/display/StageAspectRatio.hx b/externs/air/flash/display/StageAspectRatio.hx index 70ede16512..8a308b07bf 100644 --- a/externs/air/flash/display/StageAspectRatio.hx +++ b/externs/air/flash/display/StageAspectRatio.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.StageAspectRatio") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageAspectRatio(String) +@:native("flash.display.StageAspectRatio") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageAspectRatio(String) { var ANY = "any"; var LANDSCAPE = "landscape"; diff --git a/externs/air/flash/display/StageOrientation.hx b/externs/air/flash/display/StageOrientation.hx index d55da84778..2f2a9b34a8 100644 --- a/externs/air/flash/display/StageOrientation.hx +++ b/externs/air/flash/display/StageOrientation.hx @@ -1,7 +1,6 @@ package flash.display; -@:native("flash.display.StageOrientation") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageOrientation(String) +@:native("flash.display.StageOrientation") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageOrientation(String) { var DEFAULT = "default"; var ROTATED_LEFT = "rotatedLeft"; diff --git a/externs/air/flash/display3D/Context3DProfile.hx b/externs/air/flash/display3D/Context3DProfile.hx index 2c29eea679..a7e697bc09 100644 --- a/externs/air/flash/display3D/Context3DProfile.hx +++ b/externs/air/flash/display3D/Context3DProfile.hx @@ -1,7 +1,6 @@ package flash.display3D; -@:native("flash.display3D.Context3DProfile") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract Context3DProfile(String) +@:native("flash.display3D.Context3DProfile") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract Context3DProfile(String) { var BASELINE = "baseline"; var BASELINE_CONSTRAINED = "baselineConstrained"; diff --git a/externs/air/flash/errors/SQLErrorOperation.hx b/externs/air/flash/errors/SQLErrorOperation.hx index 15e7a651c0..396ba8c237 100644 --- a/externs/air/flash/errors/SQLErrorOperation.hx +++ b/externs/air/flash/errors/SQLErrorOperation.hx @@ -1,7 +1,6 @@ package flash.errors; -@:native("flash.errors.SQLErrorOperation") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLErrorOperation(String) +@:native("flash.errors.SQLErrorOperation") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SQLErrorOperation(String) { var ANALYZE = "analyze"; var ATTACH = "attach"; diff --git a/externs/air/flash/events/TouchEventIntent.hx b/externs/air/flash/events/TouchEventIntent.hx index 19a3c6a0e6..0af83e0428 100644 --- a/externs/air/flash/events/TouchEventIntent.hx +++ b/externs/air/flash/events/TouchEventIntent.hx @@ -1,7 +1,6 @@ package flash.events; -@:native("flash.events.TouchEventIntent") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract TouchEventIntent(String) +@:native("flash.events.TouchEventIntent") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract TouchEventIntent(String) { var ERASER = "eraser"; var PEN = "pen"; diff --git a/externs/air/flash/filesystem/FileMode.hx b/externs/air/flash/filesystem/FileMode.hx index 3041db9b92..6644c1627b 100644 --- a/externs/air/flash/filesystem/FileMode.hx +++ b/externs/air/flash/filesystem/FileMode.hx @@ -1,7 +1,6 @@ package flash.filesystem; -@:native("flash.filesystem.FileMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract FileMode(String) +@:native("flash.filesystem.FileMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract FileMode(String) { var APPEND = "append"; var READ = "read"; diff --git a/externs/air/flash/media/AudioPlaybackMode.hx b/externs/air/flash/media/AudioPlaybackMode.hx index fdc31990c4..9757dadbe0 100644 --- a/externs/air/flash/media/AudioPlaybackMode.hx +++ b/externs/air/flash/media/AudioPlaybackMode.hx @@ -1,7 +1,6 @@ package flash.media; -@:native("flash.media.AudioPlaybackMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract AudioPlaybackMode(String) +@:native("flash.media.AudioPlaybackMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract AudioPlaybackMode(String) { var AMBIENT = "ambient"; var MEDIA = "media"; diff --git a/externs/air/flash/media/CameraPosition.hx b/externs/air/flash/media/CameraPosition.hx index 06184cc9ed..754d0051f9 100644 --- a/externs/air/flash/media/CameraPosition.hx +++ b/externs/air/flash/media/CameraPosition.hx @@ -1,7 +1,6 @@ package flash.media; -@:native("flash.media.CameraPosition") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract CameraPosition(String) +@:native("flash.media.CameraPosition") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract CameraPosition(String) { var BACK = "back"; var FRONT = "front"; diff --git a/externs/air/flash/media/MediaType.hx b/externs/air/flash/media/MediaType.hx index 41a10306fb..e925b08397 100644 --- a/externs/air/flash/media/MediaType.hx +++ b/externs/air/flash/media/MediaType.hx @@ -1,7 +1,6 @@ package flash.media; -@:native("flash.media.MediaType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract MediaType(String) +@:native("flash.media.MediaType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract MediaType(String) { var IMAGE = "image"; var VIDEO = "video"; diff --git a/externs/air/flash/net/IPVersion.hx b/externs/air/flash/net/IPVersion.hx index ef4a44fcf2..c9d8200955 100644 --- a/externs/air/flash/net/IPVersion.hx +++ b/externs/air/flash/net/IPVersion.hx @@ -1,7 +1,6 @@ package flash.net; -@:native("flash.net.IPVersion") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract IPVersion(String) +@:native("flash.net.IPVersion") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract IPVersion(String) { var IPV4 = "ipv4"; var IPV6 = "ipv6"; diff --git a/externs/air/flash/notifications/NotificationStyle.hx b/externs/air/flash/notifications/NotificationStyle.hx index a2a9f3fdd2..715052bf6d 100644 --- a/externs/air/flash/notifications/NotificationStyle.hx +++ b/externs/air/flash/notifications/NotificationStyle.hx @@ -1,7 +1,6 @@ package flash.notifications; -@:native("flash.notifications.NotificationStyle") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NotificationStyle(String) +@:native("flash.notifications.NotificationStyle") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract NotificationStyle(String) { var ALERT = "alert"; var BADGE = "badge"; diff --git a/externs/air/flash/printing/PaperSize.hx b/externs/air/flash/printing/PaperSize.hx index fe607d1e2a..65e60bdbfa 100644 --- a/externs/air/flash/printing/PaperSize.hx +++ b/externs/air/flash/printing/PaperSize.hx @@ -1,7 +1,6 @@ package flash.printing; -@:native("flash.printing.PaperSize") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract PaperSize(String) +@:native("flash.printing.PaperSize") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract PaperSize(String) { var A4 = "a4"; var A5 = "a5"; diff --git a/externs/air/flash/printing/PrintMethod.hx b/externs/air/flash/printing/PrintMethod.hx index 070fcfcf1c..a6f7ac873a 100644 --- a/externs/air/flash/printing/PrintMethod.hx +++ b/externs/air/flash/printing/PrintMethod.hx @@ -1,7 +1,6 @@ package flash.printing; -@:native("flash.printing.PrintMethod") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract PrintMethod(String) +@:native("flash.printing.PrintMethod") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract PrintMethod(String) { var AUTO = "auto"; var BITMAP = "bitmap"; diff --git a/externs/air/flash/security/ReferencesValidationSetting.hx b/externs/air/flash/security/ReferencesValidationSetting.hx index 08fda5c8ca..b357c649d1 100644 --- a/externs/air/flash/security/ReferencesValidationSetting.hx +++ b/externs/air/flash/security/ReferencesValidationSetting.hx @@ -1,7 +1,6 @@ package flash.security; -@:native("flash.security.ReferencesValidationSetting") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract ReferencesValidationSetting(String) +@:native("flash.security.ReferencesValidationSetting") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract ReferencesValidationSetting(String) { var NEVER = "never"; var VALID_IDENTITY = "validIdentity"; diff --git a/externs/air/flash/security/RevocationCheckSettings.hx b/externs/air/flash/security/RevocationCheckSettings.hx index 09725cea85..11365b4a09 100644 --- a/externs/air/flash/security/RevocationCheckSettings.hx +++ b/externs/air/flash/security/RevocationCheckSettings.hx @@ -1,7 +1,6 @@ package flash.security; -@:native("flash.security.RevocationCheckSettings") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract RevocationCheckSettings(String) +@:native("flash.security.RevocationCheckSettings") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract RevocationCheckSettings(String) { var ALWAYS_REQUIRED = "alwaysRequired"; var BEST_EFFORT = "bestEffort"; diff --git a/externs/air/flash/security/SignatureStatus.hx b/externs/air/flash/security/SignatureStatus.hx index f8c632599e..68e03bcaf9 100644 --- a/externs/air/flash/security/SignatureStatus.hx +++ b/externs/air/flash/security/SignatureStatus.hx @@ -1,7 +1,6 @@ package flash.security; -@:native("flash.security.SignatureStatus") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SignatureStatus(String) +@:native("flash.security.SignatureStatus") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SignatureStatus(String) { var INVALID = "invalid"; var UNKNOWN = "unknown"; diff --git a/externs/air/flash/security/SignerTrustSettings.hx b/externs/air/flash/security/SignerTrustSettings.hx index 0164a3a253..0edf890a94 100644 --- a/externs/air/flash/security/SignerTrustSettings.hx +++ b/externs/air/flash/security/SignerTrustSettings.hx @@ -1,7 +1,6 @@ package flash.security; -@:native("flash.security.SignerTrustSettings") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SignerTrustSettings(String) +@:native("flash.security.SignerTrustSettings") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SignerTrustSettings(String) { var CODE_SIGNING = "codeSigning"; var PLAYLIST_SIGNING = "playlistSigning"; diff --git a/externs/air/flash/text/AutoCapitalize.hx b/externs/air/flash/text/AutoCapitalize.hx index e0bb0169df..472737f7cd 100644 --- a/externs/air/flash/text/AutoCapitalize.hx +++ b/externs/air/flash/text/AutoCapitalize.hx @@ -1,7 +1,6 @@ package flash.text; -@:native("flash.text.AutoCapitalize") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract AutoCapitalize(String) +@:native("flash.text.AutoCapitalize") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract AutoCapitalize(String) { var ALL = "all"; var NONE = "none"; diff --git a/externs/air/flash/text/ReturnKeyLabel.hx b/externs/air/flash/text/ReturnKeyLabel.hx index 3936c1722e..573d048ee3 100644 --- a/externs/air/flash/text/ReturnKeyLabel.hx +++ b/externs/air/flash/text/ReturnKeyLabel.hx @@ -1,7 +1,6 @@ package flash.text; -@:native("flash.text.ReturnKeyLabel") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract ReturnKeyLabel(String) +@:native("flash.text.ReturnKeyLabel") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract ReturnKeyLabel(String) { var DEFAULT = "default"; var DONE = "done"; diff --git a/externs/air/flash/text/SoftKeyboardType.hx b/externs/air/flash/text/SoftKeyboardType.hx index 3a9f747dc4..a6ff23fddb 100644 --- a/externs/air/flash/text/SoftKeyboardType.hx +++ b/externs/air/flash/text/SoftKeyboardType.hx @@ -1,7 +1,6 @@ package flash.text; -@:native("flash.text.SoftKeyboardType") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SoftKeyboardType(String) +@:native("flash.text.SoftKeyboardType") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract SoftKeyboardType(String) { var CONTACT = "contact"; var DEFAULT = "default"; diff --git a/externs/air/flash/text/StageTextClearButtonMode.hx b/externs/air/flash/text/StageTextClearButtonMode.hx index 21f09ecb2b..ade3888cb0 100644 --- a/externs/air/flash/text/StageTextClearButtonMode.hx +++ b/externs/air/flash/text/StageTextClearButtonMode.hx @@ -1,7 +1,6 @@ package flash.text; -@:native("flash.text.StageTextClearButtonMode") -#if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageTextClearButtonMode(String) +@:native("flash.text.StageTextClearButtonMode") #if (haxe_ver >= 4.0) extern enum #else @:extern @:enum #end abstract StageTextClearButtonMode(String) { var ALWAYS = "always"; var NEVER = "never"; diff --git a/externs/air/sys/io/FileInput.hx b/externs/air/sys/io/FileInput.hx index 93e2f3b19d..7e3558ed28 100644 --- a/externs/air/sys/io/FileInput.hx +++ b/externs/air/sys/io/FileInput.hx @@ -34,9 +34,9 @@ class FileInput extends haxe.io.Input switch (pos) { case SeekBegin: - // this.pos = p; + // this.pos = p; case SeekEnd: - // this.pos = cast Fs.fstatSync(fd).size + p; + // this.pos = cast Fs.fstatSync(fd).size + p; case SeekCur: // this.pos += p; } diff --git a/externs/air/sys/io/FileOutput.hx b/externs/air/sys/io/FileOutput.hx index cdd3ba2414..e0e96e9d57 100644 --- a/externs/air/sys/io/FileOutput.hx +++ b/externs/air/sys/io/FileOutput.hx @@ -31,9 +31,9 @@ class FileOutput extends haxe.io.Output switch (pos) { case SeekBegin: - // this.pos = p; + // this.pos = p; case SeekEnd: - // this.pos = cast Fs.fstatSync(fd).size + p; + // this.pos = cast Fs.fstatSync(fd).size + p; case SeekCur: // this.pos += p; } diff --git a/src/lime/_internal/backend/air/AIRWindow.hx b/src/lime/_internal/backend/air/AIRWindow.hx index 0c5e022fda..195d78fbc4 100644 --- a/src/lime/_internal/backend/air/AIRWindow.hx +++ b/src/lime/_internal/backend/air/AIRWindow.hx @@ -187,7 +187,8 @@ class AIRWindow extends FlashWindow if (parent.application.window == parent) { var newDeviceOrientation:Orientation = UNKNOWN; - switch (parent.stage.deviceOrientation) { + switch (parent.stage.deviceOrientation) + { case DEFAULT: newDeviceOrientation = PORTRAIT; case UPSIDE_DOWN: @@ -202,7 +203,8 @@ class AIRWindow extends FlashWindow parent.application.onDeviceOrientationChange.dispatch(newDeviceOrientation); } var newDisplayOrientation:Orientation = UNKNOWN; - switch (event.afterOrientation) { + switch (event.afterOrientation) + { case DEFAULT: newDisplayOrientation = PORTRAIT; case UPSIDE_DOWN: diff --git a/src/lime/_internal/backend/emscripten/EmscriptenFetch.hx b/src/lime/_internal/backend/emscripten/EmscriptenFetch.hx index 91fc89814e..8777ae7134 100644 --- a/src/lime/_internal/backend/emscripten/EmscriptenFetch.hx +++ b/src/lime/_internal/backend/emscripten/EmscriptenFetch.hx @@ -7,44 +7,46 @@ import cpp.ConstCharStar; @:include("emscripten/fetch.h") @:native -extern class EmscriptenFetch { +extern class EmscriptenFetch +{ + @:native("emscripten_fetch_attr_init") + public static function emscripten_fetch_attr_init(attr:Pointer):Void; - @:native("emscripten_fetch_attr_init") - public static function emscripten_fetch_attr_init(attr:Pointer):Void; + @:native("emscripten_fetch") + public static function emscripten_fetch(attr:Pointer, url:ConstCharStar):Pointer; - @:native("emscripten_fetch") - public static function emscripten_fetch(attr:Pointer, url:ConstCharStar):Pointer; - - @:native("emscripten_fetch_close") - public static function emscripten_fetch_close(fetch:Pointer):Void; + @:native("emscripten_fetch_close") + public static function emscripten_fetch_close(fetch:Pointer):Void; } @:include("emscripten/fetch.h") @:native("emscripten_fetch_attr_t") @:structAccess @:unreflective -extern class EmscriptenFetchAttrType { - public var requestMethod:ConstCharStar; - public var onsuccess:Star->Void; - public var onprogress:Star->Void; - public var onerror:Star->Void; - public var attributes:Int; - public var userData:Star; +extern class EmscriptenFetchAttrType +{ + public var requestMethod:ConstCharStar; + public var onsuccess:Star->Void; + public var onprogress:Star->Void; + public var onerror:Star->Void; + public var attributes:Int; + public var userData:Star; } @:include("emscripten/fetch.h") @:native("emscripten_fetch_t") @:structAccess -extern class EmscriptenFetchType { - public var id:Int; - public var numBytes:Int; - public var dataOffset:Int; - public var totalBytes:Int; - public var url:ConstCharStar; - public var readyState:Int; - public var status:Int; - public var statusText:ConstCharStar; - public var data:Pointer; - public var userData:Star; +extern class EmscriptenFetchType +{ + public var id:Int; + public var numBytes:Int; + public var dataOffset:Int; + public var totalBytes:Int; + public var url:ConstCharStar; + public var readyState:Int; + public var status:Int; + public var statusText:ConstCharStar; + public var data:Pointer; + public var userData:Star; } -#end \ No newline at end of file +#end diff --git a/src/lime/_internal/backend/emscripten/EmscriptenHTTPRequest.hx b/src/lime/_internal/backend/emscripten/EmscriptenHTTPRequest.hx index 435afeff94..bb726fa0a8 100644 --- a/src/lime/_internal/backend/emscripten/EmscriptenHTTPRequest.hx +++ b/src/lime/_internal/backend/emscripten/EmscriptenHTTPRequest.hx @@ -16,238 +16,237 @@ import lime.net.HTTPRequest._HTTPRequestErrorResponse; @:access(lime.graphics.Image) class EmscriptenHTTPRequest { - private static var fetchId:Int = 0; - private static var activeFetches = new Map(); - - private var binary:Bool; - private var parent:_IHTTPRequest; - private var currentFetchId:Int = -1; - - public function new() - { - } - - public function cancel():Void - { - if (currentFetchId >= 0 && activeFetches.exists(currentFetchId)) - { - var context = activeFetches.get(currentFetchId); - if (context != null && context.fetchPtr != null) - { - EmscriptenFetch.emscripten_fetch_close(context.fetchPtr); - } - activeFetches.remove(currentFetchId); - currentFetchId = -1; - } - } - - public function init(parent:_IHTTPRequest):Void - { - this.parent = parent; - } - - public function loadData(uri:String):Future - { - var promise = new Promise(); - binary = true; - __load(uri, promise, LoadType.BINARY); - return promise.future; - } - - public function loadText(uri:String):Future - { - var promise = new Promise(); - binary = false; - __load(uri, promise, LoadType.TEXT); - return promise.future; - } - - private function __load(uri:String, promise:Dynamic, loadType:LoadType):Void - { - var id = fetchId++; - currentFetchId = id; - - var context:FetchContext = { - id: id, - promise: promise, - parent: parent, - loadType: loadType, - binary: binary, - fetchPtr: null - }; - - activeFetches.set(id, context); - - var attr:EmscriptenFetchAttrType = untyped __cpp__("{}"); - var attrPtr:Pointer = Pointer.addressOf(attr); - EmscriptenFetch.emscripten_fetch_attr_init(attrPtr); - - // Set request method - var method = parent.method != null ? Std.string(parent.method) : "GET"; - untyped __cpp__('strcpy({0}, {1})', attr.requestMethod, method); - - // Set callbacks - attr.onsuccess = untyped __cpp__("onFetchSuccess"); - attr.onprogress = untyped __cpp__("onFetchProgress"); - attr.onerror = untyped __cpp__("onFetchError"); - - // Store fetch ID in userData - var idPointer:Star = untyped __cpp__('(int*)malloc(sizeof(int))'); - untyped __cpp__('*{0} = {1}', idPointer, id); - attr.userData = cast idPointer; - - // Set EMSCRIPTEN_FETCH_LOAD_TO_MEMORY - attr.attributes = 1; - - // Start fetch - var fetchPtr = EmscriptenFetch.emscripten_fetch(attrPtr, uri); - context.fetchPtr = fetchPtr; - } - - @:keep - private static function onFetchSuccess(fetchPtr:Star):Void - { - var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; - var idPointer:Star = cast fetch.userData; - var id:Int = untyped __cpp__('*(int*){0}', idPointer); - - cpp.Native.free(idPointer); - fetch.userData = null; - - if (!activeFetches.exists(id)) - { - EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); - return; - } - - var context = activeFetches.get(id); - activeFetches.remove(id); - if(context == null) - trace("EmscriptenHTTPRequest.onFetchSuccess: context is null"); - - // Process response - if (context.parent.enableResponseHeaders) - { - context.parent.responseHeaders = []; - // Note: Emscripten Fetch API has limited header access - // You may need to parse headers from fetch.statusText if available - } - - context.parent.responseStatus = fetch.status; - - // Create bytes from fetch data - var bytes:Bytes = null; - if (fetch.numBytes > 0 && fetch.data != null) - { - bytes = Bytes.ofData(cast fetch.data.toUnmanagedArray(fetch.numBytes).copy()); - } - else - { - bytes = Bytes.alloc(0); - } - - EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); - - // Complete promise based on load type - if (fetch.status >= 200 && fetch.status < 400) - { - switch (context.loadType) - { - case LoadType.BINARY: - cast(context.promise, Promise).complete(bytes); - - case LoadType.TEXT: - var text = bytes.getString(0, bytes.length, UTF8); - cast(context.promise, Promise).complete(text); - - case LoadType.IMAGE: - // For images, we need to decode the bytes - var img = new Image(); - img.__fromBytes(bytes, function(image) - { - cast(context.promise, Promise).complete(image); - }); - } - } - else - { - var errorResponse:_HTTPRequestErrorResponse; - if(context.loadType == LoadType.BINARY) { - errorResponse = new _HTTPRequestErrorResponse(fetch.status, bytes); - cast(context.promise, Promise).error(errorResponse); - }else { - errorResponse = new _HTTPRequestErrorResponse(fetch.status, bytes.getString(0, bytes.length, UTF8)); - cast(context.promise, Promise).error(errorResponse); - } - } - } - - @:keep - private static function onFetchProgress(fetchPtr:Star):Void - { - var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; - var idPointer:Star = cast fetch.userData; - var id:Int = untyped __cpp__('*(int*){0}', idPointer); - - if (activeFetches.exists(id)) - { - var context = activeFetches.get(id); - if (fetch.totalBytes > 0) - { - if(context.loadType == LoadType.BINARY) - cast(context.promise, Promise).progress(fetch.dataOffset + fetch.numBytes, fetch.totalBytes); - else if(context.loadType == LoadType.TEXT) - cast(context.promise, Promise).progress(fetch.dataOffset + fetch.numBytes, fetch.totalBytes); - } - } - } - - @:keep - private static function onFetchError(fetchPtr:Star):Void - { - var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; - var idPointer:Star = cast fetch.userData; - var id:Int = untyped __cpp__('*(int*){0}', idPointer); - - cpp.Native.free(idPointer); - - if (!activeFetches.exists(id)) - { - EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); - return; - } - - var context = activeFetches.get(id); - activeFetches.remove(id); - - context.parent.responseStatus = fetch.status; - - EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); - - var errorResponse = new _HTTPRequestErrorResponse(fetch.status, null); - if(context.loadType == LoadType.BINARY) - cast(context.promise, Promise).error(errorResponse); - else - cast(context.promise, Promise).error(errorResponse); - } + private static var fetchId:Int = 0; + private static var activeFetches = new Map(); + + private var binary:Bool; + private var parent:_IHTTPRequest; + private var currentFetchId:Int = -1; + + public function new() {} + + public function cancel():Void + { + if (currentFetchId >= 0 && activeFetches.exists(currentFetchId)) + { + var context = activeFetches.get(currentFetchId); + if (context != null && context.fetchPtr != null) + { + EmscriptenFetch.emscripten_fetch_close(context.fetchPtr); + } + activeFetches.remove(currentFetchId); + currentFetchId = -1; + } + } + + public function init(parent:_IHTTPRequest):Void + { + this.parent = parent; + } + + public function loadData(uri:String):Future + { + var promise = new Promise(); + binary = true; + __load(uri, promise, LoadType.BINARY); + return promise.future; + } + + public function loadText(uri:String):Future + { + var promise = new Promise(); + binary = false; + __load(uri, promise, LoadType.TEXT); + return promise.future; + } + + private function __load(uri:String, promise:Dynamic, loadType:LoadType):Void + { + var id = fetchId++; + currentFetchId = id; + + var context:FetchContext = + { + id: id, + promise: promise, + parent: parent, + loadType: loadType, + binary: binary, + fetchPtr: null + }; + + activeFetches.set(id, context); + + var attr:EmscriptenFetchAttrType = untyped __cpp__("{}"); + var attrPtr:Pointer = Pointer.addressOf(attr); + EmscriptenFetch.emscripten_fetch_attr_init(attrPtr); + + // Set request method + var method = parent.method != null ? Std.string(parent.method) : "GET"; + untyped __cpp__('strcpy({0}, {1})', attr.requestMethod, method); + + // Set callbacks + attr.onsuccess = untyped __cpp__("onFetchSuccess"); + attr.onprogress = untyped __cpp__("onFetchProgress"); + attr.onerror = untyped __cpp__("onFetchError"); + + // Store fetch ID in userData + var idPointer:Star = untyped __cpp__('(int*)malloc(sizeof(int))'); + untyped __cpp__('*{0} = {1}', idPointer, id); + attr.userData = cast idPointer; + + // Set EMSCRIPTEN_FETCH_LOAD_TO_MEMORY + attr.attributes = 1; + + // Start fetch + var fetchPtr = EmscriptenFetch.emscripten_fetch(attrPtr, uri); + context.fetchPtr = fetchPtr; + } + + @:keep + private static function onFetchSuccess(fetchPtr:Star):Void + { + var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; + var idPointer:Star = cast fetch.userData; + var id:Int = untyped __cpp__('*(int*){0}', idPointer); + + cpp.Native.free(idPointer); + fetch.userData = null; + + if (!activeFetches.exists(id)) + { + EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); + return; + } + + var context = activeFetches.get(id); + activeFetches.remove(id); + if (context == null) trace("EmscriptenHTTPRequest.onFetchSuccess: context is null"); + + // Process response + if (context.parent.enableResponseHeaders) + { + context.parent.responseHeaders = []; + // Note: Emscripten Fetch API has limited header access + // You may need to parse headers from fetch.statusText if available + } + + context.parent.responseStatus = fetch.status; + + // Create bytes from fetch data + var bytes:Bytes = null; + if (fetch.numBytes > 0 && fetch.data != null) + { + bytes = Bytes.ofData(cast fetch.data.toUnmanagedArray(fetch.numBytes).copy()); + } + else + { + bytes = Bytes.alloc(0); + } + + EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); + + // Complete promise based on load type + if (fetch.status >= 200 && fetch.status < 400) + { + switch (context.loadType) + { + case LoadType.BINARY: + cast(context.promise, Promise).complete(bytes); + + case LoadType.TEXT: + var text = bytes.getString(0, bytes.length, UTF8); + cast(context.promise, Promise).complete(text); + + case LoadType.IMAGE: + // For images, we need to decode the bytes + var img = new Image(); + img.__fromBytes(bytes, function(image) + { + cast(context.promise, Promise).complete(image); + }); + } + } + else + { + var errorResponse:_HTTPRequestErrorResponse; + if (context.loadType == LoadType.BINARY) + { + errorResponse = new _HTTPRequestErrorResponse(fetch.status, bytes); + cast(context.promise, Promise).error(errorResponse); + } + else + { + errorResponse = new _HTTPRequestErrorResponse(fetch.status, bytes.getString(0, bytes.length, UTF8)); + cast(context.promise, Promise).error(errorResponse); + } + } + } + + @:keep + private static function onFetchProgress(fetchPtr:Star):Void + { + var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; + var idPointer:Star = cast fetch.userData; + var id:Int = untyped __cpp__('*(int*){0}', idPointer); + + if (activeFetches.exists(id)) + { + var context = activeFetches.get(id); + if (fetch.totalBytes > 0) + { + if (context.loadType == LoadType.BINARY) cast(context.promise, Promise).progress(fetch.dataOffset + fetch.numBytes, fetch.totalBytes); + else if (context.loadType == LoadType.TEXT) cast(context.promise, Promise).progress(fetch.dataOffset + fetch.numBytes, + fetch.totalBytes); + } + } + } + + @:keep + private static function onFetchError(fetchPtr:Star):Void + { + var fetch:EmscriptenFetchType = Pointer.fromStar(fetchPtr).value; + var idPointer:Star = cast fetch.userData; + var id:Int = untyped __cpp__('*(int*){0}', idPointer); + + cpp.Native.free(idPointer); + + if (!activeFetches.exists(id)) + { + EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); + return; + } + + var context = activeFetches.get(id); + activeFetches.remove(id); + + context.parent.responseStatus = fetch.status; + + EmscriptenFetch.emscripten_fetch_close(Pointer.fromStar(fetchPtr)); + + var errorResponse = new _HTTPRequestErrorResponse(fetch.status, null); + if (context.loadType == LoadType.BINARY) cast(context.promise, Promise).error(errorResponse); + else + cast(context.promise, Promise).error(errorResponse); + } } @:dox(hide) enum LoadType { - BINARY; - TEXT; - IMAGE; + BINARY; + TEXT; + IMAGE; } @:dox(hide) typedef FetchContext = { - var id:Int; - var promise:Dynamic; - var parent:_IHTTPRequest; - var loadType:LoadType; - var binary:Bool; - var fetchPtr:Pointer; + var id:Int; + var promise:Dynamic; + var parent:_IHTTPRequest; + var loadType:LoadType; + var binary:Bool; + var fetchPtr:Pointer; } -#end \ No newline at end of file +#end diff --git a/src/lime/_internal/backend/flash/FlashHTTPRequest.hx b/src/lime/_internal/backend/flash/FlashHTTPRequest.hx index 67861d810a..e44164755f 100644 --- a/src/lime/_internal/backend/flash/FlashHTTPRequest.hx +++ b/src/lime/_internal/backend/flash/FlashHTTPRequest.hx @@ -174,4 +174,4 @@ class FlashHTTPRequest urlLoader.load(urlRequest); return promise.future; } -} \ No newline at end of file +} diff --git a/src/lime/_internal/backend/flash/FlashWindow.hx b/src/lime/_internal/backend/flash/FlashWindow.hx index 1935a11208..ad9df272bd 100644 --- a/src/lime/_internal/backend/flash/FlashWindow.hx +++ b/src/lime/_internal/backend/flash/FlashWindow.hx @@ -225,8 +225,7 @@ class FlashWindow "middleMouseMove", "middleMouseUp" #if ((!openfl && !disable_flash_right_click) - || enable_flash_right_click), "rightMouseDown", "rightMouseMove", "rightMouseUp" - #end + || enable_flash_right_click), "rightMouseDown", "rightMouseMove", "rightMouseUp" #end ]; for (event in events) diff --git a/src/lime/_internal/backend/html5/HTML5AudioSource.hx b/src/lime/_internal/backend/html5/HTML5AudioSource.hx index f2b9fe80b2..a898c7ad16 100644 --- a/src/lime/_internal/backend/html5/HTML5AudioSource.hx +++ b/src/lime/_internal/backend/html5/HTML5AudioSource.hx @@ -261,7 +261,8 @@ class HTML5AudioSource position.w = value.w; #if lime_howlerjs - if (parent.buffer != null && parent.buffer.__srcHowl != null && parent.buffer.__srcHowl.pos != null) parent.buffer.__srcHowl.pos(position.x, position.y, position.z, id); + if (parent.buffer != null && parent.buffer.__srcHowl != null && parent.buffer.__srcHowl.pos != null) parent.buffer.__srcHowl.pos(position.x, + position.y, position.z, id); // There are more settings to the position of the sound on the "pannerAttr()" function of howler. Maybe somebody who understands sound should look into it? #end diff --git a/src/lime/_internal/backend/html5/HTML5HTTPRequest.hx b/src/lime/_internal/backend/html5/HTML5HTTPRequest.hx index 4b94560e66..547d2f348e 100644 --- a/src/lime/_internal/backend/html5/HTML5HTTPRequest.hx +++ b/src/lime/_internal/backend/html5/HTML5HTTPRequest.hx @@ -64,8 +64,7 @@ class HTML5HTTPRequest if (parent.method == POST) { - if(request.upload != null) - request.upload.addEventListener("progress", progress, false); + if (request.upload != null) request.upload.addEventListener("progress", progress, false); } else { diff --git a/src/lime/_internal/backend/html5/HTML5Thread.hx b/src/lime/_internal/backend/html5/HTML5Thread.hx index 9f744e59e1..02caf2ca0c 100644 --- a/src/lime/_internal/backend/html5/HTML5Thread.hx +++ b/src/lime/_internal/backend/html5/HTML5Thread.hx @@ -1,7 +1,6 @@ package lime._internal.backend.html5; import lime.app.Event; - #if macro import haxe.macro.Context; import haxe.macro.Expr; @@ -30,7 +29,8 @@ import lime.app.Application; /** Emulates much of the `sys.thread.Thread` API using web workers. **/ -class HTML5Thread { +class HTML5Thread +{ private static var __current:HTML5Thread = new HTML5Thread(Lib.global.location.href); private static var __isWorker:Bool #if !macro = #if !haxe4 untyped __js__ #else Syntax.code #end ('typeof window == "undefined"') #end; private static var __messages:List = new List(); @@ -80,8 +80,7 @@ class HTML5Thread { #if !macro // Find the URL of the primary JS file. var url:URL = new URL(__current.__href); - url.pathname = url.pathname.substr(0, url.pathname.lastIndexOf("/") + 1) - + Application.current.meta["file"] + ".js"; + url.pathname = url.pathname.substr(0, url.pathname.lastIndexOf("/") + 1) + Application.current.meta["file"] + ".js"; // Use the hash to distinguish workers. if (url.hash.length > 0) url.hash += "_"; @@ -108,9 +107,9 @@ class HTML5Thread { private static inline function zeroDelay():Promise { return new Promise(function(resolve, _):Void - { - js.Lib.global.setTimeout(resolve); - }); + { + js.Lib.global.setTimeout(resolve); + }); } #end @@ -128,8 +127,8 @@ class HTML5Thread { // suspended, so we must insert `await` even if `block` is false. // TODO: find a more efficient way to read messages. var zeroDelayExpr:Expr = macro @:privateAccess - $jsCode("await {0}", lime._internal.backend.html5.HTML5Thread.zeroDelay()) - .then(function(_) return lime._internal.backend.html5.HTML5Thread.__messages.pop()); + $jsCode("await {0}", lime._internal.backend.html5.HTML5Thread.zeroDelay()).then(function(_) return + lime._internal.backend.html5.HTML5Thread.__messages.pop()); switch (block.expr) { @@ -138,15 +137,18 @@ class HTML5Thread { default: return macro if ($block && @:privateAccess lime._internal.backend.html5.HTML5Thread.__messages.isEmpty()) { - $jsCode("await {0}", new #if haxe4 js.lib.Promise #else js.Promise #end + $jsCode("await {0}", new + #if haxe4 + js.lib.Promise + #else + js.Promise + #end (function(resolve, _):Void { @:privateAccess lime._internal.backend.html5.HTML5Thread.__resolveMethods.add(resolve); - } - )); + })); } - else - $zeroDelayExpr; + else $zeroDelayExpr; } } @@ -294,18 +296,18 @@ abstract WorkFunction(WorkFunctionData) from Wor as the `initialExpr`. For instance, `array[i].foo.bar` will result in `chain == ["foo", "bar"]` and `initialExpr == array[i]`. **/ - private static function parseFieldChain(chain:Expr):{ chain:Array, ?initialExpr:Expr } + private static function parseFieldChain(chain:Expr):{chain:Array, ?initialExpr:Expr} { - switch(chain.expr) + switch (chain.expr) { case EConst(CIdent(ident)): - return { chain: [ident] }; + return {chain: [ident]}; case EField(e, field): var out = parseFieldChain(e); out.chain.push(field); return out; default: - return { chain: [], initialExpr: chain }; + return {chain: [], initialExpr: chain}; } } #end @@ -314,9 +316,10 @@ abstract WorkFunction(WorkFunctionData) from Wor @:noCompletion @:dox(hide) #if !macro @:from #end public static #if !macro macro #end function fromFunction(func:ExprOf) { - var defaultOutput:Expr = macro { - func: $func - }; + var defaultOutput:Expr = macro + { + func: $func + }; if (!Context.defined("lime-threads")) { @@ -343,11 +346,12 @@ abstract WorkFunction(WorkFunctionData) from Wor var classPath:String = matcher.matched(1); var functionName:String = matcher.matched(2); - return macro { - func: $func, - classPath: $v{classPath}, - functionName: $v{functionName} - }; + return macro + { + func: $func, + classPath: $v{classPath}, + functionName: $v{functionName} + }; } } @@ -416,7 +420,7 @@ abstract WorkFunction(WorkFunctionData) from Wor else { #if !macro - this.sourceCode = (cast this.func #if haxe4 :Function #end).toString(); + this.sourceCode = (cast this.func #if haxe4 : Function #end).toString(); if (this.sourceCode.indexOf("[native code]") < 0) { // All set. @@ -456,7 +460,8 @@ abstract WorkFunction(WorkFunctionData) from Wor Stores the class path and function name of a function, so that it can be found again in the background thread. **/ -typedef WorkFunctionData = { +typedef WorkFunctionData = +{ @:optional var classPath:String; @:optional var functionName:String; @:optional var sourceCode:String; @@ -475,17 +480,15 @@ abstract Message(Dynamic) from Dynamic to Dynamic private static inline function skip(object:Dynamic):Bool { // Skip `null` for obvious reasons. - return object == null - // No need to preserve a primitive type. - || !#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (object, Object) - // Objects with this field have been deliberately excluded. - || Reflect.field(object, SKIP_FIELD) == true - // A `Uint8Array` (the type used by `haxe.io.Bytes`) can have - // thousands or millions of fields, which can take entire seconds to - // enumerate. This also applies to `Int8Array`, `Float64Array`, etc. - || object.byteLength != null && object.byteOffset != null - && object.buffer != null - && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (object.buffer, #if haxe4 js.lib.ArrayBuffer #else js.html.ArrayBuffer #end); + return object == null // No need to preserve a primitive type. + || !#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (object, Object) // Objects with this field have been deliberately excluded. + || Reflect.field(object, SKIP_FIELD) == true // A `Uint8Array` (the type used by `haxe.io.Bytes`) can have + // thousands or millions of fields, which can take entire seconds to + // enumerate. This also applies to `Int8Array`, `Float64Array`, etc. + || object.byteLength != null + && object.byteOffset != null + && object.buffer != null + && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (object.buffer, #if haxe4 js.lib.ArrayBuffer #else js.html.ArrayBuffer #end); } #end @@ -556,7 +559,7 @@ abstract Message(Dynamic) from Dynamic to Dynamic // Recurse. for (child in Object.values(this)) { - (child:Message).preserveClasses(); + (child : Message).preserveClasses(); } #end } @@ -600,9 +603,8 @@ abstract Message(Dynamic) from Dynamic to Dynamic { try { - Object.setPrototypeOf(this, - #if haxe4 Syntax.code #else untyped __js__ #end - ("$hxClasses[{0}].prototype", Reflect.field(this, PROTOTYPE_FIELD))); + Object.setPrototypeOf(this, #if haxe4 Syntax.code #else untyped __js__ #end ("$hxClasses[{0}].prototype", Reflect.field(this, + PROTOTYPE_FIELD))); } catch (e:Dynamic) {} } @@ -610,7 +612,7 @@ abstract Message(Dynamic) from Dynamic to Dynamic // Recurse. for (child in Object.values(this)) { - (child:Message).restoreClasses(flag); + (child : Message).restoreClasses(flag); } #end } @@ -620,13 +622,15 @@ abstract Message(Dynamic) from Dynamic to Dynamic typedef Worker = Dynamic; typedef URL = Dynamic; class Object {} + class Browser { public static var window:Dynamic; } + class Lib { - public static var global:Dynamic = { location: {} }; + public static var global:Dynamic = {location: {}}; } #end @@ -641,15 +645,15 @@ class Lib **/ // Mozilla uses "transferable" and "transferrable" interchangeably, but the HTML // specification only uses the former. + @:forward -abstract Transferable(Dynamic) #if macro from Dynamic - #else from lime.utils.ArrayBuffer from js.html.MessagePort from js.html.ImageBitmap #end -{ -} +abstract Transferable(Dynamic) #if macro from Dynamic #else from lime.utils.ArrayBuffer from js.html.MessagePort from js.html.ImageBitmap #end +{} #if (!haxe4 && !macro) @:native("Object") -extern class Object { +extern class Object +{ static function setPrototypeOf(obj:T, prototype:Null<{}>):T; @:pure static function values(obj:{}):Array; static var prototype(default, never):Dynamic; diff --git a/src/lime/_internal/backend/native/NativeAudioSource.hx b/src/lime/_internal/backend/native/NativeAudioSource.hx index e881c5166e..51c587d73b 100644 --- a/src/lime/_internal/backend/native/NativeAudioSource.hx +++ b/src/lime/_internal/backend/native/NativeAudioSource.hx @@ -253,7 +253,8 @@ class NativeAudioSource #if lime_openalsoft if (hasDirectChannelsExt == null) { - hasDirectChannelsExt = AL.isExtensionPresent("AL_SOFT_direct_channels") && AL.isExtensionPresent("AL_SOFT_direct_channels_remix"); + hasDirectChannelsExt = AL.isExtensionPresent("AL_SOFT_direct_channels") + && AL.isExtensionPresent("AL_SOFT_direct_channels_remix"); } if (hasDirectChannelsExt) @@ -1015,7 +1016,12 @@ class NativeAudioSource refillBuffers(); - if (playing && timer == null && streamExhausted && queuedBufferCount == 0 && handle != null && AL.getSourcei(handle, AL.SOURCE_STATE) != AL.PLAYING) + if (playing + && timer == null + && streamExhausted + && queuedBufferCount == 0 + && handle != null + && AL.getSourcei(handle, AL.SOURCE_STATE) != AL.PLAYING) { if (length == null && parent.buffer.__srcSDLSoundDuration <= 0) { @@ -1085,9 +1091,9 @@ class NativeAudioSource { // `setCurrentTime()` has side effects and is never safe to skip. /* if (value == getCurrentTime()) - { - return value; - } */ + { + return value; + }*/ if (handle != null) { diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index bbb081e3d8..906d38d1fe 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -400,14 +400,13 @@ class NativeCFFI @: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_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_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; @@ -415,23 +414,23 @@ class NativeCFFI @: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_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_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_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_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_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_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; @@ -439,36 +438,36 @@ class NativeCFFI @: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_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_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_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_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_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_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_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_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_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; @@ -482,15 +481,14 @@ class NativeCFFI @: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_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; + 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; @@ -510,58 +508,57 @@ class NativeCFFI @: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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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; @@ -570,8 +567,8 @@ class NativeCFFI 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; + 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; @@ -579,16 +576,15 @@ class NativeCFFI @: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(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_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_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; @@ -602,8 +598,8 @@ class NativeCFFI @: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(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; @@ -611,29 +607,26 @@ class NativeCFFI @: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_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_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_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_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_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; @@ -741,16 +734,16 @@ class NativeCFFI "lime_sdl_sound_get_info_from_file", "so", false)); private static var lime_sdl_sound_stream_from_bytes = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_from_bytes", "oo", false)); - private static var lime_sdl_sound_stream_from_file = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", - "lime_sdl_sound_stream_from_file", "so", false)); + private static var lime_sdl_sound_stream_from_file = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_from_file", + "so", false)); private static var lime_sdl_sound_stream_read = new cpp.Callablecpp.Object->Int->Int>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_read", "ooii", false)); - private static var lime_sdl_sound_stream_rewind = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", - "lime_sdl_sound_stream_rewind", "ob", false)); - private static var lime_sdl_sound_stream_seek = new cpp.CallableInt->Bool>(cpp.Prime._loadPrime("lime", - "lime_sdl_sound_stream_seek", "oib", false)); - private static var lime_sdl_sound_stream_clear = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", - "lime_sdl_sound_stream_clear", "ov", false)); + private static var lime_sdl_sound_stream_rewind = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_rewind", "ob", + false)); + private static var lime_sdl_sound_stream_seek = new cpp.CallableInt->Bool>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_seek", "oib", + false)); + private static var lime_sdl_sound_stream_clear = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_sdl_sound_stream_clear", "ov", + false)); private static var lime_bytes_from_data_pointer = new cpp.CallableInt->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_bytes_from_data_pointer", "dioo", false)); private static var lime_bytes_get_data_pointer = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", "lime_bytes_get_data_pointer", "od", @@ -787,8 +780,7 @@ class NativeCFFI "lime_file_watcher_add_directory", "oobo", false)); private static var lime_file_watcher_remove_directory = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_file_watcher_remove_directory", "oov", false)); - private static var lime_file_watcher_update = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_file_watcher_update", "ov", - false)); + private static var lime_file_watcher_update = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_file_watcher_update", "ov", false)); private static var lime_font_get_ascender = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_ascender", "oi", false)); private static var lime_font_get_descender = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_descender", "oi", false)); private static var lime_font_get_family_name = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_get_family_name", "oo", @@ -805,10 +797,10 @@ class NativeCFFI "oi", false)); private static var lime_font_get_underline_thickness = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_underline_thickness", "oi", false)); - private static var lime_font_get_strikethrough_position = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_strikethrough_position", - "oi", false)); - private static var lime_font_get_strikethrough_thickness = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_strikethrough_thickness", - "oi", false)); + private static var lime_font_get_strikethrough_position = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", + "lime_font_get_strikethrough_position", "oi", false)); + private static var lime_font_get_strikethrough_thickness = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", + "lime_font_get_strikethrough_thickness", "oi", false)); private static var lime_font_get_units_per_em = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_units_per_em", "oi", false)); private static var lime_font_load = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_load", "oo", false)); private static var lime_font_load_bytes = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_load_bytes", "oo", false)); @@ -885,10 +877,8 @@ class NativeCFFI "lime_jpeg_decode_bytes", "oboo", false)); private static var lime_jpeg_decode_file = new cpp.CallableBool->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_jpeg_decode_file", "sboo", false)); - private static var lime_key_code_from_scan_code = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_key_code_from_scan_code", - "ii", false)); - private static var lime_key_code_to_scan_code = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_key_code_to_scan_code", - "ii", false)); + private static var lime_key_code_from_scan_code = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_key_code_from_scan_code", "ii", false)); + private static var lime_key_code_to_scan_code = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_key_code_to_scan_code", "ii", false)); private static var lime_key_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_key_event_manager_register", "oov", false)); private static var lime_lzma_compress = new cpp.Callablecpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_lzma_compress", "ooo", @@ -921,7 +911,8 @@ class NativeCFFI private static var lime_system_get_display = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_display", "io", false)); private static var lime_system_get_ios_tablet = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_system_get_ios_tablet", "b", false)); private static var lime_system_get_num_displays = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_system_get_num_displays", "i", false)); - private static var lime_system_get_device_orientation = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_system_get_device_orientation", "i", false)); + private static var lime_system_get_device_orientation = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_system_get_device_orientation", + "i", false)); private static var lime_system_get_platform_label = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_platform_label", "o", false)); private static var lime_system_get_platform_name = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_system_get_platform_name", "o", @@ -938,8 +929,7 @@ class NativeCFFI private static var lime_window_alert = new cpp.CallableString->String->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_alert", "ossv", false)); private static var lime_window_close = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_close", "ov", false)); - private static var lime_window_context_flip = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_context_flip", "ov", - false)); + private static var lime_window_context_flip = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_context_flip", "ov", false)); private static var lime_window_context_lock = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_context_lock", "oo", false)); private static var lime_window_context_make_current = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", @@ -959,8 +949,7 @@ class NativeCFFI "oo", false)); private static var lime_window_get_height = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_height", "oi", false)); private static var lime_window_get_id = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_window_get_id", "oi", false)); - private static var lime_window_get_mouse_lock = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_window_get_mouse_lock", "ob", - false)); + private static var lime_window_get_mouse_lock = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_window_get_mouse_lock", "ob", false)); private static var lime_window_get_opacity = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", "lime_window_get_opacity", "od", false)); 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", @@ -971,10 +960,10 @@ class NativeCFFI "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_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", @@ -994,10 +983,10 @@ class NativeCFFI "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_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", @@ -1018,40 +1007,40 @@ class NativeCFFI "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_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_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_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_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_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", @@ -1060,119 +1049,118 @@ class NativeCFFI "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_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_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_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_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_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_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_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_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_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_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_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_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)); + 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_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_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", @@ -1181,20 +1169,19 @@ class NativeCFFI "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_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)); private static var lime_window_move = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_move", "oiiv", false)); private static var lime_window_read_pixels = new cpp.Callablecpp.Object->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_read_pixels", "oooo", false)); - private static var lime_window_resize = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_resize", "oiiv", - false)); - private static var lime_window_set_minimum_size = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_set_minimum_size", "oiiv", - false)); - private static var lime_window_set_maximum_size = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_set_maximum_size", "oiiv", - false)); + private static var lime_window_resize = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_resize", "oiiv", false)); + private static var lime_window_set_minimum_size = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_window_set_minimum_size", "oiiv", false)); + private static var lime_window_set_maximum_size = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_window_set_maximum_size", "oiiv", false)); private static var lime_window_set_borderless = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_borderless", "obb", false)); private static var lime_window_set_cursor = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_set_cursor", "oiv", @@ -1223,8 +1210,8 @@ class NativeCFFI false)); private static var lime_window_set_visible = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_visible", "obb", false)); - private static var lime_window_set_always_on_top = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_always_on_top", "obb", - false)); + private static var lime_window_set_always_on_top = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_always_on_top", + "obb", false)); private static var lime_window_warp_mouse = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_warp_mouse", "oiiv", false)); private static var lime_window_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", @@ -1658,8 +1645,7 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_file_dialog_open_file") private static function lime_file_dialog_open_file(title:String, filter:String, - defaultPath:String):hl.Bytes + @:hlNative("lime", "hl_file_dialog_open_file") private static function lime_file_dialog_open_file(title:String, filter:String, defaultPath:String):hl.Bytes { return null; } @@ -1670,8 +1656,7 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_file_dialog_save_file") private static function lime_file_dialog_save_file(title:String, filter:String, - defaultPath:String):hl.Bytes + @:hlNative("lime", "hl_file_dialog_save_file") private static function lime_file_dialog_save_file(title:String, filter:String, defaultPath:String):hl.Bytes { return null; } @@ -1687,8 +1672,7 @@ class NativeCFFI return 0; } - @:hlNative("lime", "hl_file_watcher_remove_directory") private static function lime_file_watcher_remove_directory(handle:CFFIPointer, - watchID:Int):Void {} + @:hlNative("lime", "hl_file_watcher_remove_directory") private static function lime_file_watcher_remove_directory(handle:CFFIPointer, watchID:Int):Void {} @:hlNative("lime", "hl_file_watcher_update") private static function lime_file_watcher_update(handle:CFFIPointer):Void {} @@ -1810,7 +1794,8 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_gamepad_rumble") private static function lime_gamepad_rumble(id:Int, lowFrequencyRumble:Float, highFrequencyRumble:Float, duration:Int):Void {} + @:hlNative("lime", "hl_gamepad_rumble") private static function lime_gamepad_rumble(id:Int, lowFrequencyRumble:Float, highFrequencyRumble:Float, + duration:Int):Void {} @:hlNative("lime", "hl_gamepad_event_manager_register") private static function lime_gamepad_event_manager_register(callback:Void->Void, eventObject:GamepadEventInfo):Void {} @@ -2081,8 +2066,8 @@ 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 + @:hlNative("lime", "hl_window_create_vulkan_surface") private static function lime_window_create_vulkan_surface(handle:CFFIPointer, instanceHigh:Int, + instanceLow:Int):Dynamic { return null; } @@ -2124,8 +2109,8 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_window_get_vulkan_instance_extensions") private static function lime_window_get_vulkan_instance_extensions( - handle:CFFIPointer):hl.NativeArray + @:hlNative("lime", + "hl_window_get_vulkan_instance_extensions") private static function lime_window_get_vulkan_instance_extensions(handle:CFFIPointer):hl.NativeArray { return null; } @@ -2140,11 +2125,10 @@ class NativeCFFI 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_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_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 @@ -2159,44 +2143,44 @@ class NativeCFFI 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_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 + @: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 + @: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 + @: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_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 + @: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 + @: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_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 @@ -2204,8 +2188,8 @@ class NativeCFFI 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 + @: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; } @@ -2216,106 +2200,98 @@ class NativeCFFI 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 + @: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_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 + @: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_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 + @: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 + @: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 + @: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 + @: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_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 + @: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 + @: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 + @: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_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 + @: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 + @: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 + @: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 + @: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_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 @@ -2323,22 +2299,21 @@ class NativeCFFI 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 + @: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 + @: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_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 @@ -2346,22 +2321,21 @@ class NativeCFFI 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 + @: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 + @: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_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 @@ -2369,9 +2343,9 @@ class NativeCFFI 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 + @: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; } @@ -2383,59 +2357,58 @@ class NativeCFFI 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 + @: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_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 + @: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 + @: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_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 + @: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_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 + @: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_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 + @: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_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 @@ -2444,248 +2417,243 @@ class NativeCFFI } @: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 {} + 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 + @: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_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 + @: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 + @: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 + @: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 + 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 + @: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 + @: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_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 + @: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_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 + @: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 + @: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_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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + @: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 + 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 + 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 + @: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 + @: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 + 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 + @: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 + @: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 + @: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; } @@ -2696,8 +2664,7 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_vulkan_renderer_create") private static function lime_vulkan_renderer_create(handle:CFFIPointer, - applicationName:String):CFFIPointer + @:hlNative("lime", "hl_vulkan_renderer_create") private static function lime_vulkan_renderer_create(handle:CFFIPointer, applicationName:String):CFFIPointer { return null; } @@ -2714,8 +2681,8 @@ class NativeCFFI 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 + @: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; } @@ -2799,11 +2766,9 @@ class NativeCFFI return false; } - @:hlNative("lime", "hl_window_set_text_input_enabled") private static function lime_window_set_text_input_enabled(handle:CFFIPointer, - enabled:Bool):Void {} + @:hlNative("lime", "hl_window_set_text_input_enabled") private static function lime_window_set_text_input_enabled(handle:CFFIPointer, enabled:Bool):Void {} - @:hlNative("lime", "hl_window_set_text_input_rect") private static function lime_window_set_text_input_rect(handle:CFFIPointer, - rect:Rectangle):Void {} + @:hlNative("lime", "hl_window_set_text_input_rect") private static function lime_window_set_text_input_rect(handle:CFFIPointer, rect:Rectangle):Void {} @:hlNative("lime", "hl_window_set_title") private static function lime_window_set_title(handle:CFFIPointer, title:String):String { @@ -2822,7 +2787,10 @@ class NativeCFFI @:hlNative("lime", "hl_window_warp_mouse") private static function lime_window_warp_mouse(handle:CFFIPointer, x:Int, y:Int):Void {} - @:hlNative("lime", "hl_window_get_opacity") private static function lime_window_get_opacity(handle:CFFIPointer):Float { return 0.0; } + @:hlNative("lime", "hl_window_get_opacity") private static function lime_window_get_opacity(handle:CFFIPointer):Float + { + return 0.0; + } @:hlNative("lime", "hl_window_set_opacity") private static function lime_window_set_opacity(handle:CFFIPointer, value:Float):Void {} @@ -3174,10 +3142,8 @@ class NativeCFFI private static var lime_al_get_booleanv = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_booleanv", "iio", false)); private static var lime_al_gen_buffer = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_gen_buffer", "o", false)); private static var lime_al_gen_buffers = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_gen_buffers", "io", false)); - private static var lime_al_get_buffer3f = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_buffer3f", "oio", - false)); - private static var lime_al_get_buffer3i = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_buffer3i", "oio", - false)); + private static var lime_al_get_buffer3f = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_buffer3f", "oio", false)); + private static var lime_al_get_buffer3i = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_buffer3i", "oio", false)); private static var lime_al_get_bufferf = new cpp.CallableInt->cpp.Float32>(cpp.Prime._loadPrime("lime", "lime_al_get_bufferf", "oif", false)); private static var lime_al_get_bufferfv = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_bufferfv", "oiio", false)); @@ -3199,10 +3165,8 @@ class NativeCFFI private static var lime_al_get_listeneri = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_al_get_listeneri", "ii", false)); private static var lime_al_get_listeneriv = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_listeneriv", "iio", false)); private static var lime_al_get_proc_address = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", "lime_al_get_proc_address", "sd", false)); - private static var lime_al_get_source3f = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_source3f", "oio", - false)); - private static var lime_al_get_source3i = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_source3i", "oio", - false)); + private static var lime_al_get_source3f = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_source3f", "oio", false)); + private static var lime_al_get_source3i = new cpp.CallableInt->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_source3i", "oio", false)); private static var lime_al_get_sourcef = new cpp.CallableInt->cpp.Float32>(cpp.Prime._loadPrime("lime", "lime_al_get_sourcef", "oif", false)); private static var lime_al_get_sourcefv = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_sourcefv", "oiio", false)); @@ -3212,10 +3176,9 @@ class NativeCFFI private static var lime_al_get_string = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_al_get_string", "io", false)); private static var lime_al_is_buffer = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_al_is_buffer", "ob", false)); 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_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)); @@ -3225,8 +3188,7 @@ class NativeCFFI private static var lime_al_listeneri = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_listeneri", "iiv", false)); private static var lime_al_listeneriv = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_listeneriv", "iov", false)); private static var lime_al_source_pause = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_source_pause", "ov", false)); - private static var lime_al_source_pausev = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_source_pausev", "iov", - false)); + private static var lime_al_source_pausev = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_source_pausev", "iov", false)); private static var lime_al_source_play = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_source_play", "ov", false)); private static var lime_al_source_playv = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_al_source_playv", "iov", false)); private static var lime_al_source_queue_buffers = new cpp.CallableInt->cpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", @@ -3254,8 +3216,7 @@ class NativeCFFI private static var lime_alc_close_device = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_alc_close_device", "ob", false)); private static var lime_alc_create_context = new cpp.Callablecpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_create_context", "ooo", false)); - private static var lime_alc_destroy_context = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_destroy_context", "ov", - false)); + private static var lime_alc_destroy_context = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_destroy_context", "ov", false)); private static var lime_alc_get_contexts_device = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_get_contexts_device", "oo", false)); private static var lime_alc_get_current_context = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_get_current_context", "o", @@ -3268,21 +3229,17 @@ class NativeCFFI false)); private static var lime_alc_open_device = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_alc_open_device", "so", false)); private static var lime_alc_pause_device = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_pause_device", "ov", false)); - private static var lime_alc_process_context = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_process_context", "ov", - false)); + private static var lime_alc_process_context = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_alc_process_context", "ov", false)); 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_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_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)); @@ -3702,8 +3659,7 @@ class NativeCFFI @:hlNative("lime", "hl_al_source3f") private static function lime_al_source3f(source:CFFIPointer, param:Int, value1:hl.F32, value2:hl.F32, value3:hl.F32):Void {} - @:hlNative("lime", "hl_al_source3i") private static function lime_al_source3i(source:CFFIPointer, param:Int, value1:Dynamic, value2:Int, - value3:Int):Void {} + @:hlNative("lime", "hl_al_source3i") private static function lime_al_source3i(source:CFFIPointer, param:Int, value1:Dynamic, value2:Int, value3:Int):Void {} @:hlNative("lime", "hl_al_sourcef") private static function lime_al_sourcef(source:CFFIPointer, param:Int, value:hl.F32):Void {} @@ -3770,7 +3726,8 @@ 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 + @: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; } @@ -4088,8 +4045,7 @@ class NativeCFFI private static var lime_cairo_arc_negative = new cpp.CallableFloat->Float->Float->Float->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_arc_negative", "odddddv", false)); private static var lime_cairo_clip = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_clip", "ov", false)); - private static var lime_cairo_clip_preserve = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_clip_preserve", "ov", - false)); + private static var lime_cairo_clip_preserve = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_clip_preserve", "ov", false)); private static var lime_cairo_clip_extents = new cpp.CallableFloat->Float->Float->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_clip_extents", "oddddv", false)); private static var lime_cairo_close_path = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_close_path", "ov", false)); @@ -4100,8 +4056,7 @@ class NativeCFFI private static var lime_cairo_fill = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_fill", "ov", false)); private static var lime_cairo_fill_extents = new cpp.CallableFloat->Float->Float->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_fill_extents", "oddddv", false)); - private static var lime_cairo_fill_preserve = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_fill_preserve", "ov", - false)); + private static var lime_cairo_fill_preserve = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_fill_preserve", "ov", false)); private static var lime_cairo_get_antialias = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_cairo_get_antialias", "oi", false)); private static var lime_cairo_get_current_point = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_cairo_get_current_point", "oo", false)); @@ -4128,10 +4083,8 @@ class NativeCFFI false)); private static var lime_cairo_identity_matrix = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_identity_matrix", "ov", false)); - private static var lime_cairo_in_clip = new cpp.CallableFloat->Float->Bool>(cpp.Prime._loadPrime("lime", "lime_cairo_in_clip", "oddb", - false)); - private static var lime_cairo_in_fill = new cpp.CallableFloat->Float->Bool>(cpp.Prime._loadPrime("lime", "lime_cairo_in_fill", "oddb", - false)); + private static var lime_cairo_in_clip = new cpp.CallableFloat->Float->Bool>(cpp.Prime._loadPrime("lime", "lime_cairo_in_clip", "oddb", false)); + private static var lime_cairo_in_fill = new cpp.CallableFloat->Float->Bool>(cpp.Prime._loadPrime("lime", "lime_cairo_in_fill", "oddb", false)); private static var lime_cairo_in_stroke = new cpp.CallableFloat->Float->Bool>(cpp.Prime._loadPrime("lime", "lime_cairo_in_stroke", "oddb", false)); private static var lime_cairo_line_to = new cpp.CallableFloat->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_line_to", "oddv", @@ -4163,8 +4116,7 @@ class NativeCFFI private static var lime_cairo_restore = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_restore", "ov", false)); private static var lime_cairo_rotate = new cpp.CallableFloat->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_rotate", "odv", false)); private static var lime_cairo_save = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_save", "ov", false)); - private static var lime_cairo_scale = new cpp.CallableFloat->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_scale", "oddv", - false)); + private static var lime_cairo_scale = new cpp.CallableFloat->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_scale", "oddv", false)); private static var lime_cairo_set_antialias = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_set_antialias", "oiv", false)); private static var lime_cairo_set_dash = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_set_dash", "oov", @@ -4282,8 +4234,7 @@ class NativeCFFI "lime_cairo_pattern_set_filter", "oiv", false)); private static var lime_cairo_pattern_set_matrix = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_pattern_set_matrix", "oov", false)); - private static var lime_cairo_surface_flush = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_surface_flush", "ov", - false)); + private static var lime_cairo_surface_flush = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_cairo_surface_flush", "ov", false)); #end #end #if (neko || cppia) @@ -4428,8 +4379,8 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_cairo_curve_to") private static function lime_cairo_curve_to(handle:CFFIPointer, x1:Float, y1:Float, x2:Float, y2:Float, - x3:Float, y3:Float):Void {} + @:hlNative("lime", "hl_cairo_curve_to") private static function lime_cairo_curve_to(handle:CFFIPointer, x1:Float, y1:Float, x2:Float, y2:Float, x3:Float, + y3:Float):Void {} @:hlNative("lime", "hl_cairo_fill") private static function lime_cairo_fill(handle:CFFIPointer):Void {} @@ -4569,8 +4520,7 @@ class NativeCFFI @:hlNative("lime", "hl_cairo_push_group") private static function lime_cairo_push_group(handle:CFFIPointer):Void {} - @:hlNative("lime", "hl_cairo_push_group_with_content") private static function lime_cairo_push_group_with_content(handle:CFFIPointer, - content:Int):Void {} + @:hlNative("lime", "hl_cairo_push_group_with_content") private static function lime_cairo_push_group_with_content(handle:CFFIPointer, content:Int):Void {} @:hlNative("lime", "hl_cairo_rectangle") private static function lime_cairo_rectangle(handle:CFFIPointer, x:Float, y:Float, width:Float, height:Float):Void {} @@ -4623,8 +4573,8 @@ class NativeCFFI @:hlNative("lime", "hl_cairo_set_source_rgba") private static function lime_cairo_set_source_rgba(handle:CFFIPointer, r:Float, g:Float, b:Float, a:Float):Void {} - @:hlNative("lime", "hl_cairo_set_source_surface") private static function lime_cairo_set_source_surface(handle:CFFIPointer, surface:CFFIPointer, - x:Float, y:Float):Void {} + @:hlNative("lime", "hl_cairo_set_source_surface") private static function lime_cairo_set_source_surface(handle:CFFIPointer, surface:CFFIPointer, x:Float, + y:Float):Void {} @:hlNative("lime", "hl_cairo_set_tolerance") private static function lime_cairo_set_tolerance(handle:CFFIPointer, tolerance:Float):Void {} @@ -4692,14 +4642,12 @@ class NativeCFFI return 0; } - @:hlNative("lime", "hl_cairo_font_options_set_antialias") private static function lime_cairo_font_options_set_antialias(handle:CFFIPointer, - v:Int):Void {} + @:hlNative("lime", "hl_cairo_font_options_set_antialias") private static function lime_cairo_font_options_set_antialias(handle:CFFIPointer, v:Int):Void {} @:hlNative("lime", "hl_cairo_font_options_set_hint_metrics") private static function lime_cairo_font_options_set_hint_metrics(handle:CFFIPointer, v:Int):Void {} - @:hlNative("lime", "hl_cairo_font_options_set_hint_style") private static function lime_cairo_font_options_set_hint_style(handle:CFFIPointer, - v:Int):Void {} + @:hlNative("lime", "hl_cairo_font_options_set_hint_style") private static function lime_cairo_font_options_set_hint_style(handle:CFFIPointer, v:Int):Void {} @:hlNative("lime", "hl_cairo_font_options_set_subpixel_order") private static function lime_cairo_font_options_set_subpixel_order(handle:CFFIPointer, v:Int):Void {} @@ -4709,8 +4657,7 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_cairo_image_surface_create") private static function lime_cairo_image_surface_create(format:Int, width:Int, - height:Int):CFFIPointer + @:hlNative("lime", "hl_cairo_image_surface_create") private static function lime_cairo_image_surface_create(format:Int, width:Int, height:Int):CFFIPointer { return null; } @@ -4746,8 +4693,8 @@ class NativeCFFI return 0; } - @:hlNative("lime", "hl_cairo_pattern_add_color_stop_rgb") private static function lime_cairo_pattern_add_color_stop_rgb(handle:CFFIPointer, - offset:Float, red:Float, green:Float, blue:Float):Void {} + @:hlNative("lime", "hl_cairo_pattern_add_color_stop_rgb") private static function lime_cairo_pattern_add_color_stop_rgb(handle:CFFIPointer, offset:Float, + red:Float, green:Float, blue:Float):Void {} @:hlNative("lime", "hl_cairo_pattern_add_color_stop_rgba") private static function lime_cairo_pattern_add_color_stop_rgba(handle:CFFIPointer, offset:Float, red:Float, green:Float, blue:Float, alpha:Float):Void {} @@ -5867,8 +5814,7 @@ class NativeCFFI private static var lime_gl_get_vertex_attribi = new cpp.CallableInt->Int>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribi", "iii", false)); private static var lime_gl_get_vertex_attribiv = new cpp.CallableInt->lime.utils.DataPointer->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribiv", "iidv", false)); - private static var lime_gl_get_vertex_attribii = new cpp.CallableInt->Int>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribii", "iii", - false)); + private static var lime_gl_get_vertex_attribii = new cpp.CallableInt->Int>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribii", "iii", false)); private static var lime_gl_get_vertex_attribiiv = new cpp.CallableInt->lime.utils.DataPointer->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribiiv", "iidv", false)); private static var lime_gl_get_vertex_attribiui = new cpp.CallableInt->Int>(cpp.Prime._loadPrime("lime", "lime_gl_get_vertex_attribiui", "iii", @@ -6377,8 +6323,7 @@ class NativeCFFI @:hlNative("lime", "hl_gl_buffer_data") private static function lime_gl_buffer_data(target:Int, size:Int, srcData:DataPointer, usage:Int):Void {} - @:hlNative("lime", "hl_gl_buffer_sub_data") private static function lime_gl_buffer_sub_data(target:Int, offset:Int, size:Int, - srcData:DataPointer):Void {} + @:hlNative("lime", "hl_gl_buffer_sub_data") private static function lime_gl_buffer_sub_data(target:Int, offset:Int, size:Int, srcData:DataPointer):Void {} @:hlNative("lime", "hl_gl_check_framebuffer_status") private static function lime_gl_check_framebuffer_status(target:Int):Int { @@ -6395,8 +6340,7 @@ class NativeCFFI @:hlNative("lime", "hl_gl_clear_bufferuiv") private static function lime_gl_clear_bufferuiv(buffer:Int, drawBuffer:Int, data:DataPointer):Void {} - @:hlNative("lime", "hl_gl_client_wait_sync") private static function lime_gl_client_wait_sync(sync:CFFIPointer, flags:Int, timeoutA:Int, - timeoutB:Int):Int + @:hlNative("lime", "hl_gl_client_wait_sync") private static function lime_gl_client_wait_sync(sync:CFFIPointer, flags:Int, timeoutA:Int, timeoutB:Int):Int { return 0; } @@ -6619,8 +6563,7 @@ class NativeCFFI @:hlNative("lime", "hl_gl_get_buffer_parameteri64v") private static function lime_gl_get_buffer_parameteri64v(target:Int, index:Int, params:DataPointer):Void {} - @:hlNative("lime", "hl_gl_get_buffer_parameteriv") private static function lime_gl_get_buffer_parameteriv(target:Int, pname:Int, - params:DataPointer):Void {} + @:hlNative("lime", "hl_gl_get_buffer_parameteriv") private static function lime_gl_get_buffer_parameteriv(target:Int, pname:Int, params:DataPointer):Void {} @:hlNative("lime", "hl_gl_get_buffer_pointerv") private static function lime_gl_get_buffer_pointerv(target:Int, pname:Int):DataPointer { @@ -6982,8 +6925,8 @@ class NativeCFFI @:hlNative("lime", "hl_gl_scissor") private static function lime_gl_scissor(x:Int, y:Int, width:Int, height:Int):Void {} - @:hlNative("lime", "hl_gl_shader_binary") private static function lime_gl_shader_binary(shaders:hl.NativeArray, binaryformat:Int, - binary:DataPointer, length:Int):Void {} + @:hlNative("lime", "hl_gl_shader_binary") private static function lime_gl_shader_binary(shaders:hl.NativeArray, binaryformat:Int, binary:DataPointer, + length:Int):Void {} @:hlNative("lime", "hl_gl_shader_source") private static function lime_gl_shader_source(shader:Int, source:String):Void {} @@ -7015,8 +6958,8 @@ class NativeCFFI @:hlNative("lime", "hl_gl_tex_storage_3d") private static function lime_gl_tex_storage_3d(target:Int, level:Int, internalformat:Int, width:Int, height:Int, depth:Int):Void {} - @:hlNative("lime", "hl_gl_tex_sub_image_2d") private static function lime_gl_tex_sub_image_2d(target:Int, level:Int, xoffset:Int, yoffset:Int, - width:Int, height:Int, format:Int, type:Int, data:DataPointer):Void {} + @:hlNative("lime", "hl_gl_tex_sub_image_2d") private static function lime_gl_tex_sub_image_2d(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, + height:Int, format:Int, type:Int, data:DataPointer):Void {} @:hlNative("lime", "hl_gl_tex_sub_image_3d") private static function lime_gl_tex_sub_image_3d(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, width:Int, height:Int, depth:Int, format:Int, type:Int, data:DataPointer):Void {} @@ -7387,8 +7330,7 @@ class NativeCFFI private static var lime_hb_blob_is_immutable = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_hb_blob_is_immutable", "ob", false)); private static var lime_hb_blob_make_immutable = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_blob_make_immutable", "ov", false)); - private static var lime_hb_buffer_add = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_buffer_add", "oiiv", - false)); + private static var lime_hb_buffer_add = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_buffer_add", "oiiv", false)); private static var lime_hb_buffer_add_hxstring = new cpp.CallableString->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_buffer_add_hxstring", "osiiv", false)); private static var lime_hb_buffer_add_codepoints = new cpp.Callablelime.utils.DataPointer->Int->Int->Int-> @@ -7475,8 +7417,7 @@ class NativeCFFI "oiv", false)); private static var lime_hb_face_set_index = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_face_set_index", "oiv", false)); - private static var lime_hb_face_set_upem = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_face_set_upem", "oiv", - false)); + private static var lime_hb_face_set_upem = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_hb_face_set_upem", "oiv", false)); private static var lime_hb_feature_from_string = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_feature_from_string", "so", false)); private static var lime_hb_feature_to_string = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_feature_to_string", "oo", @@ -7494,8 +7435,7 @@ class NativeCFFI "lime_hb_font_get_glyph_kerning_for_direction", "oiiio", false)); private static var lime_hb_font_get_glyph_origin_for_direction = new cpp.CallableInt->Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_font_get_glyph_origin_for_direction", "oiio", false)); - private static var lime_hb_font_get_parent = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_font_get_parent", "oo", - false)); + private static var lime_hb_font_get_parent = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_font_get_parent", "oo", false)); private static var lime_hb_font_get_ppem = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_font_get_ppem", "oo", false)); private static var lime_hb_font_get_scale = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_hb_font_get_scale", "oo", false)); private static var lime_hb_font_glyph_from_string = new cpp.CallableString->Int>(cpp.Prime._loadPrime("lime", @@ -7839,8 +7779,7 @@ class NativeCFFI return null; } - @:hlNative("lime", "hl_hb_buffer_set_cluster_level") private static function lime_hb_buffer_set_cluster_level(buffer:CFFIPointer, - clusterLevel:Int):Void {} + @:hlNative("lime", "hl_hb_buffer_set_cluster_level") private static function lime_hb_buffer_set_cluster_level(buffer:CFFIPointer, clusterLevel:Int):Void {} @:hlNative("lime", "hl_hb_buffer_set_content_type") private static function lime_hb_buffer_set_content_type(buffer:CFFIPointer, contentType:Int):Void {} @@ -7999,8 +7938,8 @@ class NativeCFFI @:hlNative("lime", "hl_hb_font_set_scale") private static function lime_hb_font_set_scale(font:CFFIPointer, xScale:Int, yScale:Int):Void {} @:hlNative("lime", - "hl_hb_font_subtract_glyph_origin_for_direction") private static function lime_hb_font_subtract_glyph_origin_for_direction(font:CFFIPointer, - glyph:Int, direction:Int, x:Int, y:Int):Void {} + "hl_hb_font_subtract_glyph_origin_for_direction") private static function lime_hb_font_subtract_glyph_origin_for_direction(font:CFFIPointer, glyph:Int, + direction:Int, x:Int, y:Int):Void {} @:hlNative("lime", "hl_hb_ft_font_create") private static function lime_hb_ft_font_create(font:CFFIPointer):CFFIPointer { @@ -8123,8 +8062,7 @@ class NativeCFFI @:hlNative("lime", "hl_hb_set_union") private static function lime_hb_set_union(set:CFFIPointer, other:CFFIPointer):Void {} - @:hlNative("lime", "hl_hb_shape") private static function lime_hb_shape(font:CFFIPointer, buffer:CFFIPointer, - features:hl.NativeArray):Void {} + @:hlNative("lime", "hl_hb_shape") private static function lime_hb_shape(font:CFFIPointer, buffer:CFFIPointer, features:hl.NativeArray):Void {} #end #end #if (lime_cffi && !macro && lime_vorbis) @@ -8321,8 +8259,7 @@ class NativeCFFI return 0; } - @:hlNative("lime", "hl_vorbis_file_pcm_seek_lap") private static function lime_vorbis_file_pcm_seek_lap(vorbisFile:CFFIPointer, posLow:Int, - posHigh:Int):Int + @:hlNative("lime", "hl_vorbis_file_pcm_seek_lap") private static function lime_vorbis_file_pcm_seek_lap(vorbisFile:CFFIPointer, posLow:Int, posHigh:Int):Int { return 0; } @@ -8344,8 +8281,7 @@ class NativeCFFI return 0; } - @:hlNative("lime", "hl_vorbis_file_raw_seek_lap") private static function lime_vorbis_file_raw_seek_lap(vorbisFile:CFFIPointer, posLow:Int, - posHigh:Int):Int + @:hlNative("lime", "hl_vorbis_file_raw_seek_lap") private static function lime_vorbis_file_raw_seek_lap(vorbisFile:CFFIPointer, posLow:Int, posHigh:Int):Int { return 0; } @@ -8429,4 +8365,3 @@ class NativeCFFI #end #end } - diff --git a/src/lime/_internal/backend/native/NativeHTTPRequest.hx b/src/lime/_internal/backend/native/NativeHTTPRequest.hx index 026d23f963..c09d041288 100644 --- a/src/lime/_internal/backend/native/NativeHTTPRequest.hx +++ b/src/lime/_internal/backend/native/NativeHTTPRequest.hx @@ -361,7 +361,8 @@ class NativeHTTPRequest return promise.future; } - private function buildBuffer() { + private function buildBuffer() + { bytes = buffer.getBytes(); return bytes; } diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index f548ae1c5f..6fc4344a59 100644 --- a/src/lime/_internal/backend/native/NativeWindow.hx +++ b/src/lime/_internal/backend/native/NativeWindow.hx @@ -173,7 +173,8 @@ class NativeWindow contextAttributes.hardware = true; context.vulkan = new VulkanRenderContext(handle); context.type = VULKAN; - context.version = Reflect.hasField(contextAttributes, "version") && contextAttributes.version != null ? contextAttributes.version : ""; + context.version = Reflect.hasField(contextAttributes, "version") + && contextAttributes.version != null ? contextAttributes.version : ""; default: useHardware = false; diff --git a/src/lime/_internal/graphics/ImageDataUtil.hx b/src/lime/_internal/graphics/ImageDataUtil.hx index 5837151cc5..6cf41a857f 100644 --- a/src/lime/_internal/graphics/ImageDataUtil.hx +++ b/src/lime/_internal/graphics/ImageDataUtil.hx @@ -238,11 +238,7 @@ class ImageDataUtil var srcPremultiplied = sourceImage.buffer.premultiplied; var destPremultiplied = image.buffer.premultiplied; - var srcPosition, - destPosition, - srcPixel:RGBA = 0, - destPixel:RGBA = 0, - value = 0; + var srcPosition, destPosition, srcPixel:RGBA = 0, destPixel:RGBA = 0, value = 0; for (y in 0...destView.height) { @@ -601,12 +597,7 @@ class ImageDataUtil queue.push(x); queue.push(y); - var curPointX, - curPointY, - nextPointX, - nextPointY, - nextPointOffset, - readColor:RGBA = 0; + var curPointX, curPointY, nextPointX, nextPointY, nextPointOffset, readColor:RGBA = 0; while (queue.length > 0) { @@ -1000,18 +991,9 @@ class ImageDataUtil var data = image.data; var newData = newBuffer.data; - var sourceIndex:Int, - sourceIndexX:Int, - sourceIndexY:Int, - sourceIndexXY:Int, - index:Int; + var sourceIndex:Int, sourceIndexX:Int, sourceIndexY:Int, sourceIndexXY:Int, index:Int; var sourceX:Int, sourceY:Int; - var u:Float, - v:Float, - uRatio:Float, - vRatio:Float, - uOpposite:Float, - vOpposite:Float; + var u:Float, v:Float, uRatio:Float, vRatio:Float, uOpposite:Float, vOpposite:Float; for (y in 0...newHeight) { @@ -1361,13 +1343,7 @@ class ImageDataUtil var srcPremultiplied = sourceImage.buffer.premultiplied; var destPremultiplied = image.buffer.premultiplied; - var srcPosition, - destPosition, - srcPixel:RGBA = 0, - destPixel:RGBA = 0, - pixelMask:UInt, - test:Bool, - value:Int; + var srcPosition, destPosition, srcPixel:RGBA = 0, destPixel:RGBA = 0, pixelMask:UInt, test:Bool, value:Int; for (y in 0...destView.height) { @@ -1774,8 +1750,7 @@ private class ImageDataView } } -@:noCompletion @:dox(hide) -#if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract ThresholdOperation(Int) from Int to Int +@:noCompletion @:dox(hide) #if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract ThresholdOperation(Int) from Int to Int { var NOT_EQUALS = 0; var EQUALS = 1; diff --git a/src/lime/_internal/macros/AssetsMacro.hx b/src/lime/_internal/macros/AssetsMacro.hx index a5b403ee86..390cc4c209 100644 --- a/src/lime/_internal/macros/AssetsMacro.hx +++ b/src/lime/_internal/macros/AssetsMacro.hx @@ -41,18 +41,17 @@ class AssetsMacro } } - var superCall = Context.defined("html5") ? macro super(bytes.b.buffer) - : Context.defined("hl") ? macro super(bytes.b, bytes.length) - : macro super(bytes.length, bytes.b); + var superCall = Context.defined("html5") ? macro super(bytes.b.buffer) : Context.defined("hl") ? macro super(bytes.b, + bytes.length) : macro super(bytes.length, bytes.b); var definition = macro class Temp - { - public function new(?length:Int, ?bytesData:haxe.io.BytesData) { - var bytes = haxe.Resource.getBytes(resourceName); - $superCall; - } - }; + public function new(?length:Int, ?bytesData:haxe.io.BytesData) + { + var bytes = haxe.Resource.getBytes(resourceName); + $superCall; + } + }; fields.push(definition.fields[0]); @@ -65,15 +64,15 @@ class AssetsMacro if (fields == null) return null; var definition = macro class Temp - { - public function new(?length:Int = 0) { - super(); + public function new(?length:Int = 0) + { + super(); - var bytes = haxe.Resource.getBytes(resourceName); - __fromBytes(bytes); - } - }; + var bytes = haxe.Resource.getBytes(resourceName); + __fromBytes(bytes); + } + }; fields.push(definition.fields[0]); @@ -112,11 +111,7 @@ class AssetsMacro } var bytes = File.getBytes(path); - var resourceName = "__ASSET__" - + metaName - + "_" - + (classType.pack.length > 0 ? classType.pack.join("_") + "_" : "") - + classType.name; + var resourceName = "__ASSET__" + metaName + "_" + (classType.pack.length > 0 ? classType.pack.join("_") + "_" : "") + classType.name; if (Context.getResources().exists(resourceName)) { @@ -137,9 +132,9 @@ class AssetsMacro } var definition = macro class Temp - { - private static inline var resourceType:String = $v{ resourceType }; - }; + { + private static inline var resourceType:String = $v{resourceType}; + }; fields.push(definition.fields[0]); @@ -152,9 +147,9 @@ class AssetsMacro } var definition = macro class Temp - { - private static inline var resourceName:String = $v{ resourceName }; - }; + { + private static inline var resourceName:String = $v{resourceName}; + }; fields.push(definition.fields[0]); @@ -226,16 +221,16 @@ class AssetsMacro } var definition = macro class Temp - { - private static var resourceName:String = $v{ resourceName }; - - public function new() { - super(); + private static var resourceName:String = $v{resourceName}; - __fromBytes(haxe.Resource.getBytes(resourceName)); - } - }; + public function new() + { + super(); + + __fromBytes(haxe.Resource.getBytes(resourceName)); + } + }; fields.push(definition.fields[0]); fields.push(definition.fields[1]); @@ -255,56 +250,53 @@ class AssetsMacro if (Context.defined("html5")) { definition = macro class Temp - { - public static var preload:js.html.Image; - - public function new(?buffer:lime.graphics.ImageBuffer, - ?offsetX:Int, ?offsetY:Int, ?width:Int, ?height:Int, - ?color:Null, ?type:lime.graphics.ImageType, - ?onload:Dynamic = true) { - super(); + public static var preload:js.html.Image; - if (preload != null) + public function new(?buffer:lime.graphics.ImageBuffer, ?offsetX:Int, ?offsetY:Int, ?width:Int, ?height:Int, ?color:Null, + ?type:lime.graphics.ImageType, ?onload:Dynamic = true) { - var buffer = new lime.graphics.ImageBuffer(); - buffer.__srcImage = preload; - buffer.width = preload.width; - buffer.width = preload.height; + super(); - __fromImageBuffer(buffer); - } - else - { - __fromBase64(haxe.Resource.getString(resourceName), resourceType, function(image) + if (preload != null) { - if (preload == null) - { - preload = image.buffer.__srcImage; - } + var buffer = new lime.graphics.ImageBuffer(); + buffer.__srcImage = preload; + buffer.width = preload.width; + buffer.width = preload.height; - if (onload != null) + __fromImageBuffer(buffer); + } + else + { + __fromBase64(haxe.Resource.getString(resourceName), resourceType, function(image) { - onload(image); - } - }); + if (preload == null) + { + preload = image.buffer.__srcImage; + } + + if (onload != null) + { + onload(image); + } + }); + } } - } - }; + }; } else { definition = macro class Temp - { - public function new(?buffer:lime.graphics.ImageBuffer, - ?offsetX:Int, ?offsetY:Int, ?width:Int, ?height:Int, - ?color:Null, ?type:lime.graphics.ImageType) { - super(); + public function new(?buffer:lime.graphics.ImageBuffer, ?offsetX:Int, ?offsetY:Int, ?width:Int, ?height:Int, ?color:Null, + ?type:lime.graphics.ImageType) + { + super(); - __fromBytes(haxe.Resource.getBytes(resourceName), null); - } - }; + __fromBytes(haxe.Resource.getBytes(resourceName), null); + } + }; } for (field in definition.fields) @@ -319,21 +311,18 @@ class AssetsMacro { var fields = embedData(":sound"); // CFFILoader.h(248) : NOT Implemented:api_buffer_data - if (fields == null || Context.defined("html5") || !Context.defined("openfl")) - return null; + if (fields == null || Context.defined("html5") || !Context.defined("openfl")) return null; var definition = macro class Temp - { - public function new(?stream:openfl.net.URLRequest, - ?context:openfl.media.SoundLoaderContext, - ?forcePlayAsMusic:Bool = false) { - super(); + public function new(?stream:openfl.net.URLRequest, ?context:openfl.media.SoundLoaderContext, ?forcePlayAsMusic:Bool = false) + { + super(); - var byteArray = openfl.utils.ByteArray.fromBytes(haxe.Resource.getBytes(resourceName)); - loadCompressedDataFromByteArray(byteArray, byteArray.length, forcePlayAsMusic); - } - }; + var byteArray = openfl.utils.ByteArray.fromBytes(haxe.Resource.getBytes(resourceName)); + loadCompressedDataFromByteArray(byteArray, byteArray.length, forcePlayAsMusic); + } + }; fields.push(definition.fields[0]); diff --git a/src/lime/_internal/macros/CFFIMacro.hx b/src/lime/_internal/macros/CFFIMacro.hx index 5b65675863..51430f550d 100644 --- a/src/lime/_internal/macros/CFFIMacro.hx +++ b/src/lime/_internal/macros/CFFIMacro.hx @@ -183,7 +183,7 @@ class CFFIMacro case "cpp.Float32": if (useCPPTypes) { - typeArgs.push({name: arg.name, opt: false, t: (macro:cpp.Float32).toType()}); + typeArgs.push({name: arg.name, opt: false, t: (macro :cpp.Float32).toType()}); } else { @@ -207,7 +207,7 @@ class CFFIMacro case "Void", "cpp.Void": if (useCPPTypes) { - typeArgs.push({name: arg.name, opt: false, t: (macro:cpp.Void).toType()}); + typeArgs.push({name: arg.name, opt: false, t: (macro :cpp.Void).toType()}); } else { @@ -219,11 +219,11 @@ class CFFIMacro default: if (useCPPTypes) { - typeArgs.push({name: arg.name, opt: false, t: (macro:cpp.Object).toType()}); + typeArgs.push({name: arg.name, opt: false, t: (macro :cpp.Object).toType()}); } else { - typeArgs.push({name: arg.name, opt: false, t: (macro:Dynamic).toType()}); + typeArgs.push({name: arg.name, opt: false, t: (macro :Dynamic).toType()}); } typeSignature += "o"; @@ -243,7 +243,7 @@ class CFFIMacro case "cpp.Float32": if (useCPPTypes) { - typeResult = (macro:cpp.Float32).toType(); + typeResult = (macro :cpp.Float32).toType(); } else { @@ -267,7 +267,7 @@ class CFFIMacro case "Void", "cpp.Void": if (useCPPTypes) { - typeResult = (macro:cpp.Void).toType(); + typeResult = (macro :cpp.Void).toType(); } else { @@ -279,11 +279,11 @@ class CFFIMacro default: if (useCPPTypes) { - typeResult = (macro:cpp.Object).toType(); + typeResult = (macro :cpp.Object).toType(); } else { - typeResult = (macro:Dynamic).toType(); + typeResult = (macro :Dynamic).toType(); } typeSignature += "o"; diff --git a/src/lime/_internal/macros/EventMacro.hx b/src/lime/_internal/macros/EventMacro.hx index 4071ce5841..eae7aad1b2 100644 --- a/src/lime/_internal/macros/EventMacro.hx +++ b/src/lime/_internal/macros/EventMacro.hx @@ -29,8 +29,8 @@ class EventMacro return null; case TInst(_, paramTypes): - Context.fatalError("Expected only one type parameter. Did you mean Event<" - + paramTypes.map(haxe.macro.TypeTools.toString).join(" -> ") + ">?", Context.currentPos()); + Context.fatalError("Expected only one type parameter. Did you mean Event<" + paramTypes.map(haxe.macro.TypeTools.toString).join(" -> ") + ">?", + Context.currentPos()); return null; default: @@ -200,7 +200,7 @@ class EventMacro args: args, expr: dispatch, params: [], - ret: macro:Void + ret: macro :Void }), pos: pos }); @@ -210,10 +210,11 @@ class EventMacro access: [APublic], kind: FFun( { - args: [{name: "timestamp", type: macro:Int}].concat(args), + args: [ + {name: "timestamp", type: macro :Int}].concat(args), expr: timestampDispatch, params: [], - ret: macro:Void + ret: macro :Void }), meta: [ {name: ":dox", params: [macro hide], pos: pos}, diff --git a/src/lime/_internal/macros/HTTPRequestMacro.hx b/src/lime/_internal/macros/HTTPRequestMacro.hx index f862fe6ead..e4532738e7 100644 --- a/src/lime/_internal/macros/HTTPRequestMacro.hx +++ b/src/lime/_internal/macros/HTTPRequestMacro.hx @@ -129,11 +129,11 @@ class HTTPRequestMacro kind: FFun( { args: [ - {name: "uri", type: macro:String, opt: true}], + {name: "uri", type: macro :String, opt: true}], expr: macro {super(uri);}, params: [], - ret: macro:Void + ret: macro :Void }), pos: Context.currentPos() }, @@ -143,7 +143,7 @@ class HTTPRequestMacro kind: FFun( { args: [ - {name: "bytes", type: macro:haxe.io.Bytes}], + {name: "bytes", type: macro :haxe.io.Bytes}], expr: Context.parse("return " + typeString + ".fromBytes (bytes)", pos), params: [], ret: paramType.toComplexType() diff --git a/src/lime/app/Event.hx b/src/lime/app/Event.hx index 5c4b0a9daa..bdca9898f0 100644 --- a/src/lime/app/Event.hx +++ b/src/lime/app/Event.hx @@ -97,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 { diff --git a/src/lime/graphics/Image.hx b/src/lime/graphics/Image.hx index 79c79ac326..5bfd568619 100644 --- a/src/lime/graphics/Image.hx +++ b/src/lime/graphics/Image.hx @@ -59,7 +59,6 @@ import format.tools.Deflate; import sys.io.File; #end #end - /** `Image` is a convenience class for working with bitmap images in Lime. @@ -395,8 +394,7 @@ class Image sourceRect.offset(sourceImage.offsetX, sourceImage.offsetY); destPoint.offset(offsetX, offsetY); - buffer.__srcBitmapData.copyChannel(sourceImage.buffer.src, sourceRect.__toFlashRectangle(), destPoint.__toFlashPoint(), srcChannel, - dstChannel); + buffer.__srcBitmapData.copyChannel(sourceImage.buffer.src, sourceRect.__toFlashRectangle(), destPoint.__toFlashPoint(), srcChannel, dstChannel); default: } diff --git a/src/lime/graphics/OpenGLES3RenderContext.hx b/src/lime/graphics/OpenGLES3RenderContext.hx index 8c0c21ae7d..2ab458e81c 100644 --- a/src/lime/graphics/OpenGLES3RenderContext.hx +++ b/src/lime/graphics/OpenGLES3RenderContext.hx @@ -9,7 +9,6 @@ import lime.graphics.opengl.*; import lime.utils.DataPointer; import lime.utils.Float32Array; import lime.utils.Int32Array; - /** The `OpenGLES3RenderContext` allows access to OpenGL ES 3.0 features when OpenGL or OpenGL ES is the render context type of the `Window`, and the current context supports diff --git a/src/lime/graphics/VulkanRenderContext.hx b/src/lime/graphics/VulkanRenderContext.hx index 39e2e3c1b6..b9b6412056 100644 --- a/src/lime/graphics/VulkanRenderContext.hx +++ b/src/lime/graphics/VulkanRenderContext.hx @@ -9,7 +9,6 @@ import lime.system.CFFI; #if (!lime_doc_gen || lime_cffi) import lime.system.CFFIPointer; #end - #if hl import hl.Bytes as HLBytes; import hl.NativeArray; diff --git a/src/lime/graphics/WebGL2RenderContext.hx b/src/lime/graphics/WebGL2RenderContext.hx index 3fdc913647..802b3fa5f0 100644 --- a/src/lime/graphics/WebGL2RenderContext.hx +++ b/src/lime/graphics/WebGL2RenderContext.hx @@ -301,15 +301,14 @@ import lime.utils.UInt32Array; **/ @:access(lime.graphics.RenderContext) #if !doc_gen -@:transitive -abstract WebGL2RenderContext(OpenGLRenderContext) from OpenGLRenderContext to OpenGLRenderContext +@:transitive abstract WebGL2RenderContext(OpenGLRenderContext) from OpenGLRenderContext to OpenGLRenderContext { #else abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic { #end - private static var __tempPointer = new BytePointer(); + public var DEPTH_BUFFER_BIT(get, never):Int; public var STENCIL_BUFFER_BIT(get, never):Int; public var COLOR_BUFFER_BIT(get, never):Int; @@ -3766,10 +3765,9 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic #end { var size = (srcData != null) ? srcData.byteLength : 0; - __tempPointer.set(srcData, srcOffset); this.bufferData(target, size, __tempPointer, usage); - } + } #if !lime_webgl public inline function bufferSubData(target:Int, offset:Int, srcData:ArrayBufferView, srcOffset:Int = 0, ?length:Int):Void @@ -3778,7 +3776,6 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic #end { var size = (length != null) ? length : (srcData != null) ? srcData.byteLength : 0; - __tempPointer.set(srcData, srcOffset); this.bufferSubData(target, offset, size, __tempPointer); } @@ -3849,21 +3846,18 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic #if !lime_webgl public function compressedTexImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Int, srcData:ArrayBufferView, srcOffset:Int = 0, - ?srcLengthOverride:Int):Void + ?srcLengthOverride:Int):Void #else - public inline function compressedTexImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Int, srcData:Dynamic, - ?srcOffset:Int, - ?srcLengthOverride:Int):Void + public inline function compressedTexImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Int, srcData:Dynamic, ?srcOffset:Int, + ?srcLengthOverride:Int):Void #end { var imageSize = (srcLengthOverride != null) ? srcLengthOverride : (srcData != null) ? srcData.byteLength : 0; - __tempPointer.set(srcData, srcOffset); this.compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, __tempPointer); } - public function compressedTexImage3D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, depth:Int, border:Int, - srcData:ArrayBufferView, + public function compressedTexImage3D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, depth:Int, border:Int, srcData:ArrayBufferView, srcOffset:Int = 0, ?srcLengthOverride:Int):Void { var imageSize = (srcLengthOverride != null) ? srcLengthOverride : (srcData != null) ? srcData.byteLength : 0; @@ -3872,23 +3866,19 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function compressedTexSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, - srcData:ArrayBufferView, - srcOffset:Int = 0, ?srcLengthOverride:Int):Void + public inline function compressedTexSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, srcData:ArrayBufferView, + srcOffset:Int = 0, ?srcLengthOverride:Int):Void #else - public inline function compressedTexSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, - srcData:Dynamic, - ?srcOffset:Int, ?srcLengthOverride:Int):Void + public inline function compressedTexSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, srcData:Dynamic, + ?srcOffset:Int, ?srcLengthOverride:Int):Void #end { var imageSize = (srcLengthOverride != null) ? srcLengthOverride : (srcData != null) ? srcData.byteLength : 0; - __tempPointer.set(srcData, srcOffset); this.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, __tempPointer); } - public inline function compressedTexSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, width:Int, height:Int, - depth:Int, format:Int, + public inline function compressedTexSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, width:Int, height:Int, depth:Int, format:Int, srcData:ArrayBufferView, srcOffset:Int = 0, ?srcLengthOverride:Int):Void { var imageSize = (srcLengthOverride != null) ? srcLengthOverride : (srcData != null) ? srcData.byteLength : 0; @@ -3911,8 +3901,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); } - public inline function copyTexSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, x:Int, y:Int, width:Int, - height:Int):Void + public inline function copyTexSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, x:Int, y:Int, width:Int, height:Int):Void { this.copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); } @@ -4195,7 +4184,6 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic { #if !js var size = (length != null) ? length : (dstData != null) ? dstData.length : 0; - this.getBufferSubData(target, srcByteOffset + srcOffset, size, dstData); #end } @@ -4451,8 +4439,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function readPixels(x:Int, y:Int, width:Int, height:Int, format:Int, type:Int, pixels:ArrayBufferView, - dstOffset:Int = 0):Void + public inline function readPixels(x:Int, y:Int, width:Int, height:Int, format:Int, type:Int, pixels:ArrayBufferView, dstOffset:Int = 0):Void #else public inline function readPixels(x:Int, y:Int, width:Int, height:Int, format:Int, type:Int, pixels:Dynamic, ?dstOffset:Int):Void #end @@ -4532,13 +4519,13 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function texImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Int, format:Int, - type:Int, srcData:ArrayBufferView, - srcOffset:Int = 0):Void + public inline function texImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Int, format:Int, type:Int, + srcData:ArrayBufferView, + srcOffset:Int = 0):Void #else - public inline function texImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Dynamic, ?format:Int, - ?type:Int, ?srcData:Dynamic, - ?srcOffset:Int):Void + public inline function texImage2D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, border:Dynamic, ?format:Int, ?type:Int, + ?srcData:Dynamic, + ?srcOffset:Int):Void #end { #if !lime_webgl @@ -4547,8 +4534,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic #end } - public inline function texImage3D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, depth:Int, border:Int, - format:Int, type:Int, + public inline function texImage3D(target:Int, level:Int, internalformat:Int, width:Int, height:Int, depth:Int, border:Int, format:Int, type:Int, srcData:ArrayBufferView, srcOffset:Int = 0):Void { __tempPointer.set(srcData, srcOffset); @@ -4576,21 +4562,18 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function texSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, - type:Int, srcData:ArrayBufferView, - srcOffset:Int = 0):Void + public inline function texSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Int, type:Int, srcData:ArrayBufferView, + srcOffset:Int = 0):Void #else - public inline function texSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Dynamic, - ?type:Int, ?srcData:Dynamic, - ?srcOffset:Int):Void + public inline function texSubImage2D(target:Int, level:Int, xoffset:Int, yoffset:Int, width:Int, height:Int, format:Dynamic, ?type:Int, ?srcData:Dynamic, + ?srcOffset:Int):Void #end { __tempPointer.set(srcData, srcOffset); this.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, __tempPointer); } - public inline function texSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, width:Int, height:Int, - depth:Int, format:Int, type:Int, + public inline function texSubImage3D(target:Int, level:Int, xoffset:Int, yoffset:Int, zoffset:Int, width:Int, height:Int, depth:Int, format:Int, type:Int, srcData:ArrayBufferView, srcOffset:Int = 0):Void { __tempPointer.set(srcData, srcOffset); @@ -4673,8 +4656,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.uniform2ui(location, v0, v1); } - public inline function uniform2uiv(location:GLUniformLocation, v:UInt32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform2uiv(location:GLUniformLocation, v:UInt32Array, ?srcOffset:Int, ?srcLength:Int):Void { this.uniform2uiv(location, v != null ? v.length >> 1 : 0, v); } @@ -4685,11 +4667,9 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function uniform3fv(location:GLUniformLocation, v:Float32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform3fv(location:GLUniformLocation, v:Float32Array, ?srcOffset:Int, ?srcLength:Int):Void #else - public inline function uniform3fv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform3fv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { this.uniform3fv(location, v != null ? Std.int(v.length / 3) : 0, v); @@ -4701,11 +4681,9 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public inline function uniform3iv(location:GLUniformLocation, v:Int32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform3iv(location:GLUniformLocation, v:Int32Array, ?srcOffset:Int, ?srcLength:Int):Void #else - public inline function uniform3iv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform3iv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { this.uniform3iv(location, v != null ? Std.int(v.length / 3) : 0, v); @@ -4716,82 +4694,68 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.uniform3ui(location, v0, v1, v2); } - public inline function uniform3uiv(location:GLUniformLocation, v:UInt32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform3uiv(location:GLUniformLocation, v:UInt32Array, ?srcOffset:Int, ?srcLength:Int):Void { this.uniform3uiv(location, v != null ? Std.int(v.length / 3) : 0, v); } - public inline function uniform4f(location:GLUniformLocation, v0:Float, v1:Float, v2:Float, - v3:Float):Void + public inline function uniform4f(location:GLUniformLocation, v0:Float, v1:Float, v2:Float, v3:Float):Void { this.uniform4f(location, v0, v1, v2, v3); } #if !lime_webgl - public inline function uniform4fv(location:GLUniformLocation, v:Float32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform4fv(location:GLUniformLocation, v:Float32Array, ?srcOffset:Int, ?srcLength:Int):Void #else - public inline function uniform4fv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform4fv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { this.uniform4fv(location, v != null ? v.length >> 2 : 0, v); } - public inline function uniform4i(location:GLUniformLocation, v0:Int, v1:Int, v2:Int, - v3:Int):Void + public inline function uniform4i(location:GLUniformLocation, v0:Int, v1:Int, v2:Int, v3:Int):Void { this.uniform4i(location, v0, v1, v2, v3); } #if !lime_webgl - public inline function uniform4iv(location:GLUniformLocation, v:Int32Array, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform4iv(location:GLUniformLocation, v:Int32Array, ?srcOffset:Int, ?srcLength:Int):Void #else - public inline function uniform4iv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, - ?srcLength:Int):Void + public inline function uniform4iv(location:GLUniformLocation, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { this.uniform4iv(location, v != null ? v.length >> 2 : 0, v); } - public inline function uniform4ui(location:GLUniformLocation, v0:Int, v1:Int, v2:Int, - v3:Int):Void + public inline function uniform4ui(location:GLUniformLocation, v0:Int, v1:Int, v2:Int, v3:Int):Void { this.uniform4ui(location, v0, v1, v2, v3); } - public inline function uniform4uiv(location:GLUniformLocation, v:UInt32Array, - ?srcOffset:Int, ?srcLength:Int):Void + public inline function uniform4uiv(location:GLUniformLocation, v:UInt32Array, ?srcOffset:Int, ?srcLength:Int):Void { this.uniform4uiv(location, v != null ? v.length >> 2 : 0, v); } - public inline function uniformBlockBinding(program:GLProgram, uniformBlockIndex:Int, - uniformBlockBinding:Int):Void + public inline function uniformBlockBinding(program:GLProgram, uniformBlockIndex:Int, uniformBlockBinding:Int):Void { this.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); } #if !lime_webgl - public function uniformMatrix2fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix2fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void #else - public inline function uniformMatrix2fv(location:GLUniformLocation, transpose:Bool, - v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void + public inline function uniformMatrix2fv(location:GLUniformLocation, transpose:Bool, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { var count = 0; - if (srcLength != null) count = srcLength; else if (v != null) count = v.length >> 2; __tempPointer.set(v, srcOffset); this.uniformMatrix2fv(location, count, transpose, __tempPointer); } - public function uniformMatrix2x3fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix2x3fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4802,8 +4766,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.uniformMatrix2x3fv(location, count, transpose, __tempPointer); } - public function uniformMatrix2x4fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix2x4fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4815,23 +4778,19 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public function uniformMatrix3fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix3fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void #else - public inline function uniformMatrix3fv(location:GLUniformLocation, transpose:Bool, - v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void + public inline function uniformMatrix3fv(location:GLUniformLocation, transpose:Bool, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { var count = 0; - if (srcLength != null) count = srcLength; else if (v != null) count = Std.int(v.length / 9); __tempPointer.set(v, srcOffset); this.uniformMatrix3fv(location, count, transpose, __tempPointer); } - public function uniformMatrix3x2fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix3x2fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4842,8 +4801,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.uniformMatrix3x2fv(location, count, transpose, __tempPointer); } - public function uniformMatrix3x4fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix3x4fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4855,23 +4813,19 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic } #if !lime_webgl - public function uniformMatrix4fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix4fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void #else - public inline function uniformMatrix4fv(location:GLUniformLocation, transpose:Bool, - v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void + public inline function uniformMatrix4fv(location:GLUniformLocation, transpose:Bool, v:Dynamic, ?srcOffset:Int, ?srcLength:Int):Void #end { var count = 0; - if (srcLength != null) count = srcLength; else if (v != null) count = v.length >> 4; __tempPointer.set(v, srcOffset); this.uniformMatrix4fv(location, count, transpose, __tempPointer); } - public function uniformMatrix4x2fv(location:GLUniformLocation, - transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix4x2fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4882,8 +4836,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.uniformMatrix4x2fv(location, count, transpose, __tempPointer); } - public function uniformMatrix4x3fv(location:GLUniformLocation, transpose:Bool, - v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void + public function uniformMatrix4x3fv(location:GLUniformLocation, transpose:Bool, v:Float32Array, srcOffset:Int = 0, ?srcLength:Int):Void { var count = 0; if (srcLength != null) count = srcLength; @@ -4909,8 +4862,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.vertexAttrib1f(indx, x); } - public inline function vertexAttrib1fv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttrib1fv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttrib1fv(indx, values); } @@ -4920,8 +4872,7 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.vertexAttrib2f(indx, x, y); } - public inline function vertexAttrib2fv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttrib2fv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttrib2fv(indx, values); } @@ -4931,20 +4882,17 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.vertexAttrib3f(indx, x, y, z); } - public inline function vertexAttrib3fv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttrib3fv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttrib3fv(indx, values); } - public inline function vertexAttrib4f(indx:Int, x:Float, y:Float, z:Float, - w:Float):Void + public inline function vertexAttrib4f(indx:Int, x:Float, y:Float, z:Float, w:Float):Void { this.vertexAttrib4f(indx, x, y, z, w); } - public inline function vertexAttrib4fv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttrib4fv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttrib4fv(indx, values); } @@ -4954,38 +4902,32 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic this.vertexAttribDivisor(index, divisor); } - public inline function vertexAttribI4i(indx:Int, x:Int, y:Int, z:Int, - w:Int):Void + public inline function vertexAttribI4i(indx:Int, x:Int, y:Int, z:Int, w:Int):Void { this.vertexAttribI4i(indx, x, y, z, w); } - public inline function vertexAttribI4iv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttribI4iv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttribI4iv(indx, values); } - public inline function vertexAttribI4ui(indx:Int, x:Int, y:Int, z:Int, - w:Int):Void + public inline function vertexAttribI4ui(indx:Int, x:Int, y:Int, z:Int, w:Int):Void { this.vertexAttribI4ui(indx, x, y, z, w); } - public inline function vertexAttribI4uiv(indx:Int, - values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void + public inline function vertexAttribI4uiv(indx:Int, values:#if (!lime_webgl && !doc_gen) DataPointer #else Float32Array #end):Void { this.vertexAttribI4uiv(indx, values); } - public inline function vertexAttribIPointer(index:Int, size:Int, type:Int, - stride:Int, offset:DataPointer):Void + public inline function vertexAttribIPointer(index:Int, size:Int, type:Int, stride:Int, offset:DataPointer):Void { this.vertexAttribIPointer(index, size, type, stride, offset); } - public inline function vertexAttribPointer(indx:Int, size:Int, type:Int, - normalized:Bool, stride:Int, offset:DataPointer):Void + public inline function vertexAttribPointer(indx:Int, size:Int, type:Int, normalized:Bool, stride:Int, offset:DataPointer):Void { this.vertexAttribPointer(indx, size, type, normalized, stride, offset); } @@ -5016,5 +4958,5 @@ abstract WebGL2RenderContext(Dynamic) from Dynamic to Dynamic { return cast GL.context; } -} + } #end diff --git a/src/lime/graphics/vulkan/VK.hx b/src/lime/graphics/vulkan/VK.hx index 93e9a0137b..35f47c8f1d 100644 --- a/src/lime/graphics/vulkan/VK.hx +++ b/src/lime/graphics/vulkan/VK.hx @@ -5,7 +5,6 @@ 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 @@ -352,8 +351,7 @@ class VK 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 + public static function pickPhysicalDevice(devices:Array, requirePresent:Bool = false, preferDiscrete:Bool = true):VKPhysicalDevice { if (devices == null || devices.length == 0) { diff --git a/src/lime/graphics/vulkan/VKBuffer.hx b/src/lime/graphics/vulkan/VKBuffer.hx index de31962199..c87157323e 100644 --- a/src/lime/graphics/vulkan/VKBuffer.hx +++ b/src/lime/graphics/vulkan/VKBuffer.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import haxe.io.Bytes; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKCommandBuffer.hx b/src/lime/graphics/vulkan/VKCommandBuffer.hx index 12638f2e2a..01ba3250ca 100644 --- a/src/lime/graphics/vulkan/VKCommandBuffer.hx +++ b/src/lime/graphics/vulkan/VKCommandBuffer.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -47,21 +46,19 @@ class VKCommandBuffer } } - 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 + 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()) + 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); + 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 @@ -86,9 +83,9 @@ class VKCommandBuffer 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); + 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 @@ -120,9 +117,8 @@ class VKCommandBuffer #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); + 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 @@ -134,9 +130,8 @@ class VKCommandBuffer #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); + 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 @@ -153,9 +148,8 @@ class VKCommandBuffer #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); + 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 @@ -170,9 +164,9 @@ class VKCommandBuffer 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, + 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; @@ -213,15 +207,14 @@ class VKCommandBuffer 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 + 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]); + 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 @@ -229,25 +222,33 @@ class VKCommandBuffer } 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 + 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]; + 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]); + 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 + 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]; @@ -255,8 +256,8 @@ class VKCommandBuffer #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); + 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 @@ -267,7 +268,14 @@ class VKCommandBuffer { 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]; + 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()) @@ -281,16 +289,14 @@ class VKCommandBuffer return false; } - public function copyBufferToImage(buffer:VKBuffer, image:VKImage, width:Int, height:Int, - layout:Int = VK.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL):Bool + 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 + 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 = [ @@ -312,7 +318,13 @@ class VKCommandBuffer ]; #if (!macro && lime_cffi && lime_vulkan) - if (isValid() && device != null && device.isValid() && buffer != null && buffer.isValid() && image != null && image.isValid()) + 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, @@ -323,10 +335,9 @@ class VKCommandBuffer 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 + 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 = [ @@ -348,7 +359,13 @@ class VKCommandBuffer ]; #if (!macro && lime_cffi && lime_vulkan) - if (isValid() && device != null && device.isValid() && image != null && image.isValid() && buffer != null && buffer.isValid()) + 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, @@ -390,9 +407,9 @@ class VKCommandBuffer #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); + 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 @@ -431,8 +448,8 @@ class VKCommandBuffer #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); + 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 @@ -465,8 +482,19 @@ class VKCommandBuffer 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]; + 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()) @@ -479,8 +507,7 @@ class VKCommandBuffer return false; } - public function pushConstants(layout:VKPipelineLayout, stageFlags:Int, bytes:haxe.io.Bytes, offset:Int = 0, byteOffset:Int = 0, - byteLength:Int = -1):Bool + 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) { @@ -495,9 +522,8 @@ class VKCommandBuffer #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); + 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 diff --git a/src/lime/graphics/vulkan/VKCommandPool.hx b/src/lime/graphics/vulkan/VKCommandPool.hx index a95be9ee2e..f01e0c3a71 100644 --- a/src/lime/graphics/vulkan/VKCommandPool.hx +++ b/src/lime/graphics/vulkan/VKCommandPool.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKDescriptorPool.hx b/src/lime/graphics/vulkan/VKDescriptorPool.hx index e754efbb31..8763407d72 100644 --- a/src/lime/graphics/vulkan/VKDescriptorPool.hx +++ b/src/lime/graphics/vulkan/VKDescriptorPool.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKDescriptorSet.hx b/src/lime/graphics/vulkan/VKDescriptorSet.hx index 26c7d806c6..8fe7110a9f 100644 --- a/src/lime/graphics/vulkan/VKDescriptorSet.hx +++ b/src/lime/graphics/vulkan/VKDescriptorSet.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -33,24 +32,23 @@ class VKDescriptorSet return !VK.__isZero(handle); } - public function updateBuffer(binding:Int, buffer:VKBuffer, range:Int, offset:Int = 0, - descriptorType:Int = VK.DESCRIPTOR_TYPE_UNIFORM_BUFFER):Bool + 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); + 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 + 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(); @@ -58,8 +56,8 @@ class VKDescriptorSet { 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); + 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 diff --git a/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx b/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx index d14fb572ba..fd6a04d14c 100644 --- a/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx +++ b/src/lime/graphics/vulkan/VKDescriptorSetLayout.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -25,8 +24,8 @@ class VKDescriptorSetLayout #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); + 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 diff --git a/src/lime/graphics/vulkan/VKDescriptorWrite.hx b/src/lime/graphics/vulkan/VKDescriptorWrite.hx index 5768a76244..b06c522d7e 100644 --- a/src/lime/graphics/vulkan/VKDescriptorWrite.hx +++ b/src/lime/graphics/vulkan/VKDescriptorWrite.hx @@ -34,8 +34,8 @@ class VKDescriptorWrite 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 + 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; @@ -50,8 +50,8 @@ class VKDescriptorWrite } 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 + 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; diff --git a/src/lime/graphics/vulkan/VKDevice.hx b/src/lime/graphics/vulkan/VKDevice.hx index 28e375114e..50bd192581 100644 --- a/src/lime/graphics/vulkan/VKDevice.hx +++ b/src/lime/graphics/vulkan/VKDevice.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import haxe.io.Bytes; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -42,8 +41,8 @@ class VKDevice #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 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)) { @@ -103,8 +102,8 @@ class VKDevice #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 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)) { @@ -147,8 +146,8 @@ class VKDevice 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); + 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, @@ -217,8 +216,8 @@ class VKDevice #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 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)) { @@ -278,8 +277,8 @@ class VKDevice #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 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)) { @@ -291,8 +290,8 @@ class VKDevice return null; } - public function createGraphicsPipeline(renderPass:VKRenderPass, layout:VKPipelineLayout, vertexShader:VKShaderModule, - fragmentShader:VKShaderModule, info:VKGraphicsPipelineInfo, cache:VKPipelineCache = null):VKPipeline + 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) { @@ -309,8 +308,8 @@ class VKDevice 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)); + 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)) { @@ -328,8 +327,8 @@ class VKDevice #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 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)) { @@ -397,16 +396,13 @@ class VKDevice 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 + 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()) @@ -429,8 +425,8 @@ class VKDevice 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 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)) { @@ -443,14 +439,14 @@ class VKDevice } 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 + 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 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)) { @@ -467,8 +463,8 @@ class VKDevice #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 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)) { @@ -519,8 +515,8 @@ class VKDevice { 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); + 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)) { diff --git a/src/lime/graphics/vulkan/VKDeviceMemory.hx b/src/lime/graphics/vulkan/VKDeviceMemory.hx index 39dc6ad5ee..ef742ebffc 100644 --- a/src/lime/graphics/vulkan/VKDeviceMemory.hx +++ b/src/lime/graphics/vulkan/VKDeviceMemory.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import haxe.io.Bytes; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -78,9 +77,8 @@ class VKDeviceMemory #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); + 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; @@ -131,9 +129,8 @@ class VKDeviceMemory #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); + 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 @@ -158,9 +155,8 @@ class VKDeviceMemory #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); + 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 @@ -186,8 +182,7 @@ class VKDeviceMemory 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); + device.instance.handle.low, device.handle.high, device.handle.low, handle.high, handle.low, offset.high, offset.low, size.high, size.low); } #end diff --git a/src/lime/graphics/vulkan/VKFence.hx b/src/lime/graphics/vulkan/VKFence.hx index 6fd009ac1f..9fc7d1779a 100644 --- a/src/lime/graphics/vulkan/VKFence.hx +++ b/src/lime/graphics/vulkan/VKFence.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKFramebuffer.hx b/src/lime/graphics/vulkan/VKFramebuffer.hx index be12eaf8b9..d2298a2f09 100644 --- a/src/lime/graphics/vulkan/VKFramebuffer.hx +++ b/src/lime/graphics/vulkan/VKFramebuffer.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKImage.hx b/src/lime/graphics/vulkan/VKImage.hx index 491f40350a..fd5a556a81 100644 --- a/src/lime/graphics/vulkan/VKImage.hx +++ b/src/lime/graphics/vulkan/VKImage.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -82,9 +81,8 @@ class VKImage #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); + 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; @@ -96,8 +94,8 @@ class VKImage 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 + 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) { @@ -108,8 +106,8 @@ class VKImage 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); + 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)) { diff --git a/src/lime/graphics/vulkan/VKImageView.hx b/src/lime/graphics/vulkan/VKImageView.hx index 5cf888f93a..6f911c1b60 100644 --- a/src/lime/graphics/vulkan/VKImageView.hx +++ b/src/lime/graphics/vulkan/VKImageView.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKInstance.hx b/src/lime/graphics/vulkan/VKInstance.hx index 71d4e079a3..42601584fc 100644 --- a/src/lime/graphics/vulkan/VKInstance.hx +++ b/src/lime/graphics/vulkan/VKInstance.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import lime.graphics.VulkanRenderContext; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKPhysicalDevice.hx b/src/lime/graphics/vulkan/VKPhysicalDevice.hx index c05a23fc4f..f21d0e9d0b 100644 --- a/src/lime/graphics/vulkan/VKPhysicalDevice.hx +++ b/src/lime/graphics/vulkan/VKPhysicalDevice.hx @@ -121,7 +121,7 @@ class VKPhysicalDevice 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 + requireTransfer:Bool = false):VKQueueFamilyInfo { for (queueFamily in queueFamilies) { @@ -135,7 +135,7 @@ class VKPhysicalDevice } public inline function hasQueueFamily(requireGraphics:Bool = true, requirePresent:Bool = false, requireCompute:Bool = false, - requireTransfer:Bool = false):Bool + requireTransfer:Bool = false):Bool { return getQueueFamily(requireGraphics, requirePresent, requireCompute, requireTransfer) != null; } @@ -152,8 +152,14 @@ class VKPhysicalDevice 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]) + 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) { diff --git a/src/lime/graphics/vulkan/VKPipeline.hx b/src/lime/graphics/vulkan/VKPipeline.hx index 20b377ec44..6baa424b04 100644 --- a/src/lime/graphics/vulkan/VKPipeline.hx +++ b/src/lime/graphics/vulkan/VKPipeline.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKPipelineCache.hx b/src/lime/graphics/vulkan/VKPipelineCache.hx index e690940e26..9214294458 100644 --- a/src/lime/graphics/vulkan/VKPipelineCache.hx +++ b/src/lime/graphics/vulkan/VKPipelineCache.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import haxe.io.Bytes; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -49,8 +48,8 @@ class VKPipelineCache 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)) + 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; } diff --git a/src/lime/graphics/vulkan/VKPipelineLayout.hx b/src/lime/graphics/vulkan/VKPipelineLayout.hx index 83c3b77ed2..958a77c519 100644 --- a/src/lime/graphics/vulkan/VKPipelineLayout.hx +++ b/src/lime/graphics/vulkan/VKPipelineLayout.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKQueue.hx b/src/lime/graphics/vulkan/VKQueue.hx index a372e78d26..6e563c193a 100644 --- a/src/lime/graphics/vulkan/VKQueue.hx +++ b/src/lime/graphics/vulkan/VKQueue.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -80,8 +79,8 @@ class VKQueue 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 + 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()) @@ -89,7 +88,15 @@ class VKQueue 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]; + 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); diff --git a/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx b/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx index d8df278384..d80c4ed39c 100644 --- a/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx +++ b/src/lime/graphics/vulkan/VKQueueFamilyInfo.hx @@ -30,8 +30,7 @@ class VKQueueFamilyInfo /** 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 + 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; diff --git a/src/lime/graphics/vulkan/VKRenderPass.hx b/src/lime/graphics/vulkan/VKRenderPass.hx index 8a7ddfe95c..fa0f580e70 100644 --- a/src/lime/graphics/vulkan/VKRenderPass.hx +++ b/src/lime/graphics/vulkan/VKRenderPass.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKRenderer.hx b/src/lime/graphics/vulkan/VKRenderer.hx index d3b70e3023..25ca3651b6 100644 --- a/src/lime/graphics/vulkan/VKRenderer.hx +++ b/src/lime/graphics/vulkan/VKRenderer.hx @@ -7,7 +7,6 @@ import lime.system.CFFI; #if (!lime_doc_gen || lime_cffi) import lime.system.CFFIPointer; #end - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKSampler.hx b/src/lime/graphics/vulkan/VKSampler.hx index 69504203a1..7c3cbafd67 100644 --- a/src/lime/graphics/vulkan/VKSampler.hx +++ b/src/lime/graphics/vulkan/VKSampler.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKSemaphore.hx b/src/lime/graphics/vulkan/VKSemaphore.hx index 4128be555b..9301dfc3c6 100644 --- a/src/lime/graphics/vulkan/VKSemaphore.hx +++ b/src/lime/graphics/vulkan/VKSemaphore.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKShaderModule.hx b/src/lime/graphics/vulkan/VKShaderModule.hx index 4204a32c3a..09edfc1411 100644 --- a/src/lime/graphics/vulkan/VKShaderModule.hx +++ b/src/lime/graphics/vulkan/VKShaderModule.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKSurface.hx b/src/lime/graphics/vulkan/VKSurface.hx index 6abd8988fb..f6166a3e41 100644 --- a/src/lime/graphics/vulkan/VKSurface.hx +++ b/src/lime/graphics/vulkan/VKSurface.hx @@ -2,7 +2,6 @@ package lime.graphics.vulkan; import haxe.Int64; import lime.graphics.VulkanRenderContext; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end diff --git a/src/lime/graphics/vulkan/VKSwapchain.hx b/src/lime/graphics/vulkan/VKSwapchain.hx index 389c36e58e..089f38adcd 100644 --- a/src/lime/graphics/vulkan/VKSwapchain.hx +++ b/src/lime/graphics/vulkan/VKSwapchain.hx @@ -1,7 +1,6 @@ package lime.graphics.vulkan; import haxe.Int64; - #if (!lime_doc_gen || lime_cffi) import lime._internal.backend.native.NativeCFFI; #end @@ -56,8 +55,8 @@ class VKSwapchain 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); + 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) { diff --git a/src/lime/math/Matrix3.hx b/src/lime/math/Matrix3.hx index 330cad97c9..15aedcbdd1 100644 --- a/src/lime/math/Matrix3.hx +++ b/src/lime/math/Matrix3.hx @@ -70,9 +70,15 @@ abstract Matrix3(Float32Array) to Float32Array { // Column-major order means adjacent values form a column, not a row. this = new Float32Array([ - a, b, 0, // column 0 - c, d, 0, // column 1 - tx, ty, 1 // column 2 + a, + b, + 0, // column 0 + c, + d, + 0, // column 1 + tx, + ty, + 1 // column 2 ]); } @@ -561,7 +567,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[0]; } - inline function set_a(value: Float):Float + + inline function set_a(value:Float):Float { return this[0] = value; } @@ -570,7 +577,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[1]; } - inline function set_b(value: Float):Float + + inline function set_b(value:Float):Float { return this[1] = value; } @@ -579,7 +587,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[3]; } - inline function set_c(value: Float):Float + + inline function set_c(value:Float):Float { return this[3] = value; } @@ -588,7 +597,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[4]; } - inline function set_d(value: Float):Float + + inline function set_d(value:Float):Float { return this[4] = value; } @@ -597,7 +607,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[6]; } - inline function set_tx(value: Float):Float + + inline function set_tx(value:Float):Float { return this[6] = value; } @@ -606,7 +617,8 @@ abstract Matrix3(Float32Array) to Float32Array { return this[7]; } - inline function set_ty(value: Float):Float + + inline function set_ty(value:Float):Float { return this[7] = value; } diff --git a/src/lime/math/Matrix4.hx b/src/lime/math/Matrix4.hx index ee479fbb78..65807d478b 100644 --- a/src/lime/math/Matrix4.hx +++ b/src/lime/math/Matrix4.hx @@ -378,7 +378,7 @@ abstract Matrix4(Float32Array) from Float32Array to Float32Array this[14] = -(zNear + zFar) * sz; this[15] = 1; } - + /** Initializes this matrix with values for a perspective projection @param fov The field of view diff --git a/src/lime/media/AudioBuffer.hx b/src/lime/media/AudioBuffer.hx index 1cf584c5d8..b3cfa7e1d3 100644 --- a/src/lime/media/AudioBuffer.hx +++ b/src/lime/media/AudioBuffer.hx @@ -396,7 +396,6 @@ class AudioBuffer @return An `AudioBuffer` instance with the decoded audio data. **/ #if lime_vorbis - public static function fromVorbisFile(vorbisFile:VorbisFile):AudioBuffer { if (vorbisFile == null) return null; @@ -509,22 +508,19 @@ class AudioBuffer var promise = new Promise(); var request = new HTTPRequest(); - request.load(path) - .onProgress(promise.progress) - .onComplete(function(bytes) + request.load(path).onProgress(promise.progress).onComplete(function(bytes) + { + var buffer = fromBytesStream(bytes); + + if (buffer != null) { - var buffer = fromBytesStream(bytes); - - if (buffer != null) - { - promise.complete(buffer); - } - else - { - promise.error(""); - } - }) - .onError(promise.error); + promise.complete(buffer); + } + else + { + promise.error(""); + } + }).onError(promise.error); return promise.future; } @@ -694,7 +690,7 @@ class AudioBuffer } }).onError(function(_) { - __loadFromFilesStream(paths, promise, index + 1); + __loadFromFilesStream(paths, promise, index + 1); }); } diff --git a/src/lime/media/AudioInput.hx b/src/lime/media/AudioInput.hx index 17446ff888..7fc3919d97 100644 --- a/src/lime/media/AudioInput.hx +++ b/src/lime/media/AudioInput.hx @@ -7,6 +7,7 @@ import lime.app.Event; @:fileXml('tags="haxe,release"') @:noDebug #end + /** The `AudioInput` class provides polling-based access to microphone or other audio capture input. diff --git a/src/lime/media/AudioInputDevice.hx b/src/lime/media/AudioInputDevice.hx index 948fe799a9..cfcf4a6ced 100644 --- a/src/lime/media/AudioInputDevice.hx +++ b/src/lime/media/AudioInputDevice.hx @@ -4,6 +4,7 @@ package lime.media; @:fileXml('tags="haxe,release"') @:noDebug #end + /** The `AudioInputDevice` class describes an audio capture device that can be used with `AudioInput`. diff --git a/src/lime/media/AudioSource.hx b/src/lime/media/AudioSource.hx index 2ccc9b1465..5e883167ad 100644 --- a/src/lime/media/AudioSource.hx +++ b/src/lime/media/AudioSource.hx @@ -9,6 +9,7 @@ import lime.math.Vector4; @:fileXml('tags="haxe,release"') @:noDebug #end + /** The `AudioSource` class provides a way to control audio playback in a Lime application. It allows for playing, pausing, and stopping audio, as well as controlling various @@ -24,7 +25,7 @@ class AudioSource An event that is dispatched when the audio playback is complete. **/ public var onComplete = new EventVoid>(); - + /** The `AudioBuffer` associated with this `AudioSource`. **/ @@ -78,16 +79,13 @@ class AudioSource { this.buffer = buffer; this.offset = offset; - __backend = new AudioSourceBackend(this); if (length != null && length != 0) { this.length = length; } - this.loops = loops; - if (buffer != null) { init(); diff --git a/src/lime/media/OpenALAudioContext.hx b/src/lime/media/OpenALAudioContext.hx index 9d7b7d21a7..b7d0cc90e6 100644 --- a/src/lime/media/OpenALAudioContext.hx +++ b/src/lime/media/OpenALAudioContext.hx @@ -412,8 +412,13 @@ class OpenALAudioContext return ALC.getString(device, param); } - 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) + 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(cast null, param); } diff --git a/src/lime/net/HTTPRequest.hx b/src/lime/net/HTTPRequest.hx index 70c0ac8fe8..6703673b52 100644 --- a/src/lime/net/HTTPRequest.hx +++ b/src/lime/net/HTTPRequest.hx @@ -160,10 +160,13 @@ public function load(uri:String = null):Future } } -@:noCompletion class _HTTPRequestErrorResponse { +@:noCompletion class _HTTPRequestErrorResponse +{ public var error:Dynamic; public var responseData:T; - public function new(error:Dynamic, responseData:T) { + + public function new(error:Dynamic, responseData:T) + { this.error = error; this.responseData = responseData; } diff --git a/src/lime/system/BackgroundWorker.hx b/src/lime/system/BackgroundWorker.hx index 30d69d1ed8..df72812a36 100644 --- a/src/lime/system/BackgroundWorker.hx +++ b/src/lime/system/BackgroundWorker.hx @@ -14,7 +14,6 @@ import neko.vm.Deque; import neko.vm.Thread; #end #end - /** A `BackgroundWorker` allows the execution of a function on a background thread, avoiding the blocking of the main thread. This is particularly useful for long-running @@ -24,7 +23,7 @@ import neko.vm.Thread; - **Thread Support:** Only system targets (such as C++, Neko) support threading. - **Events:** The class uses the `Event` class to dispatch completion, error, and progress notifications. - + @see `ThreadPool` for more advanced threading capabilities, including thread safety, HTML5 threads, and more robust handling of tasks. **/ @@ -62,7 +61,7 @@ class BackgroundWorker Dispatched if an error occurs during the execution of the worker's task. **/ public var onError = new EventVoid>(); - + /** Dispatched periodically during the worker's task to provide progress updates. **/ @@ -154,7 +153,7 @@ class BackgroundWorker } #end } - + /** Sends a progress update message. @param message An optional message to pass to the `onProgress` event. diff --git a/src/lime/system/CFFI.hx b/src/lime/system/CFFI.hx index add385db32..20fb07e438 100644 --- a/src/lime/system/CFFI.hx +++ b/src/lime/system/CFFI.hx @@ -315,7 +315,10 @@ class CFFI var ndllFolder = __findNDLLFolder() + __sysName(); throw "Could not load lime.ndll. This file is provided with Lime's Haxelib releases, but not via Git. " + "Please copy it from Lime's latest Haxelib release into either " - + ndllFolder + " or " + ndllFolder + "64, as appropriate for your system. " + + ndllFolder + + " or " + + ndllFolder + + "64, as appropriate for your system. " + "Advanced users may run `lime rebuild cpp` instead." + (error != null ? '\nInternal error: $error' : ""); } diff --git a/src/lime/system/JNI.hx b/src/lime/system/JNI.hx index 8c1c4ad5bd..ed2007028b 100644 --- a/src/lime/system/JNI.hx +++ b/src/lime/system/JNI.hx @@ -17,7 +17,6 @@ import cpp.vm.Thread; import neko.vm.Thread; #end #end - using StringTools; /** @@ -51,12 +50,10 @@ class JNI private static function transformClassName(className:String):String { var parts:Array = className.split("."); - if (parts.length <= 1) - return className; + if (parts.length <= 1) return className; var nestedClassName:String = ""; - if (~/^[A-Z]/.match(parts[parts.length - 2])) - nestedClassName = "$" + parts.pop(); + if (~/^[A-Z]/.match(parts[parts.length - 2])) nestedClassName = "$" + parts.pop(); return parts.join("/") + nestedClassName; } @@ -430,8 +427,7 @@ class JNISafetyTools } // Don't modify functions lacking `@:runOnMainThread`. - if (field.meta == null || !Lambda.exists(field.meta, - function(meta) return meta.name == ":runOnMainThread")) + if (field.meta == null || !Lambda.exists(field.meta, function(meta) return meta.name == ":runOnMainThread")) { continue; } @@ -445,13 +441,12 @@ class JNISafetyTools // Make sure there's no return value. switch (f.ret) { - case macro:Void: + case macro :Void: // Good to go. case null: - f.ret = macro:Void; + f.ret = macro :Void; default: - Context.error("Expected return type Void, got " - + new haxe.macro.Printer().printComplexType(f.ret) + ".", field.pos); + Context.error("Expected return type Void, got " + new haxe.macro.Printer().printComplexType(f.ret) + ".", field.pos); } var args:Array = []; @@ -460,16 +455,12 @@ class JNISafetyTools args.push(macro $i{arg.name}); // Account for an unlikely edge case. - if (arg.name == field.name) - Context.error('${field.name}() should not take an argument named ${field.name}.', field.pos); + if (arg.name == field.name) Context.error('${field.name}() should not take an argument named ${field.name}.', field.pos); } // Check the thread before running the function. - f.expr = macro - if (!lime.system.JNI.JNISafetyTools.onMainThread()) - haxe.MainLoop.runInMainThread($i{field.name}.bind($a{args})) - else - ${f.expr}; + f.expr = macro if (!lime.system.JNI.JNISafetyTools.onMainThread()) haxe.MainLoop.runInMainThread($i{field.name}.bind($a{args})) else + ${f.expr}; default: } } diff --git a/src/lime/system/Orientation.hx b/src/lime/system/Orientation.hx index b3d076b908..34e5bfb95a 100644 --- a/src/lime/system/Orientation.hx +++ b/src/lime/system/Orientation.hx @@ -7,4 +7,4 @@ package lime.system; var LANDSCAPE_FLIPPED = 2; var PORTRAIT = 3; var PORTRAIT_FLIPPED = 4; -} \ No newline at end of file +} diff --git a/src/lime/system/System.hx b/src/lime/system/System.hx index 64dc264dc4..25c1fca04a 100644 --- a/src/lime/system/System.hx +++ b/src/lime/system/System.hx @@ -252,17 +252,16 @@ class System #if android var getDisplaySafeArea = JNI.createStaticMethod("org/haxe/lime/GameActivity", "getDisplaySafeAreaInsets", "()[I"); var result = getDisplaySafeArea(); - display.safeArea = new Rectangle( - display.bounds.x + result[0], - display.bounds.y + result[1], - display.bounds.width - result[0] - result[2], - display.bounds.height - result[1] - result[3]); + display.safeArea = new Rectangle(display.bounds.x + + result[0], display.bounds.y + + result[1], display.bounds.width + - result[0] + - result[2], + display.bounds.height + - result[1] + - result[3]); #else - display.safeArea = new Rectangle( - displayInfo.safeArea.x, - displayInfo.safeArea.y, - displayInfo.safeArea.width, - displayInfo.safeArea.height); + display.safeArea = new Rectangle(displayInfo.safeArea.x, displayInfo.safeArea.y, displayInfo.safeArea.width, displayInfo.safeArea.height); #end #if ios @@ -328,7 +327,8 @@ class System display.dpi = Capabilities.screenDPI; display.currentMode = new DisplayMode(Std.int(Capabilities.screenResolutionX), Std.int(Capabilities.screenResolutionY), 60, ARGB32); #if air - switch (flash.Lib.current.stage.orientation) { + switch (flash.Lib.current.stage.orientation) + { case DEFAULT: display.orientation = PORTRAIT; case UPSIDE_DOWN: @@ -340,7 +340,6 @@ class System default: display.orientation = UNKNOWN; } - #else display.orientation = UNKNOWN; #end diff --git a/src/lime/system/ThreadPool.hx b/src/lime/system/ThreadPool.hx index 6e0150341f..8cb6a874f7 100644 --- a/src/lime/system/ThreadPool.hx +++ b/src/lime/system/ThreadPool.hx @@ -16,7 +16,6 @@ import neko.vm.Thread; #elseif html5 import lime._internal.backend.html5.HTML5Thread as Thread; import lime._internal.backend.html5.HTML5Thread.Transferable; - #if lime_threads_deque #error "lime_threads_deque is not yet supported in HTML5" #end @@ -474,21 +473,21 @@ class ThreadPool extends WorkOutput } } #end - else if (event.jobID != null) + else if (event.jobID != null) + { + #if (lime_threads && lime_threads_deque) + // `cancelJob()` can't remove the job from the queue, so instead it + // marks it to be canceled later. (And "later" is now.) + if (event.event == WORK && event.threadID != null) { - #if (lime_threads && lime_threads_deque) - // `cancelJob()` can't remove the job from the queue, so instead it - // marks it to be canceled later. (And "later" is now.) - if (event.event == WORK && event.threadID != null) - { - __threads[event.threadID].thread.sendMessage({event: IDLE}); - __queuedWorkEvents--; - } - #end - - activeJob = oldActiveJob; - return; + __threads[event.threadID].thread.sendMessage({event: IDLE}); + __queuedWorkEvents--; } + #end + + activeJob = oldActiveJob; + return; + } switch (event.event) { @@ -514,7 +513,7 @@ class ThreadPool extends WorkOutput } else { - message = (event.message:Exception).details(); + message = (event.message : Exception).details(); } } else @@ -553,8 +552,7 @@ class ThreadPool extends WorkOutput case EXIT: var threadData:ThreadData = __threads[event.threadID]; - if (threadData.jobID != null) - activeThreads--; + if (threadData.jobID != null) activeThreads--; else __idleThreads--; @@ -834,7 +832,6 @@ class ThreadPool extends WorkOutput } #if lime_threads - /** Handles a thread that just became idle. Depending on the circumstances, this may do one of three things: @@ -897,12 +894,13 @@ class ThreadPool extends WorkOutput job.doWork.makePortable(); #end - var threadEvent:ThreadEvent = { - event: WORK, - jobID: job.id, - doWork: job.doWork, - state: job.state - }; + var threadEvent:ThreadEvent = + { + event: WORK, + jobID: job.id, + doWork: job.doWork, + state: job.state + }; #if lime_threads_deque __multiThreadedQueue.add(threadEvent); @@ -991,19 +989,19 @@ class ThreadPool extends WorkOutput __threads[index] = {thread: thread, jobID: null}; __idleThreads++; - thread.sendMessage({ - #if !html5 - output: this, - #end - #if lime_threads_deque - queue: __multiThreadedQueue, - #end - threadID: index - }); + thread.sendMessage( + { + #if !html5 + output: this, + #end + #if lime_threads_deque + queue: __multiThreadedQueue, + #end + threadID: index + }); return thread; } - #end // Getters & Setters @@ -1026,7 +1024,7 @@ class ThreadPool extends WorkOutput private inline function get_idleThreads():Int { return __idleThreads - #if lime_threads - __queuedExitEvents #end; + #if lime_threads - __queuedExitEvents #end; } private inline function set___singleThreadedJobRunning(value:Bool):Bool @@ -1255,7 +1253,8 @@ private abstract JobQueue(Deque) from Deque } #end -private typedef ThreadArguments = { +private typedef ThreadArguments = +{ #if !html5 var output:WorkOutput; #end @@ -1268,7 +1267,8 @@ private typedef ThreadArguments = { }; #if lime_threads -private typedef ThreadData = { +private typedef ThreadData = +{ var thread:Thread; @:optional var jobID:Int; }; diff --git a/src/lime/text/Font.hx b/src/lime/text/Font.hx index 586a75d25a..090499423f 100644 --- a/src/lime/text/Font.hx +++ b/src/lime/text/Font.hx @@ -35,56 +35,55 @@ import haxe.io.Path; class Font { /** - * The ascender value of the font. - */ + * The ascender value of the font. + */ public var ascender:Int; - /** - * The descender value of the font. - */ + /** + * The descender value of the font. + */ public var descender:Int; /** - * The height of the font. - */ + * The height of the font. + */ public var height:Int; /** - * The name of the font. - */ + * The name of the font. + */ public var name(default, null):String; /** - * The number of glyphs in the font. - */ + * The number of glyphs in the font. + */ public var numGlyphs:Int; - public var src:Dynamic; /** - * The underline position of the font. - */ + * The underline position of the font. + */ public var underlinePosition:Int; /** - * The underline thickness of the font. - */ + * The underline thickness of the font. + */ public var underlineThickness:Int; /** - * The underline position of the font. - */ + * The underline position of the font. + */ public var strikethroughPosition:Int; /** - * The underline thickness of the font. - */ + * The underline thickness of the font. + */ public var strikethroughThickness:Int; /** - * The units per EM of the font. - */ + * The units per EM of the font. + */ public var unitsPerEM:Int; @:noCompletion private var __fontID:String; @@ -95,10 +94,10 @@ class Font @:noCompletion private var __init:Bool; /** - * Creates a new instance of a Font object. - * - * @param name Optional name of the font. - */ + * Creates a new instance of a Font object. + * + * @param name Optional name of the font. + */ public function new(name:String = null) { if (name != null) @@ -149,19 +148,18 @@ class Font } /** - * Decomposes the font into outline data. - * - * @param forceAutoHint When `true`, force auto-hinting for outline decomposition. - * When `false`, preserve the unhinted glyph outlines. - * @return An instance of `NativeFontData` that contains decomposed font outline information. - */ + * Decomposes the font into outline data. + * + * @param forceAutoHint When `true`, force auto-hinting for outline decomposition. + * When `false`, preserve the unhinted glyph outlines. + * @return An instance of `NativeFontData` that contains decomposed font outline information. + */ public function decompose(forceAutoHint:Bool = true):NativeFontData { #if (lime_cffi && !macro) if (src == null) throw "Uninitialized font handle."; - var data:Dynamic = forceAutoHint - ? NativeCFFI.lime_font_outline_decompose(src, 1024 * 20) - : NativeCFFI.lime_font_outline_decompose_no_hint(src, 1024 * 20); + var data:Dynamic = forceAutoHint ? NativeCFFI.lime_font_outline_decompose(src, + 1024 * 20) : NativeCFFI.lime_font_outline_decompose_no_hint(src, 1024 * 20); #if hl if (data != null) { @@ -176,11 +174,11 @@ class Font } /** - * Creates a Font instance from byte data. - * - * @param bytes The byte data containing the font. - * @return A `Font` instance. - */ + * Creates a Font instance from byte data. + * + * @param bytes The byte data containing the font. + * @return A `Font` instance. + */ public static function fromBytes(bytes:Bytes):Font { if (bytes == null) return null; @@ -196,11 +194,11 @@ class Font } /** - * Creates a Font instance from a file path. - * - * @param path The file path of the font. - * @return A `Font` instance. - */ + * Creates a Font instance from a file path. + * + * @param path The file path of the font. + * @return A `Font` instance. + */ public static function fromFile(path:String):Font { if (path == null) return null; @@ -216,22 +214,22 @@ class Font } /** - * Loads a Font from byte data asynchronously. - * - * @param bytes The byte data containing the font. - * @return A `Future` containing a `Font` instance. - */ + * Loads a Font from byte data asynchronously. + * + * @param bytes The byte data containing the font. + * @return A `Future` containing a `Font` instance. + */ public static function loadFromBytes(bytes:Bytes):Future { return Future.withValue(fromBytes(bytes)); } /** - * Loads a Font from a file path asynchronously. - * - * @param path The file path of the font. - * @return A `Future` containing a `Font` instance. - */ + * Loads a Font from a file path asynchronously. + * + * @param path The file path of the font. + * @return A `Future` containing a `Font` instance. + */ public static function loadFromFile(path:String):Future { var request = new HTTPRequest(); @@ -249,11 +247,11 @@ class Font } /** - * Loads a Font by its name asynchronously. - * - * @param path The name of the font. - * @return A `Future` containing a `Font` instance. - */ + * Loads a Font by its name asynchronously. + * + * @param path The name of the font. + * @return A `Future` containing a `Font` instance. + */ public static function loadFromName(path:String):Future { #if (js && html5) @@ -265,11 +263,11 @@ class Font } /** - * Retrieves a glyph from the font by a character. - * - * @param character The character whose glyph to retrieve. - * @return A `Glyph` instance representing the glyph of the character. - */ + * Retrieves a glyph from the font by a character. + * + * @param character The character whose glyph to retrieve. + * @return A `Glyph` instance representing the glyph of the character. + */ public function getGlyph(character:String):Glyph { #if (lime_cffi && !macro) @@ -280,16 +278,18 @@ class Font } /** - * Retrieves an array of glyphs for a set of characters. - * - * @param characters The string containing characters to retrieve glyphs for. - * @return An array of `Glyph` instances representing the glyphs of the characters. - */ + * Retrieves an array of glyphs for a set of characters. + * + * @param characters The string containing characters to retrieve glyphs for. + * @return An array of `Glyph` instances representing the glyphs of the characters. + */ public function getGlyphs(characters:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "):Array { #if (lime_cffi && !macro) #if hl - return [for (index in NativeCFFI.lime_font_get_glyph_indices(src, characters)) new Glyph(index)]; + return [ + for (index in NativeCFFI.lime_font_get_glyph_indices(src, characters)) new Glyph(index) + ]; #else return NativeCFFI.lime_font_get_glyph_indices(src, characters); #end @@ -299,11 +299,11 @@ class Font } /** - * Retrieves metrics for a given glyph. - * - * @param glyph The glyph whose metrics to retrieve. - * @return A `GlyphMetrics` instance containing the metrics of the glyph. - */ + * Retrieves metrics for a given glyph. + * + * @param glyph The glyph whose metrics to retrieve. + * @return A `GlyphMetrics` instance containing the metrics of the glyph. + */ public function getGlyphMetrics(glyph:Glyph):GlyphMetrics { #if (lime_cffi && !macro) @@ -322,26 +322,26 @@ class Font } /** - * Renders a specific glyph to an image. - * - * @param glyph The glyph to render. - * @param fontSize The size to render the glyph at. - * @return An `Image` instance representing the rendered glyph. - */ + * Renders a specific glyph to an image. + * + * @param glyph The glyph to render. + * @param fontSize The size to render the glyph at. + * @return An `Image` instance representing the rendered glyph. + */ public function renderGlyph(glyph:Glyph, fontSize:Int, dpi:Int = 96):Image { return renderGlyphWithLoadFlags(glyph, fontSize, dpi); } /** - * Renders a specific glyph to an image using explicit FreeType load flags. - * - * @param glyph The glyph to render. - * @param fontSize The size to render the glyph at. - * @param dpi The DPI used to size the glyph before rasterization. - * @param loadFlags Additional FreeType load flags to apply when rasterizing. - * @return An `Image` instance representing the rendered glyph. - */ + * Renders a specific glyph to an image using explicit FreeType load flags. + * + * @param glyph The glyph to render. + * @param fontSize The size to render the glyph at. + * @param dpi The DPI used to size the glyph before rasterization. + * @param loadFlags Additional FreeType load flags to apply when rasterizing. + * @return An `Image` instance representing the rendered glyph. + */ public function renderGlyphWithLoadFlags(glyph:Glyph, fontSize:Int, dpi:Int = 96, ?loadFlags:Int):Image { #if (lime_cffi && !macro) @@ -351,9 +351,8 @@ class Font var bytes:Bytes = Bytes.alloc(0); // Allocate some reasonable initial size // Call native function to render glyph and get byte data - bytes = loadFlags == null - ? NativeCFFI.lime_font_render_glyph(src, glyph, bytes) - : NativeCFFI.lime_font_render_glyph_with_flags(src, glyph, loadFlags, bytes); + bytes = loadFlags == null ? NativeCFFI.lime_font_render_glyph(src, glyph, + bytes) : NativeCFFI.lime_font_render_glyph_with_flags(src, glyph, loadFlags, bytes); if (bytes != null && bytes.length > 0) { @@ -405,13 +404,14 @@ class Font return null; } + /** - * Renders a set of glyphs to images. - * - * @param glyphs The glyphs to render. - * @param fontSize The size to render the glyphs at. - * @return A `Map` containing glyphs mapped to their corresponding images. - */ + * Renders a set of glyphs to images. + * + * @param glyphs The glyphs to render. + * @param fontSize The size to render the glyphs at. + * @return A `Map` containing glyphs mapped to their corresponding images. + */ public function renderGlyphs(glyphs:Array, fontSize:Int):Map { #if (lime_cffi && !macro) @@ -760,8 +760,8 @@ class Font } /** -* Represents decomposed font data, containing kerning information, glyphs, and other properties. -*/ + * Represents decomposed font data, containing kerning information, glyphs, and other properties. + */ typedef NativeFontData = { var has_kerning:Bool; @@ -781,8 +781,8 @@ typedef NativeFontData = } /** -* Represents data for an individual glyph, including dimensions and control points. -*/ + * Represents data for an individual glyph, including dimensions and control points. + */ typedef NativeGlyphData = { var char_code:Int; @@ -795,8 +795,8 @@ typedef NativeGlyphData = } /** -* Represents kerning information between two glyphs. -*/ + * Represents kerning information between two glyphs. + */ typedef NativeKerningData = { var left_glyph:Int; diff --git a/src/lime/text/harfbuzz/HBBufferSerializeFormat.hx b/src/lime/text/harfbuzz/HBBufferSerializeFormat.hx index 92f60090e3..b932134305 100644 --- a/src/lime/text/harfbuzz/HBBufferSerializeFormat.hx +++ b/src/lime/text/harfbuzz/HBBufferSerializeFormat.hx @@ -12,6 +12,7 @@ package lime.text.harfbuzz; // // } } + // @:cffi private static function lime_hb_buffer_serialize_format_from_string (str:String, len:Int):Int; // @:cffi private static function lime_hb_buffer_serialize_format_to_string (format:Int):CFFIPointer; // @:cffi private static function lime_hb_buffer_serialize_list_formats ():CFFIPointer; diff --git a/src/lime/tools/AIRHelper.hx b/src/lime/tools/AIRHelper.hx index d3837bba5c..5495fc39cc 100644 --- a/src/lime/tools/AIRHelper.hx +++ b/src/lime/tools/AIRHelper.hx @@ -5,22 +5,20 @@ import sys.FileSystem; class AIRHelper { - public static function build(project:HXProject, workingDirectory:String, targetPlatform:Platform, targetPathWithoutExtension:String, applicationXML:String, - files:Array, fileDirectory:String = null):String + public static function build(project:HXProject, workingDirectory:String, targetPlatform:Platform, targetPathWithoutExtension:String, + applicationXML:String, files:Array, fileDirectory:String = null):String { var airTarget = "bundle"; - switch(targetPlatform) + switch (targetPlatform) { case WINDOWS: - if (project.targetFlags.exists("shared")) { airTarget = "air"; } case MAC: - if (project.targetFlags.exists("shared")) { airTarget = "air"; @@ -53,7 +51,8 @@ class AIRHelper exportMethod = m; } } - if (exportMethod == null && project.targetFlags.exists("final")) { + if (exportMethod == null && project.targetFlags.exists("final")) + { exportMethod = "appstore"; } @@ -122,14 +121,12 @@ class AIRHelper switch (targetPlatform) { case WINDOWS: - if (airTarget == "air") { extension = ".air"; } case MAC: - if (airTarget == "bundle") { extension = ".app"; @@ -140,7 +137,6 @@ class AIRHelper } case ANDROID: - if (StringTools.startsWith(airTarget, "aab")) { extension = ".aab"; @@ -155,7 +151,6 @@ class AIRHelper } case IOS: - extension = ".ipa"; default: diff --git a/src/lime/tools/ApplicationData.hx b/src/lime/tools/ApplicationData.hx index 301917209d..a81d4688c2 100644 --- a/src/lime/tools/ApplicationData.hx +++ b/src/lime/tools/ApplicationData.hx @@ -12,13 +12,14 @@ abstract ApplicationData({ }) from Dynamic { @:noCompletion - public static var expectedFields:ApplicationData = { - file: "", - init: "", - main: "", - path: "", - preloader: "", - swfVersion: 0.0, - url: "" - }; + public static var expectedFields:ApplicationData = + { + file: "", + init: "", + main: "", + path: "", + preloader: "", + swfVersion: 0.0, + url: "" + }; } diff --git a/src/lime/tools/AssetHelper.hx b/src/lime/tools/AssetHelper.hx index f0ab371c82..ed4bb6bdbb 100644 --- a/src/lime/tools/AssetHelper.hx +++ b/src/lime/tools/AssetHelper.hx @@ -25,13 +25,65 @@ class AssetHelper { knownExtensions = [ - "jpg" => IMAGE, "jpeg" => IMAGE, "png" => IMAGE, "gif" => IMAGE, "webp" => IMAGE, "bmp" => IMAGE, "tiff" => IMAGE, "jfif" => IMAGE, "otf" => FONT, - "ttf" => FONT, "wav" => SOUND, "wave" => SOUND, "flac" => SOUND, "mid" => SOUND, "midi" => SOUND, "ogg" => SOUND, "spx" => SOUND, "au" => SOUND, - "aiff" => SOUND, "oga" => SOUND, "mp3" => MUSIC, "mp2" => MUSIC, "exe" => BINARY, "bin" => BINARY, "so" => BINARY, "pch" => BINARY, - "dll" => BINARY, "zip" => BINARY, "tar" => BINARY, "gz" => BINARY, "fla" => BINARY, "swf" => BINARY, "atf" => BINARY, "psd" => BINARY, - "awd" => BINARY, "txt" => TEXT, "text" => TEXT, "xml" => TEXT, "java" => TEXT, "hx" => TEXT, "cpp" => TEXT, "c" => TEXT, "h" => TEXT, - "cs" => TEXT, "js" => TEXT, "mm" => TEXT, "hxml" => TEXT, "html" => TEXT, "json" => TEXT, "css" => TEXT, "gpe" => TEXT, "pbxproj" => TEXT, - "plist" => TEXT, "properties" => TEXT, "ini" => TEXT, "hxproj" => TEXT, "nmml" => TEXT, "lime" => TEXT, "svg" => TEXT, + "jpg" => IMAGE, + "jpeg" => IMAGE, + "png" => IMAGE, + "gif" => IMAGE, + "webp" => IMAGE, + "bmp" => IMAGE, + "tiff" => IMAGE, + "jfif" => IMAGE, + "otf" => FONT, + "ttf" => FONT, + "wav" => SOUND, + "wave" => SOUND, + "flac" => SOUND, + "mid" => SOUND, + "midi" => SOUND, + "ogg" => SOUND, + "spx" => SOUND, + "au" => SOUND, + "aiff" => SOUND, + "oga" => SOUND, + "mp3" => MUSIC, + "mp2" => MUSIC, + "exe" => BINARY, + "bin" => BINARY, + "so" => BINARY, + "pch" => BINARY, + "dll" => BINARY, + "zip" => BINARY, + "tar" => BINARY, + "gz" => BINARY, + "fla" => BINARY, + "swf" => BINARY, + "atf" => BINARY, + "psd" => BINARY, + "awd" => BINARY, + "txt" => TEXT, + "text" => TEXT, + "xml" => TEXT, + "java" => TEXT, + "hx" => TEXT, + "cpp" => TEXT, + "c" => TEXT, + "h" => TEXT, + "cs" => TEXT, + "js" => TEXT, + "mm" => TEXT, + "hxml" => TEXT, + "html" => TEXT, + "json" => TEXT, + "css" => TEXT, + "gpe" => TEXT, + "pbxproj" => TEXT, + "plist" => TEXT, + "properties" => TEXT, + "ini" => TEXT, + "hxproj" => TEXT, + "nmml" => TEXT, + "lime" => TEXT, + "svg" => TEXT, ]; } diff --git a/src/lime/tools/CPPHelper.hx b/src/lime/tools/CPPHelper.hx index e2877c9205..66d2dc71bc 100644 --- a/src/lime/tools/CPPHelper.hx +++ b/src/lime/tools/CPPHelper.hx @@ -208,7 +208,10 @@ class CPPHelper if (!FileSystem.exists(path)) { - Log.warn("Skipping rebuild. Path not found: " + path + "\nIf you are using a release from Haxelib, source code for native binaries may not be bundled. To rebuild, you may need to check out the full repository."); + Log.warn("Skipping rebuild. Path not found: " + + path + + + "\nIf you are using a release from Haxelib, source code for native binaries may not be bundled. To rebuild, you may need to check out the full repository."); return; } @@ -221,7 +224,10 @@ class CPPHelper if (!FileSystem.exists(Path.combine(path, buildFile))) { - Log.warn("Skipping rebuild. Path not found: " + path + "\nIf you are using a release from Haxelib, source code for native binaries may not be bundled. To rebuild, you may need to check out the full repository."); + Log.warn("Skipping rebuild. Path not found: " + + path + + + "\nIf you are using a release from Haxelib, source code for native binaries may not be bundled. To rebuild, you may need to check out the full repository."); return; } diff --git a/src/lime/tools/CSHelper.hx b/src/lime/tools/CSHelper.hx index 2aa3a391d1..e92149248c 100644 --- a/src/lime/tools/CSHelper.hx +++ b/src/lime/tools/CSHelper.hx @@ -11,8 +11,16 @@ using StringTools; class CSHelper { public static var ndllSourceFiles:Array = [ - "cs.ndll.NDLLFunction", "cs.ndll.CFFICSLoader", "cs.ndll.CSAbstract", "cs.ndll.CSHandleContainer", "cs.ndll.CSHandleScope", "cs.ndll.CSPersistent", - "cs.ndll.DelegateConverter", "cs.ndll.HandleUtils", "cs.ndll.NativeMethods", "cs.ndll.NDLLFunction", + "cs.ndll.NDLLFunction", + "cs.ndll.CFFICSLoader", + "cs.ndll.CSAbstract", + "cs.ndll.CSHandleContainer", + "cs.ndll.CSHandleScope", + "cs.ndll.CSPersistent", + "cs.ndll.DelegateConverter", + "cs.ndll.HandleUtils", + "cs.ndll.NativeMethods", + "cs.ndll.NDLLFunction", ]; private static function getAndroidABIName(arch:Architecture):String diff --git a/src/lime/tools/ConfigData.hx b/src/lime/tools/ConfigData.hx index 96b3928505..1ae3c54c2e 100644 --- a/src/lime/tools/ConfigData.hx +++ b/src/lime/tools/ConfigData.hx @@ -175,7 +175,7 @@ abstract ConfigData(Dynamic) to Dynamic from Dynamic return defaultValue; } - public function getKeyValueArray(id:String, defaultValues:Dynamic = null):Array<{ key:String, value:Dynamic }> + public function getKeyValueArray(id:String, defaultValues:Dynamic = null):Array<{key:String, value:Dynamic}> { var values = {}; if (defaultValues != null) @@ -192,10 +192,10 @@ abstract ConfigData(Dynamic) to Dynamic from Dynamic } } - var pairs:Array<{ key:String, value:Dynamic }> = []; + var pairs:Array<{key:String, value:Dynamic}> = []; for (key in Reflect.fields(values)) { - pairs.push({ key: key, value: Reflect.field(values, key) }); + pairs.push({key: key, value: Reflect.field(values, key)}); } return pairs; @@ -237,7 +237,10 @@ abstract ConfigData(Dynamic) to Dynamic from Dynamic continue; } - if (valueSource != valueDest && valueDest != null && typeSource != "TObject" && !#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(valueSource, Array)) + if (valueSource != valueDest + && valueDest != null + && typeSource != "TObject" + && !#if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (valueSource, Array)) { if (!Reflect.hasField(destination, ARRAY + field)) { @@ -264,11 +267,13 @@ abstract ConfigData(Dynamic) to Dynamic from Dynamic { mergeValues(valueSource, valueDest); } - else if (typeDest == "TClass" && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (valueSource, Array) && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end(valueDest, Array)) + else if (typeDest == "TClass" + && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (valueSource, Array) + && #if (haxe_ver >= 4.2) Std.isOfType #else Std.is #end (valueDest, Array)) { - for (item in (cast valueSource:Array)) + for (item in (cast valueSource : Array)) { - (cast valueDest:Array).push(item); + (cast valueDest : Array).push(item); } } else @@ -529,11 +534,13 @@ abstract ConfigData(Dynamic) to Dynamic from Dynamic // Getters & Setters - private inline function get_xmlChildren():Array { + private inline function get_xmlChildren():Array + { return Reflect.field(this, "config:xml_children"); } - private inline function set_xmlChildren(value:Array):Array { + private inline function set_xmlChildren(value:Array):Array + { Reflect.setField(this, "config:xml_children", value); return value; } diff --git a/src/lime/tools/FlashHelper.hx b/src/lime/tools/FlashHelper.hx index 07b68201f5..0b4f840432 100644 --- a/src/lime/tools/FlashHelper.hx +++ b/src/lime/tools/FlashHelper.hx @@ -623,7 +623,22 @@ class FlashHelper var label = (id > 0 ? Std.string(id + 1) : ""); var swfVersions = [ - 9, 10, /*10.1,*/ 10.2, 10.3, 11, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 12, 13, 14 + 9, + 10, /*10.1,*/ + 10.2, + 10.3, + 11, + 11.1, + 11.2, + 11.3, + 11.4, + 11.5, + 11.6, + 11.7, + 11.8, + 12, + 13, + 14 ]; var flashVersion = 9; diff --git a/src/lime/tools/HTML5Helper.hx b/src/lime/tools/HTML5Helper.hx index d7550381f1..f895a46295 100644 --- a/src/lime/tools/HTML5Helper.hx +++ b/src/lime/tools/HTML5Helper.hx @@ -107,11 +107,11 @@ class HTML5Helper { suffix += "32"; } - else if( System.hostArchitecture == ARMV7) + else if (System.hostArchitecture == ARMV7) { suffix += "Arm"; } - else if( System.hostArchitecture == ARM64) + else if (System.hostArchitecture == ARM64) { suffix += "Arm64"; } @@ -174,7 +174,8 @@ class HTML5Helper { var executable = "npx"; var terser = "terser"; - if (!project.targetFlags.exists("npx")) { + if (!project.targetFlags.exists("npx")) + { var suffix = switch (System.hostPlatform) { case WINDOWS: "-windows.exe"; @@ -207,14 +208,7 @@ class HTML5Helper } } - var args = [ - terser, - sourceFile, - "-c", - "-m", - "-o", - tempFile - ]; + var args = [terser, sourceFile, "-c", "-m", "-o", tempFile]; if (FileSystem.exists(sourceFile + ".map")) { @@ -245,9 +239,7 @@ class HTML5Helper if (project.targetFlags.exists("npx")) { executable = "npx"; - args = [ - "google-closure-compiler" - ]; + args = ["google-closure-compiler"]; } else { diff --git a/src/lime/tools/HXProject.hx b/src/lime/tools/HXProject.hx index 164a3e0fee..c87cf3dc06 100644 --- a/src/lime/tools/HXProject.hx +++ b/src/lime/tools/HXProject.hx @@ -107,7 +107,7 @@ class HXProject extends Script var classRef = Type.resolveClass(inputData.name); if (classRef == null) { - Log.error('Unable to find class ${ inputData.name } in ${ inputData.projectFile }'); + Log.error('Unable to find class ${inputData.name} in ${inputData.projectFile}'); return; } var instance = Type.createInstance(classRef, []); @@ -189,7 +189,20 @@ class HXProject extends Script else { environment = Sys.environment(); - for (conflict in ["air", "android", "cpp", "flash", "hl", "html5", "ios", "linux", "mac", "neko", "webassembly", "windows"]) + for (conflict in [ + "air", + "android", + "cpp", + "flash", + "hl", + "html5", + "ios", + "linux", + "mac", + "neko", + "webassembly", + "windows" + ]) { environment.remove(conflict); } @@ -212,7 +225,7 @@ class HXProject extends Script splashScreens = new Array(); targetHandlers = new Map(); - config.set("android", { manifest:{}, application:{}, activity:{} }); + config.set("android", {manifest: {}, application: {}, activity: {}}); config.get("android.manifest").xmlChildren = []; config.get("android.application").xmlChildren = []; config.get("android.activity").xmlChildren = []; @@ -403,11 +416,12 @@ class HXProject extends Script var args = [ name, #if lime - "-lib", "lime", - "-lib", "hxp", + "-lib", "lime", "-lib", "hxp", #end - "-cp", tempDirectory, - "-cp", Path.combine(Haxelib.getPath(new Haxelib("hxp")), "src") + "-cp", + tempDirectory, + "-cp", + Path.combine(Haxelib.getPath(new Haxelib("hxp")), "src") ]; var input = File.read(classFile, false); var tag = "@:compiler("; @@ -682,6 +696,7 @@ class HXProject extends Script @:privateAccess projectXML.parseXML(new Access(Xml.parse(xml).firstElement()), ""); merge(projectXML); } + // #end private function initializeDefines():Void @@ -793,8 +808,7 @@ class HXProject extends Script defines.set("native", "1"); defines.set("cpp", "1"); } - else if (targetFlags.exists("cpp") - || ((platformType != PlatformType.WEB) && !targetFlags.exists("html5"))) + else if (targetFlags.exists("cpp") || ((platformType != PlatformType.WEB) && !targetFlags.exists("html5"))) { defines.set("targetType", "cpp"); defines.set("native", "1"); diff --git a/src/lime/tools/HashlinkHelper.hx b/src/lime/tools/HashlinkHelper.hx index efd1d29e5d..879f180bcc 100644 --- a/src/lime/tools/HashlinkHelper.hx +++ b/src/lime/tools/HashlinkHelper.hx @@ -35,11 +35,8 @@ class HashlinkHelper var peOffset = readUInt32LE(bytes, 0x3C); var subsystemOffset = peOffset + 24 + 68; - if (peOffset < 0 || subsystemOffset + 1 >= bytes.length - || bytes.get(peOffset) != 0x50 - || bytes.get(peOffset + 1) != 0x45 - || bytes.get(peOffset + 2) != 0 - || bytes.get(peOffset + 3) != 0) + if (peOffset < 0 || subsystemOffset + 1 >= bytes.length || bytes.get(peOffset) != 0x50 || bytes.get(peOffset + 1) != 0x45 + || bytes.get(peOffset + 2) != 0 || bytes.get(peOffset + 3) != 0) { Log.warn('Could not hide HashLink console: "$executablePath" has an unsupported PE header'); return; @@ -68,7 +65,8 @@ class HashlinkHelper Sys.exit(1); ""; }; - if(is64) { + if (is64) + { bindir += "64"; } @@ -81,9 +79,8 @@ class HashlinkHelper if (project.targetFlags.exists("hlc")) { var limeDirectory = Haxelib.getPath(new Haxelib("lime"), true); - var includeDirectory = sys.FileSystem.exists(Path.combine(limeDirectory, "project")) - ? Path.combine(limeDirectory, "project/lib/hashlink/src") - : Path.combine(limeDirectory, "templates/bin/hl/include"); + var includeDirectory = sys.FileSystem.exists(Path.combine(limeDirectory, + "project")) ? Path.combine(limeDirectory, "project/lib/hashlink/src") : Path.combine(limeDirectory, "templates/bin/hl/include"); System.copyFile(Path.combine(includeDirectory, "hlc.h"), Path.combine(targetDirectory, "obj/hlc.h"), null, false); System.copyFile(Path.combine(includeDirectory, "hl.h"), Path.combine(targetDirectory, "obj/hl.h"), null, false); @@ -167,7 +164,8 @@ class HashlinkHelper var appMainCPath = Path.combine(targetDirectory, "obj/ApplicationMain.c"); var appMainCText = System.readText(appMainCPath); var index = appMainCText.indexOf("#ifndef HL_MAKE"); - appMainCText = appMainCText.substr(0, index) + " + appMainCText = appMainCText.substr(0, index) + + " // --------- START LIME HL/C INJECTED CODE --------- // // undefine things to avoid Haxe field name conflicts #undef BIG_ENDIAN @@ -197,7 +195,8 @@ class HashlinkHelper #undef __valid #undef WAIT_FAILED // ---------- END LIME HL/C INJECTED CODE ---------- // -" + appMainCText.substr(index); +" + + appMainCText.substr(index); System.writeText(appMainCText, appMainCPath); } else diff --git a/src/lime/tools/IOSHelper.hx b/src/lime/tools/IOSHelper.hx index c4202c2faf..431312f13a 100644 --- a/src/lime/tools/IOSHelper.hx +++ b/src/lime/tools/IOSHelper.hx @@ -364,7 +364,8 @@ class IOSHelper var requireIPhone = project.config.getString("ios.device", "universal") == "iphone"; var xcodeVersion = Std.parseFloat(getXcodeVersion()); - if (!Math.isNaN(xcodeVersion) && xcodeVersion >= 16) { + if (!Math.isNaN(xcodeVersion) && xcodeVersion >= 16) + { // ios-deploy doesn't work with newer iOS SDKs where it can't // find DeveloperDiskImage.dmg. however, Xcode 16 adds new // commands for installing and launching apps on connected @@ -389,10 +390,7 @@ class IOSHelper // 1. the platform must always be iOS (which includes iPadOS). // 2. the device must be in developer mode. // 3. if required by the project config, limit to iPhone or iPad only - var baseFilters = [ - filterPlatformIOS, - filterDeveloperModeEnabled, - ]; + var baseFilters = [filterPlatformIOS, filterDeveloperModeEnabled,]; if (requireIPad) { baseFilters.push(filterDeviceTypeIPad); @@ -411,10 +409,7 @@ class IOSHelper { for (transportTypeFilter in transportTypeFilters) { - deviceUUID = findDeviceUUIDWithFilters(baseFilters.concat([ - stateFilter, - transportTypeFilter - ])); + deviceUUID = findDeviceUUIDWithFilters(baseFilters.concat([stateFilter, transportTypeFilter])); if (deviceUUID != null && deviceUUID.length > 0) { break; @@ -426,7 +421,8 @@ class IOSHelper } } - if (deviceUUID == null || deviceUUID.length == 0) { + if (deviceUUID == null || deviceUUID.length == 0) + { // devices running iOS 16 and older don't support // xcrun devicectl, so if no device was found, try falling // back to ios-deploy @@ -440,9 +436,28 @@ class IOSHelper Log.info("Detected iOS device UUID: " + deviceUUID); } - System.runCommand("", "xcrun", ["devicectl", "device", "install", "app", "--device", deviceUUID, FileSystem.fullPath(applicationPath)]); - System.runCommand("", "xcrun", ["devicectl", "device", "process", "launch", "--console", "--device", deviceUUID, project.meta.packageName]); - } else { + System.runCommand("", "xcrun", [ + "devicectl", + "device", + "install", + "app", + "--device", + deviceUUID, + FileSystem.fullPath(applicationPath) + ]); + System.runCommand("", "xcrun", [ + "devicectl", + "device", + "process", + "launch", + "--console", + "--device", + deviceUUID, + project.meta.packageName + ]); + } + else + { // continue using ios-deploy if Xcode version is 15 or older fallbackLaunch(project, applicationPath); } @@ -451,12 +466,16 @@ class IOSHelper private static function findDeviceUUIDWithFilters(filters:Array):String { - var listDevicesOutput = System.runProcess("", "xcrun", - [ - "devicectl", "list", "devices", - "--hide-default-columns", "--columns", "Identifier", - "--filter", filters.join(" AND ") - ]); + var listDevicesOutput = System.runProcess("", "xcrun", [ + "devicectl", + "list", + "devices", + "--hide-default-columns", + "--columns", + "Identifier", + "--filter", + filters.join(" AND ") + ]); var ready = false; for (line in listDevicesOutput.split("\n")) { diff --git a/src/lime/tools/IconHelper.hx b/src/lime/tools/IconHelper.hx index 95b1a7d6c0..694c18af4f 100644 --- a/src/lime/tools/IconHelper.hx +++ b/src/lime/tools/IconHelper.hx @@ -311,7 +311,8 @@ class IconHelper } if (Math.abs(iconDifference) < Math.abs(matchDifference) - || iconDifference == matchDifference && icon.priority >= match.priority) + || iconDifference == matchDifference + && icon.priority >= match.priority) { match = icon; matchDifference = iconDifference; diff --git a/src/lime/tools/MetaData.hx b/src/lime/tools/MetaData.hx index f06a76b20d..8680a18dc8 100644 --- a/src/lime/tools/MetaData.hx +++ b/src/lime/tools/MetaData.hx @@ -14,15 +14,16 @@ abstract MetaData({ }) from Dynamic { @:noCompletion - public static var expectedFields:MetaData = { - buildNumber: "", - company: "", - companyId: "", - companyUrl: "", - description: "", - packageName: "", - title: "", - version: "", - copyrightYears: "" - }; + public static var expectedFields:MetaData = + { + buildNumber: "", + company: "", + companyId: "", + companyUrl: "", + description: "", + packageName: "", + title: "", + version: "", + copyrightYears: "" + }; } diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index 49e5b17a95..b752ac16f9 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -57,8 +57,7 @@ class PlatformTarget // known issue: this may not log in `-eval` mode on Linux inline function logCommand(command:String):Void { - if (!Reflect.hasField(metaFields, command) - || !Reflect.hasField(Reflect.field(metaFields, command), "ignore")) + if (!Reflect.hasField(metaFields, command) || !Reflect.hasField(Reflect.field(metaFields, command), "ignore")) { Log.info("", "\n" + Log.accentColor + "Running command: " + command.toUpperCase() + Log.resetColor); } @@ -137,8 +136,7 @@ class PlatformTarget run(); } - if ((command == "test" || command == "trace" || command == "run" || command == "rerun") - && (traceEnabled || command == "trace")) + if ((command == "test" || command == "trace" || command == "run" || command == "rerun") && (traceEnabled || command == "trace")) { logCommand("trace"); this.trace(); @@ -264,7 +262,10 @@ class PlatformTarget } } - private function getDisplayHXML():HXML { return null; } + private function getDisplayHXML():HXML + { + return null; + } // Functions to track and delete stale files diff --git a/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index e535b37f5e..83b5ec4ef8 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1434,7 +1434,6 @@ class ProjectXMLParser extends HXProject sources.push(path); case "extension": - // deprecated case "haxedef": @@ -1536,7 +1535,6 @@ class ProjectXMLParser extends HXProject parseModuleElement(element, extensionPath); case "ssl": - // if (wantSslCertificate()) // parseSsl (element); diff --git a/src/lime/tools/WindowData.hx b/src/lime/tools/WindowData.hx index 1f74f090ad..712cb44b7e 100644 --- a/src/lime/tools/WindowData.hx +++ b/src/lime/tools/WindowData.hx @@ -37,38 +37,39 @@ abstract WindowData({ }) from Dynamic { @:noCompletion - public static var expectedFields:WindowData = { - width: 0, - height: 0, - x: 0.0, - y: 0.0, - background: 0, - parameters: "", - fps: 0, - hardware: false, - display: 0, - resizable: false, - borderless: false, - vsync: false, - vsyncMode: null, - fullscreen: false, - 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 - colorDepth: 0, - minimized: false, - maximized: false, - hidden: false - }; + public static var expectedFields:WindowData = + { + width: 0, + height: 0, + x: 0.0, + y: 0.0, + background: 0, + parameters: "", + fps: 0, + hardware: false, + display: 0, + resizable: false, + borderless: false, + vsync: false, + vsyncMode: null, + fullscreen: false, + 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 + colorDepth: 0, + minimized: false, + maximized: false, + hidden: false + }; } diff --git a/src/lime/tools/XCodeHelper.hx b/src/lime/tools/XCodeHelper.hx index 7abd0c08dd..1121a79090 100644 --- a/src/lime/tools/XCodeHelper.hx +++ b/src/lime/tools/XCodeHelper.hx @@ -7,10 +7,7 @@ class XCodeHelper { // different computers may have different sets of simulators installed // so there isn't necessarily a reasonable default for ipads - private static var DEFAULT_IPAD_SIMULATOR_NAMES = [ - "ipad", - "ipad-air" - ]; + private static var DEFAULT_IPAD_SIMULATOR_NAMES = ["ipad", "ipad-air"]; private static var DEFAULT_IPAD_AIR_SIMULATOR_FALLBACK_REGEX = ~/ipad-air-.+/g; private static var DEFAULT_IPAD_SIMULATOR_FALLBACK_REGEX = ~/ipad-.+/g; // this should be a standard iPhone of a particular generation diff --git a/src/lime/ui/FileDialog.hx b/src/lime/ui/FileDialog.hx index 7004406412..31a1a349b2 100644 --- a/src/lime/ui/FileDialog.hx +++ b/src/lime/ui/FileDialog.hx @@ -99,10 +99,7 @@ class FileDialog extension = extension.substr(1); } - if (extension.length == 0 - || extension.indexOf("*") != -1 - || extension.indexOf("?") != -1 - || extension.indexOf("/") != -1 + if (extension.length == 0 || extension.indexOf("*") != -1 || extension.indexOf("?") != -1 || extension.indexOf("/") != -1 || extension.indexOf("\\") != -1) { continue; @@ -132,9 +129,7 @@ class FileDialog if (type == null) type = FileDialogType.OPEN; #if sys - if (defaultPath != null && defaultPath.length > 0 - && FileSystem.exists(defaultPath) - && FileSystem.isDirectory(defaultPath)) + if (defaultPath != null && defaultPath.length > 0 && FileSystem.exists(defaultPath) && FileSystem.isDirectory(defaultPath)) { // if the default path is a directory, and the default path doesn't // end with a separator, tiny file dialogs may open its parent diff --git a/src/lime/ui/Gamepad.hx b/src/lime/ui/Gamepad.hx index 19017ead14..3c7ab47f74 100644 --- a/src/lime/ui/Gamepad.hx +++ b/src/lime/ui/Gamepad.hx @@ -65,18 +65,17 @@ class Gamepad #if (lime_cffi && !macro) NativeCFFI.lime_gamepad_rumble(this.id, lowFrequencyRumble, highFrequencyRumble, duration); #elseif (js && html5) - var actuator:Dynamic = (untyped __jsGamepad.vibrationActuator) ? untyped __jsGamepad.vibrationActuator - : (untyped __jsGamepad.hapticActuators) ? untyped __jsGamepad.hapticActuators[0] - : null; + var actuator:Dynamic = (untyped __jsGamepad.vibrationActuator) ? untyped __jsGamepad.vibrationActuator : (untyped __jsGamepad.hapticActuators) ? untyped __jsGamepad.hapticActuators[0] : null; if (actuator == null) return; if (untyped actuator.playEffect) { - untyped actuator.playEffect("dual-rumble", { - duration: duration, - strongMagnitude: lowFrequencyRumble, - weakMagnitude: highFrequencyRumble - }); + untyped actuator.playEffect("dual-rumble", + { + duration: duration, + strongMagnitude: lowFrequencyRumble, + weakMagnitude: highFrequencyRumble + }); } else if (untyped actuator.pulse) { diff --git a/src/lime/ui/KeyCode.hx b/src/lime/ui/KeyCode.hx index 36bdedf7de..7772aaa710 100644 --- a/src/lime/ui/KeyCode.hx +++ b/src/lime/ui/KeyCode.hx @@ -10,8 +10,7 @@ import lime._internal.backend.native.NativeCFFI; @see `lime.ui.Window.onKeyUp` @see `lime.ui.ScanCode` **/ -@:access(lime._internal.backend.native.NativeCFFI) -#if (haxe_ver >= 4.0) enum #else @:enum #end abstract KeyCode(Int) from Int to Int from UInt to UInt +@:access(lime._internal.backend.native.NativeCFFI) #if (haxe_ver >= 4.0) enum #else @:enum #end abstract KeyCode(Int) from Int to Int from UInt to UInt { var UNKNOWN = 0x00; var BACKSPACE = 0x08; diff --git a/src/lime/ui/ScanCode.hx b/src/lime/ui/ScanCode.hx index 1d115499ed..c6a9eab247 100644 --- a/src/lime/ui/ScanCode.hx +++ b/src/lime/ui/ScanCode.hx @@ -11,8 +11,7 @@ import lime._internal.backend.native.NativeCFFI; @see `lime.ui.KeyCode` **/ @:access(lime._internal.backend.native.NativeCFFI) -@:access(lime.ui.KeyCode) -#if (haxe_ver >= 4.0) enum #else @:enum #end abstract ScanCode(Int) from Int to Int from UInt to UInt +@:access(lime.ui.KeyCode) #if (haxe_ver >= 4.0) enum #else @:enum #end abstract ScanCode(Int) from Int to Int from UInt to UInt { var UNKNOWN = 0; var BACKSPACE = 42; diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index 37e5f870b2..eb364c4bcd 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -56,6 +56,7 @@ class Window * vertical-sync setting. **/ public var vsyncMode(get, set):VSyncMode; + public var fullscreen(get, set):Bool; public var height(get, set):Int; public var hidden(get, null):Bool; diff --git a/src/lime/ui/WindowAttributes.hx b/src/lime/ui/WindowAttributes.hx index fbf59dffe1..96d5fbe6e7 100644 --- a/src/lime/ui/WindowAttributes.hx +++ b/src/lime/ui/WindowAttributes.hx @@ -32,6 +32,7 @@ typedef WindowAttributes = shared application frame profile. **/ @:optional public var frameProfile:FrameProfile; + @:optional public var fullscreen:Bool; @:optional public var height:Int; @:optional public var hidden:Bool; diff --git a/src/lime/utils/ArrayBufferView.hx b/src/lime/utils/ArrayBufferView.hx index 8b25a82c79..aa429a1277 100644 --- a/src/lime/utils/ArrayBufferView.hx +++ b/src/lime/utils/ArrayBufferView.hx @@ -46,6 +46,7 @@ class ArrayBufferView } // new // Constructor helpers + @:allow(lime.utils) #if !no_typedarray_inline inline @@ -138,7 +139,8 @@ class ArrayBufferView { if (view != null && array == null) { - if (offset + view.length > this.length) { + if (offset + view.length > this.length) + { throw TAError.RangeError; } if (bytesPerElement == view.bytesPerElement) @@ -296,12 +298,13 @@ class ArrayBufferView // Non-spec #if !no_typedarray_inline #end - function copyFromArray(array:Array<#if hl Dynamic #else Float #end>, offset:Int = 0) + function copyFromArray(array:Array< #if hl Dynamic #else Float #end>, offset:Int = 0) { // Ideally, native semantics could be used, like cpp.NativeArray.blit var i = 0, len = array.length; - if (offset + len > this.length) { + if (offset + len > this.length) + { throw TAError.RangeError; } @@ -471,7 +474,6 @@ class ArrayBufferView throw "transferElement on a base type ArrayBuffer"; } } - } // ArrayBufferView #end // !js diff --git a/src/lime/utils/AssetLibrary.hx b/src/lime/utils/AssetLibrary.hx index 146d9a7191..ea3c287098 100644 --- a/src/lime/utils/AssetLibrary.hx +++ b/src/lime/utils/AssetLibrary.hx @@ -381,8 +381,11 @@ class AssetLibrary return switch (cast(type, AssetType)) { case null: - cachedBytes.exists(id) || cachedText.exists(id) || cachedImages.exists(id) - || cachedAudioBuffers.exists(id) || cachedFonts.exists(id); + cachedBytes.exists(id) + || cachedText.exists(id) + || cachedImages.exists(id) + || cachedAudioBuffers.exists(id) + || cachedFonts.exists(id); case IMAGE: cachedImages.exists(id); @@ -393,8 +396,7 @@ class AssetLibrary case FONT: cachedFonts.exists(id); - default: - cachedBytes.exists(id) || cachedText.exists(id); + default: cachedBytes.exists(id) || cachedText.exists(id); } #end } diff --git a/src/lime/utils/Assets.hx b/src/lime/utils/Assets.hx index 2f43d1327f..8ddeceb16b 100644 --- a/src/lime/utils/Assets.hx +++ b/src/lime/utils/Assets.hx @@ -15,8 +15,8 @@ import lime.utils.Log; #if !macro import haxe.Json; #end -@:access(lime.media.AudioBuffer) +@:access(lime.media.AudioBuffer) /** *

The Assets class provides a cross-platform interface to access * embedded images, fonts, sounds and other resource files.

diff --git a/src/lime/utils/ObjectPool.hx b/src/lime/utils/ObjectPool.hx index a023128f02..0b10868c89 100644 --- a/src/lime/utils/ObjectPool.hx +++ b/src/lime/utils/ObjectPool.hx @@ -2,10 +2,9 @@ package lime.utils; import haxe.ds.ObjectMap; - /** - A generic object pool for reusing objects. - **/ + A generic object pool for reusing objects. +**/ #if !lime_debug @:fileXml('tags="haxe,release"') @:noDebug @@ -13,18 +12,18 @@ import haxe.ds.ObjectMap; #if !js @:generic #end class ObjectPool { /** - The number of active objects in the pool. - **/ + The number of active objects in the pool. + **/ public var activeObjects(default, null):Int; /** - The number of inactive objects in the pool. - **/ + The number of inactive objects in the pool. + **/ public var inactiveObjects(default, null):Int; /** - The total size of the object pool (both active and inactive objects). - **/ + The total size of the object pool (both active and inactive objects). + **/ public var size(get, set):Null; @:noCompletion private var __inactiveObject0:T; @@ -34,12 +33,12 @@ import haxe.ds.ObjectMap; @:noCompletion private var __size:Null; /** - Creates a new ObjectPool instance. - - @param create A function that creates a new instance of type T. - @param clean A function that cleans up an instance of type T before it is reused. - @param size The maximum size of the object pool. - **/ + Creates a new ObjectPool instance. + + @param create A function that creates a new instance of type T. + @param clean A function that cleans up an instance of type T before it is reused. + @param size The maximum size of the object pool. + **/ public function new(create:Void->T = null, clean:T->Void = null, size:Null = null) { __pool = cast new ObjectMap(); @@ -64,11 +63,12 @@ import haxe.ds.ObjectMap; this.size = size; } } + /** - Adds an object to the object pool. - - @param object The object to add to the pool. - **/ + Adds an object to the object pool. + + @param object The object to add to the pool. + **/ public function add(object:T):Void { if (object != null && !__pool.exists(object)) @@ -82,15 +82,15 @@ import haxe.ds.ObjectMap; /** Dynamic function. - Cleans up an object before returning it to the pool. - - @param object The object to clean up. - **/ + Cleans up an object before returning it to the pool. + + @param object The object to clean up. + **/ public dynamic function clean(object:T):Void {} /** - Clears the object pool, removing all objects. - **/ + Clears the object pool, removing all objects. + **/ public function clear():Void { __pool = cast new ObjectMap(); @@ -106,18 +106,18 @@ import haxe.ds.ObjectMap; /** Dynamic function. - Creates a new Object. - **/ + Creates a new Object. + **/ public dynamic function create():T { return null; } /** - Creates a new object and adds it to the pool, or returns an existing inactive object from the pool. - - @return The object retrieved from the pool, or null if the pool is full and no new objects can be created. - **/ + Creates a new object and adds it to the pool, or returns an existing inactive object from the pool. + + @return The object retrieved from the pool, or null if the pool is full and no new objects can be created. + **/ public function get():T { var object = null; @@ -141,10 +141,10 @@ import haxe.ds.ObjectMap; } /** - Releases an active object back into the pool. - - @param object The object to release. - **/ + Releases an active object back into the pool. + + @param object The object to release. + **/ public function release(object:T):Void { #if debug @@ -172,10 +172,10 @@ import haxe.ds.ObjectMap; } /** - Removes an object from the pool. - - @param object The object to remove from the pool. - **/ + Removes an object from the pool. + + @param object The object to remove from the pool. + **/ public function remove(object:T):Void { if (object != null && __pool.exists(object)) diff --git a/src/lime/utils/PackedAssetLibrary.hx b/src/lime/utils/PackedAssetLibrary.hx index 5a7a98f10a..42021c954d 100644 --- a/src/lime/utils/PackedAssetLibrary.hx +++ b/src/lime/utils/PackedAssetLibrary.hx @@ -174,7 +174,7 @@ import flash.media.Sound; // TODO: Do not preload bytes on native, if we can read from it instead (all non-Android targets?) assetsLoaded = 0; - assetsTotal = 2; //for our initial __assetLoaded(null) call and __assetLoaded(this.id) + assetsTotal = 2; // for our initial __assetLoaded(null) call and __assetLoaded(this.id) for (id in preload.keys()) { @@ -252,7 +252,7 @@ import flash.media.Sound; } else { - var basePath = rootPath == null || rootPath == "" ? "" : Path.addTrailingSlash(rootPath); + var basePath = rootPath == null || rootPath == "" ? "" : Path.addTrailingSlash(rootPath); var libPath = getPath(id); if (libPath == null) libPath = id; @@ -261,7 +261,10 @@ import flash.media.Sound; var packedData_onProgress = load_onProgress.bind(this.id); - Bytes.loadFromFile(path).onProgress(packedData_onProgress).onError(promise.error).onComplete(packedData_onComplete); + Bytes.loadFromFile(path) + .onProgress(packedData_onProgress) + .onError(promise.error) + .onComplete(packedData_onComplete); } } @@ -431,9 +434,9 @@ import flash.media.Sound; var length = Reflect.field(asset, "length"); lengths.set(id, length); - //for individual packed assets, the size represents the work done unpacking them - //since this is likely to be much faster than downloading, set it to something - //small like the packed length / 10. + // for individual packed assets, the size represents the work done unpacking them + // since this is likely to be much faster than downloading, set it to something + // small like the packed length / 10. sizes.set(id, Math.floor(length / 10)); packedBytesTotal += length; @@ -444,7 +447,7 @@ import flash.media.Sound; bytesTotal += sizes.get(id); } } - + sizes.set(this.id, packedBytesTotal); bytesTotal += packedBytesTotal; } diff --git a/src/lime/utils/Preloader.hx b/src/lime/utils/Preloader.hx index d9f309aeff..f74c35c25d 100644 --- a/src/lime/utils/Preloader.hx +++ b/src/lime/utils/Preloader.hx @@ -26,8 +26,7 @@ import flash.Lib; @:access(lime.utils.AssetLibrary) #if !lime_debug -@:fileXml('tags="haxe,release"') -@:noDebug +@:fileXml('tags="haxe,release"') @:noDebug #end class Preloader #if flash extends Sprite #end { @@ -36,12 +35,12 @@ class Preloader #if flash extends Sprite #end public var onProgress = new EventInt->Void>(); @:noCompletion private var bytesLoaded:Int; - @:noCompletion private var bytesLoadedCache = new ObjectMap<#if !disable_preloader_assets AssetLibrary #else Dynamic #end, Int>(); + @:noCompletion private var bytesLoadedCache = new ObjectMap< #if !disable_preloader_assets AssetLibrary #else Dynamic #end, Int>(); @:noCompletion private var bytesLoadedCache2 = new Map(); @:noCompletion private var bytesTotal:Int; @:noCompletion private var bytesTotalCache = new Map(); @:noCompletion private var initLibraryNames:Bool; - @:noCompletion private var libraries:Array<#if !disable_preloader_assets AssetLibrary #else Dynamic #end>; + @:noCompletion private var libraries:Array< #if !disable_preloader_assets AssetLibrary #else Dynamic #end>; @:noCompletion private var libraryNames:Array; @:noCompletion private var loadedLibraries:Int; @:noCompletion private var loadedStage:Bool; @@ -60,7 +59,7 @@ class Preloader #if flash extends Sprite #end bytesLoaded = 0; bytesTotal = 0; - libraries = new Array<#if !disable_preloader_assets AssetLibrary #else Dynamic #end>(); + libraries = new Array< #if !disable_preloader_assets AssetLibrary #else Dynamic #end>(); libraryNames = new Array(); onProgress.add(update); @@ -296,8 +295,7 @@ class Preloader #if flash extends Sprite #end } #end - if (!simulateProgress #if flash && loadedStage #end - && loadedLibraries == (libraries.length + libraryNames.length)) + if (!simulateProgress #if flash && loadedStage #end && loadedLibraries == (libraries.length + libraryNames.length)) { if (!preloadComplete) { diff --git a/tests/unit/src/TestMain.hx b/tests/unit/src/TestMain.hx index e5f15d054e..dae8fda9c3 100644 --- a/tests/unit/src/TestMain.hx +++ b/tests/unit/src/TestMain.hx @@ -2,8 +2,10 @@ import utest.Runner; import utest.ui.Report; import lime.app.Application; -class TestMain extends Application { - public function new() { +class TestMain extends Application +{ + public function new() + { super(); var runner = new Runner(); diff --git a/tests/unit/src/utils/ArrayBufferTest.hx b/tests/unit/src/utils/ArrayBufferTest.hx index 32dda5e2cf..8981b1b080 100644 --- a/tests/unit/src/utils/ArrayBufferTest.hx +++ b/tests/unit/src/utils/ArrayBufferTest.hx @@ -6,17 +6,21 @@ import lime.utils.ArrayBuffer; import utest.Assert; import utest.Test; -class ArrayBufferTest extends Test { - public function new() { +class ArrayBufferTest extends Test +{ + public function new() + { super(); } - public function testByteLength():Void { + public function testByteLength():Void + { var buffer = new ArrayBuffer(4); Assert.equals(4, buffer.byteLength); } - public function testSubarray():Void { + public function testSubarray():Void + { var buffer = new ArrayBuffer(4); var array = new UInt8Array(buffer); array[0] = 0xca; @@ -66,4 +70,4 @@ class ArrayBufferTest extends Test { Assert.equals(0xba, beyondLengthArray[2]); Assert.equals(0xbe, beyondLengthArray[3]); } -} \ No newline at end of file +} diff --git a/tests/unit/src/utils/DataViewTest.hx b/tests/unit/src/utils/DataViewTest.hx index 3fb397dfa2..ad2fcfa8bb 100644 --- a/tests/unit/src/utils/DataViewTest.hx +++ b/tests/unit/src/utils/DataViewTest.hx @@ -6,62 +6,61 @@ import lime.utils.ArrayBuffer; import utest.Assert; import utest.Test; -class DataViewTest extends Test { - public function new() { +class DataViewTest extends Test +{ + public function new() + { super(); } - public function testInt8():Void { - var values:Array = [0, 1, 2, 127, 128, 255, -1, -2, -128, -129]; - var result:Array = [0, 1, 2, 127, -128, -1, -1, -2, -128, 127]; + public function testInt8():Void + { + var values:Array = [0, 1, 2, 127, 128, 255, -1, -2, -128, -129]; + var result:Array = [0, 1, 2, 127, -128, -1, -1, -2, -128, 127]; Assert.equals(values.length, result.length); var count = values.length; var buffer = new ArrayBuffer(count); var dataView = new DataView(buffer); - for (i in 0...count) { + for (i in 0...count) + { var value = values[i]; dataView.setInt8(i, value); } - for (i in 0...count) { + for (i in 0...count) + { var value = dataView.getInt8(i); var expected = result[i]; Assert.equals(expected, value, 'Int8: expected $expected but got $value at index $i'); } } - public function testUint8():Void { - var values:Array = [0, 1, 2, 255, 256, -1, -2, -255]; - var result:Array = [0, 1, 2, 255, 0, 255, 254, 1]; + public function testUint8():Void + { + var values:Array = [0, 1, 2, 255, 256, -1, -2, -255]; + var result:Array = [0, 1, 2, 255, 0, 255, 254, 1]; Assert.equals(values.length, result.length); var count = values.length; var buffer = new ArrayBuffer(count); var dataView = new DataView(buffer); - for (i in 0...count) { + for (i in 0...count) + { var value = values[i]; dataView.setUint8(i, value); } - for (i in 0...count) { + for (i in 0...count) + { var value = dataView.getUint8(i); var expected = result[i]; Assert.equals(expected, value, 'Uint8: expected $expected but got $value at index $i'); } } - public function testInt16():Void { - var values:Array = [0, 1, 2, 32767, 32768, 65535, -1, -2, -32768, -32769]; - var result:Array = [0, 1, 2, 32767, -32768, -1, -1, -2, -32768, 32767]; + public function testInt16():Void + { + var values:Array = [0, 1, 2, 32767, 32768, 65535, -1, -2, -32768, -32769]; + var result:Array = [0, 1, 2, 32767, -32768, -1, -1, -2, -32768, 32767]; var resultBytesLE:Array> = [ - [0x00, 0x00], - [0x01, 0x00], - [0x02, 0x00], - [0xff, 0x7f], - [0x00, 0x80], - [0xff, 0xff], - [0xff, 0xff], - [0xfe, 0xff], - [0x00, 0x80], - [0xff, 0x7f] - ]; + [0x00, 0x00], [0x01, 0x00], [0x02, 0x00], [0xff, 0x7f], [0x00, 0x80], [0xff, 0xff], [0xff, 0xff], [0xfe, 0xff], [0x00, 0x80], [0xff, 0x7f]]; Assert.equals(values.length, result.length); Assert.equals(values.length, resultBytesLE.length); var count = values.length; @@ -69,52 +68,55 @@ class DataViewTest extends Test { var dataView = new DataView(buffer); // little endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = values[i]; dataView.setInt16(byteIndex, value); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = dataView.getInt16(byteIndex); var expected = result[i]; Assert.equals(expected, value, 'Int16 little endian: expected $expected but got $value at index $i'); - var valueBytes = [ - dataView.getUint8(byteIndex), - dataView.getUint8(byteIndex + 1) - ]; + var valueBytes = [dataView.getUint8(byteIndex), dataView.getUint8(byteIndex + 1)]; var expectedBytesLE = resultBytesLE[i]; Assert.equals(2, expectedBytesLE.length); - Assert.equals(expectedBytesLE[0], valueBytes[0], 'Int16 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesLE[1], valueBytes[1], 'Int16 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesLE[0], valueBytes[0], + 'Int16 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesLE[1], valueBytes[1], + 'Int16 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); } // big endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = values[i]; dataView.setInt16(byteIndex, value, false); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = dataView.getInt16(byteIndex, false); var expected = result[i]; Assert.equals(expected, value, 'Int16 big endian: expected $expected but got $value at index $i'); - var valueBytes = [ - dataView.getUint8(byteIndex), - dataView.getUint8(byteIndex + 1) - ]; + var valueBytes = [dataView.getUint8(byteIndex), dataView.getUint8(byteIndex + 1)]; var expectedBytesBE = resultBytesLE[i].copy(); expectedBytesBE.reverse(); // big endian is little endian reversed Assert.equals(2, expectedBytesBE.length); - Assert.equals(expectedBytesBE[0], valueBytes[0], 'Int16 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesBE[1], valueBytes[1], 'Int16 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesBE[0], valueBytes[0], + 'Int16 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesBE[1], valueBytes[1], + 'Int16 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); } } - public function testUint16():Void { - var values:Array = [0, 1, 2, 65535, 65536, -1, -2, -65535]; - var result:Array = [0, 1, 2, 65535, 0, 65535, 65534, 1]; + public function testUint16():Void + { + var values:Array = [0, 1, 2, 65535, 65536, -1, -2, -65535]; + var result:Array = [0, 1, 2, 65535, 0, 65535, 65534, 1]; var resultBytesLE:Array> = [ [0x00, 0x00], [0x01, 0x00], @@ -132,50 +134,53 @@ class DataViewTest extends Test { var dataView = new DataView(buffer); // little endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = values[i]; dataView.setUint16(byteIndex, value); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = dataView.getUint16(byteIndex); var expected = result[i]; Assert.equals(expected, value, 'Uint16 little endian: expected $expected but got $value at index $i'); - var valueBytes = [ - dataView.getUint8(byteIndex), - dataView.getUint8(byteIndex + 1) - ]; + var valueBytes = [dataView.getUint8(byteIndex), dataView.getUint8(byteIndex + 1)]; var expectedBytesLE = resultBytesLE[i]; Assert.equals(2, expectedBytesLE.length); - Assert.equals(expectedBytesLE[0], valueBytes[0], 'Uint16 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesLE[1], valueBytes[1], 'Uint16 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesLE[0], valueBytes[0], + 'Uint16 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesLE[1], valueBytes[1], + 'Uint16 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); } // big endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = values[i]; dataView.setUint16(byteIndex, value, false); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 2; var value = dataView.getUint16(byteIndex, false); var expected = result[i]; Assert.equals(expected, value, 'Uint16 big endian: expected $expected but got $value at index $i'); - var valueBytes = [ - dataView.getUint8(byteIndex), - dataView.getUint8(byteIndex + 1) - ]; + var valueBytes = [dataView.getUint8(byteIndex), dataView.getUint8(byteIndex + 1)]; var expectedBytesBE = resultBytesLE[i].copy(); expectedBytesBE.reverse(); // big endian is little endian reversed Assert.equals(2, expectedBytesBE.length); - Assert.equals(expectedBytesBE[0], valueBytes[0], 'Uint16 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesBE[1], valueBytes[1], 'Uint16 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesBE[0], valueBytes[0], + 'Uint16 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesBE[1], valueBytes[1], + 'Uint16 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); } } - public function testInt32():Void { + public function testInt32():Void + { var values:Array = [0, 1, 2, 2147483647, -1, -2, -2147483648]; var result:Array = [0, 1, 2, 2147483647, -1, -2, -2147483648]; var resultBytesLE:Array> = [ @@ -194,12 +199,14 @@ class DataViewTest extends Test { var dataView = new DataView(buffer); // little endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = values[i]; dataView.setInt32(byteIndex, value); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = dataView.getInt32(byteIndex); var expected = result[i]; @@ -213,19 +220,25 @@ class DataViewTest extends Test { ]; var expectedBytesLE = resultBytesLE[i]; Assert.equals(4, expectedBytesLE.length); - Assert.equals(expectedBytesLE[0], valueBytes[0], 'Int32 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesLE[1], valueBytes[1], 'Int32 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); - Assert.equals(expectedBytesLE[2], valueBytes[2], 'Int32 little endian: expected byte 2 to be ${StringTools.hex(expectedBytesLE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); - Assert.equals(expectedBytesLE[3], valueBytes[3], 'Int32 little endian: expected byte 3 to be ${StringTools.hex(expectedBytesLE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); + Assert.equals(expectedBytesLE[0], valueBytes[0], + 'Int32 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesLE[1], valueBytes[1], + 'Int32 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesLE[2], valueBytes[2], + 'Int32 little endian: expected byte 2 to be ${StringTools.hex(expectedBytesLE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); + Assert.equals(expectedBytesLE[3], valueBytes[3], + 'Int32 little endian: expected byte 3 to be ${StringTools.hex(expectedBytesLE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); } // big endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = values[i]; dataView.setInt32(byteIndex, value, false); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = dataView.getInt32(byteIndex, false); var expected = result[i]; @@ -240,14 +253,19 @@ class DataViewTest extends Test { var expectedBytesBE = resultBytesLE[i].copy(); expectedBytesBE.reverse(); // big endian is little endian reversed Assert.equals(4, expectedBytesBE.length); - Assert.equals(expectedBytesBE[0], valueBytes[0], 'Int32 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesBE[1], valueBytes[1], 'Int32 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); - Assert.equals(expectedBytesBE[2], valueBytes[2], 'Int32 big endian: expected byte 2 to be ${StringTools.hex(expectedBytesBE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); - Assert.equals(expectedBytesBE[3], valueBytes[3], 'Int32 big endian: expected byte 3 to be ${StringTools.hex(expectedBytesBE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); + Assert.equals(expectedBytesBE[0], valueBytes[0], + 'Int32 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesBE[1], valueBytes[1], + 'Int32 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesBE[2], valueBytes[2], + 'Int32 big endian: expected byte 2 to be ${StringTools.hex(expectedBytesBE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); + Assert.equals(expectedBytesBE[3], valueBytes[3], + 'Int32 big endian: expected byte 3 to be ${StringTools.hex(expectedBytesBE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); } } - public function testUint32():Void { + public function testUint32():Void + { var values:Array = [0, 1, 2, 0xffffffff, 0xdeadbeef, 0xcafebabe, 0xdecafbad]; var resultBytesLE:Array> = [ [0x00, 0x00, 0x00, 0x00], @@ -264,12 +282,14 @@ class DataViewTest extends Test { var dataView = new DataView(buffer); // little endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = values[i]; dataView.setUint32(byteIndex, value); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var valueBytes = [ dataView.getUint8(byteIndex), @@ -279,19 +299,25 @@ class DataViewTest extends Test { ]; var expectedBytesLE = resultBytesLE[i]; Assert.equals(4, expectedBytesLE.length); - Assert.equals(expectedBytesLE[0], valueBytes[0], 'Uint32 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesLE[1], valueBytes[1], 'Uint32 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); - Assert.equals(expectedBytesLE[2], valueBytes[2], 'Uint32 little endian: expected byte 2 to be ${StringTools.hex(expectedBytesLE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); - Assert.equals(expectedBytesLE[3], valueBytes[3], 'Uint32 little endian: expected byte 3 to be ${StringTools.hex(expectedBytesLE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); + Assert.equals(expectedBytesLE[0], valueBytes[0], + 'Uint32 little endian: expected byte 0 to be ${StringTools.hex(expectedBytesLE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesLE[1], valueBytes[1], + 'Uint32 little endian: expected byte 1 to be ${StringTools.hex(expectedBytesLE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesLE[2], valueBytes[2], + 'Uint32 little endian: expected byte 2 to be ${StringTools.hex(expectedBytesLE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); + Assert.equals(expectedBytesLE[3], valueBytes[3], + 'Uint32 little endian: expected byte 3 to be ${StringTools.hex(expectedBytesLE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); } // big endian - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var value = values[i]; dataView.setUint32(byteIndex, value, false); } - for (i in 0...count) { + for (i in 0...count) + { var byteIndex = i * 4; var valueBytes = [ dataView.getUint8(byteIndex), @@ -302,10 +328,14 @@ class DataViewTest extends Test { var expectedBytesBE = resultBytesLE[i].copy(); expectedBytesBE.reverse(); // big endian is little endian reversed Assert.equals(4, expectedBytesBE.length); - Assert.equals(expectedBytesBE[0], valueBytes[0], 'Uint32 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); - Assert.equals(expectedBytesBE[1], valueBytes[1], 'Uint32 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); - Assert.equals(expectedBytesBE[2], valueBytes[2], 'Uint32 big endian: expected byte 2 to be ${StringTools.hex(expectedBytesBE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); - Assert.equals(expectedBytesBE[3], valueBytes[3], 'Uint32 big endian: expected byte 3 to be ${StringTools.hex(expectedBytesBE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); + Assert.equals(expectedBytesBE[0], valueBytes[0], + 'Uint32 big endian: expected byte 0 to be ${StringTools.hex(expectedBytesBE[0])} but got ${StringTools.hex(valueBytes[0])} at index $i'); + Assert.equals(expectedBytesBE[1], valueBytes[1], + 'Uint32 big endian: expected byte 1 to be ${StringTools.hex(expectedBytesBE[1])} but got ${StringTools.hex(valueBytes[1])} at index $i'); + Assert.equals(expectedBytesBE[2], valueBytes[2], + 'Uint32 big endian: expected byte 2 to be ${StringTools.hex(expectedBytesBE[2])} but got ${StringTools.hex(valueBytes[2])} at index $i'); + Assert.equals(expectedBytesBE[3], valueBytes[3], + 'Uint32 big endian: expected byte 3 to be ${StringTools.hex(expectedBytesBE[3])} but got ${StringTools.hex(valueBytes[3])} at index $i'); } } -} \ No newline at end of file +} diff --git a/tests/unit/src/utils/UInt16ArrayTest.hx b/tests/unit/src/utils/UInt16ArrayTest.hx index 84200f99f4..6f3d1ae8cf 100644 --- a/tests/unit/src/utils/UInt16ArrayTest.hx +++ b/tests/unit/src/utils/UInt16ArrayTest.hx @@ -7,19 +7,23 @@ import lime.utils.ArrayBuffer; import utest.Assert; import utest.Test; -class UInt16ArrayTest extends Test { - public function new() { +class UInt16ArrayTest extends Test +{ + public function new() + { super(); } - public function testByteLength():Void { + public function testByteLength():Void + { var buffer = new ArrayBuffer(8); var array = new UInt16Array(buffer); Assert.equals(4, array.length); Assert.equals(8, array.byteLength); } - public function testValues():Void { + public function testValues():Void + { var buffer = new ArrayBuffer(8); var array = new UInt16Array(buffer); Assert.equals(0x0, array[0]); @@ -36,7 +40,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0xfbad, array[3]); } - public function testSubarray():Void { + public function testSubarray():Void + { var buffer = new ArrayBuffer(8); var array = new UInt16Array(buffer); array[0] = 0xcafe; @@ -81,12 +86,13 @@ class UInt16ArrayTest extends Test { Assert.equals(0xfbad, beyondLength[3]); } - public function testSetArrayOfInts():Void { + public function testSetArrayOfInts():Void + { var array1:Array = [0xcafe, 0xbabe, 0xdeca, 0xfbad]; var buffer2 = new ArrayBuffer(16); var array2 = new UInt16Array(buffer2); - + array2.set(array1); Assert.equals(0xcafe, array2[0]); Assert.equals(0xbabe, array2[1]); @@ -97,7 +103,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -111,11 +118,13 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); Assert.equals(0x0, array2[0]); @@ -128,7 +137,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt8Array():Void { + public function testSetUInt8Array():Void + { var buffer1 = new ArrayBuffer(4); var array1 = new UInt8Array(buffer1); array1[0] = 0xca; @@ -150,7 +160,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -164,12 +175,14 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -183,7 +196,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt16Array():Void { + public function testSetUInt16Array():Void + { var buffer1 = new ArrayBuffer(8); var array1 = new UInt16Array(buffer1); array1[0] = 0xcafe; @@ -205,7 +219,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -219,12 +234,14 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -238,7 +255,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt32Array():Void { + public function testSetUInt32Array():Void + { var buffer1 = new ArrayBuffer(16); var array1 = new UInt32Array(buffer1); array1[0] = 0xcafebabe; @@ -260,7 +278,8 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -274,12 +293,14 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -292,4 +313,4 @@ class UInt16ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); } -} \ No newline at end of file +} diff --git a/tests/unit/src/utils/UInt32ArrayTest.hx b/tests/unit/src/utils/UInt32ArrayTest.hx index 5e3c88a42a..882ff52efb 100644 --- a/tests/unit/src/utils/UInt32ArrayTest.hx +++ b/tests/unit/src/utils/UInt32ArrayTest.hx @@ -7,19 +7,23 @@ import lime.utils.ArrayBuffer; import utest.Assert; import utest.Test; -class UInt32ArrayTest extends Test { - public function new() { +class UInt32ArrayTest extends Test +{ + public function new() + { super(); } - public function testByteLength():Void { + public function testByteLength():Void + { var buffer = new ArrayBuffer(16); var array = new UInt32Array(buffer); Assert.equals(4, array.length); Assert.equals(16, array.byteLength); } - public function testValues():Void { + public function testValues():Void + { var buffer = new ArrayBuffer(16); var array = new UInt32Array(buffer); Assert.equals(0x0, array[0]); @@ -44,7 +48,8 @@ class UInt32ArrayTest extends Test { #end } - public function testSubarray():Void { + public function testSubarray():Void + { var buffer = new ArrayBuffer(16); var array = new UInt32Array(buffer); array[0] = 0xcafebabe; @@ -113,12 +118,13 @@ class UInt32ArrayTest extends Test { #end } - public function testSetArrayOfInts():Void { + public function testSetArrayOfInts():Void + { var array1:Array = [0xcafebabe, 0xdecafbad, 0xffffffff, 0xdeadbeef]; var buffer2 = new ArrayBuffer(32); var array2 = new UInt32Array(buffer2); - + array2.set(array1); #if js Assert.equals(untyped #if haxe4 js.Syntax.code #else __js__ #end ('0xcafebabe'), array2[0]); @@ -136,7 +142,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -165,7 +172,8 @@ class UInt32ArrayTest extends Test { var buffer2 = new ArrayBuffer(32); var array2 = new UInt32Array(buffer2); - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); Assert.equals(0x0, array2[0]); @@ -178,7 +186,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt8Array():Void { + public function testSetUInt8Array():Void + { var buffer1 = new ArrayBuffer(4); var array1 = new UInt8Array(buffer1); array1[0] = 0xca; @@ -200,7 +209,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -215,7 +225,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt8ArrayRangeError():Void { + public function testSetUInt8ArrayRangeError():Void + { var buffer1 = new ArrayBuffer(4); var array1 = new UInt8Array(buffer1); array1[0] = 0xca; @@ -227,7 +238,8 @@ class UInt32ArrayTest extends Test { var array2 = new UInt32Array(buffer2); // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -241,7 +253,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt16Array():Void { + public function testSetUInt16Array():Void + { var buffer1 = new ArrayBuffer(8); var array1 = new UInt16Array(buffer1); array1[0] = 0xcafe; @@ -263,7 +276,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -278,7 +292,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt16ArrayRangeError():Void { + public function testSetUInt16ArrayRangeError():Void + { var buffer1 = new ArrayBuffer(8); var array1 = new UInt16Array(buffer1); array1[0] = 0xcafe; @@ -290,7 +305,8 @@ class UInt32ArrayTest extends Test { var array2 = new UInt32Array(buffer2); // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -304,7 +320,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt32Array():Void { + public function testSetUInt32Array():Void + { var buffer1 = new ArrayBuffer(16); var array1 = new UInt32Array(buffer1); array1[0] = 0xcafebabe; @@ -333,7 +350,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -355,7 +373,8 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt32ArrayRangeError():Void { + public function testSetUInt32ArrayRangeError():Void + { var buffer1 = new ArrayBuffer(16); var array1 = new UInt32Array(buffer1); array1[0] = 0xcafebabe; @@ -367,7 +386,8 @@ class UInt32ArrayTest extends Test { var array2 = new UInt32Array(buffer2); // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -380,4 +400,4 @@ class UInt32ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); } -} \ No newline at end of file +} diff --git a/tests/unit/src/utils/UInt8ArrayTest.hx b/tests/unit/src/utils/UInt8ArrayTest.hx index 04a87afd8c..9503481fc9 100644 --- a/tests/unit/src/utils/UInt8ArrayTest.hx +++ b/tests/unit/src/utils/UInt8ArrayTest.hx @@ -7,19 +7,23 @@ import lime.utils.UInt8Array; import utest.Assert; import utest.Test; -class UInt8ArrayTest extends Test { - public function new() { +class UInt8ArrayTest extends Test +{ + public function new() + { super(); } - public function testByteLength():Void { + public function testByteLength():Void + { var buffer = new ArrayBuffer(4); var array = new UInt8Array(buffer); Assert.equals(4, array.length); Assert.equals(4, array.byteLength); } - public function testValues():Void { + public function testValues():Void + { var buffer = new ArrayBuffer(4); var array = new UInt8Array(buffer); Assert.equals(0x0, array[0]); @@ -36,7 +40,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0xbe, array[3]); } - public function testSubarray():Void { + public function testSubarray():Void + { var buffer = new ArrayBuffer(4); var array = new UInt8Array(buffer); array[0] = 0xca; @@ -81,12 +86,13 @@ class UInt8ArrayTest extends Test { Assert.equals(0xbe, beyondLength[3]); } - public function testSetArrayOfInts():Void { + public function testSetArrayOfInts():Void + { var array1:Array = [0xca, 0xfe, 0xba, 0xbe]; var buffer2 = new ArrayBuffer(8); var array2 = new UInt8Array(buffer2); - + array2.set(array1); Assert.equals(0xca, array2[0]); Assert.equals(0xfe, array2[1]); @@ -97,7 +103,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -111,11 +118,13 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); Assert.equals(0x0, array2[0]); @@ -128,7 +137,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt8Array():Void { + public function testSetUInt8Array():Void + { var buffer1 = new ArrayBuffer(4); var array1 = new UInt8Array(buffer1); array1[0] = 0xca; @@ -150,7 +160,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -164,12 +175,14 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -183,7 +196,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt16Array():Void { + public function testSetUInt16Array():Void + { var buffer1 = new ArrayBuffer(8); var array1 = new UInt16Array(buffer1); array1[0] = 0xcafe; @@ -205,7 +219,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -219,12 +234,14 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -238,7 +255,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); } - public function testSetUInt32Array():Void { + public function testSetUInt32Array():Void + { var buffer1 = new ArrayBuffer(16); var array1 = new UInt32Array(buffer1); array1[0] = 0xcafebabe; @@ -260,7 +278,8 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[7]); // reset the array to all zeros - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } @@ -274,12 +293,14 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); - for (i in 0...array2.length) { + for (i in 0...array2.length) + { array2[i] = 0x0; } // if the array can't fit, it throws - Assert.raises(function():Void { + Assert.raises(function():Void + { array2.set(array1, 6); }); // in that case, none of the values should have been updated @@ -292,4 +313,4 @@ class UInt8ArrayTest extends Test { Assert.equals(0x0, array2[6]); Assert.equals(0x0, array2[7]); } -} \ No newline at end of file +} diff --git a/tests/vulkan-smoke/Source/Main.hx b/tests/vulkan-smoke/Source/Main.hx index fd63e61ba6..d0ca0048ac 100644 --- a/tests/vulkan-smoke/Source/Main.hx +++ b/tests/vulkan-smoke/Source/Main.hx @@ -220,7 +220,11 @@ class Main extends Application return; } - if (!createSourceTexture() || !createGeometry() || !createDescriptorLayouts() || !createOffscreenPass() || !createOnscreenPass()) + if (!createSourceTexture() + || !createGeometry() + || !createDescriptorLayouts() + || !createOffscreenPass() + || !createOnscreenPass()) { return; } @@ -264,7 +268,8 @@ class Main extends Application return false; } - if (!commandBuffer.reset() || !commandBuffer.begin(VK.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) + 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) @@ -306,8 +311,7 @@ class Main extends Application return false; } - uniformBuffer = device.createUniformBuffer(Int64.ofInt(64), - VK.MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK.MEMORY_PROPERTY_HOST_COHERENT_BIT); + 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()); @@ -322,9 +326,9 @@ class Main extends Application 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 + 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) { @@ -338,10 +342,10 @@ class Main extends Application 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); + 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) { @@ -355,36 +359,36 @@ class Main extends Application 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 + -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, + 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 @@ -402,10 +406,10 @@ class Main extends Application 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); + 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) { @@ -441,13 +445,14 @@ class Main extends Application 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); + 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) + 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; @@ -462,8 +467,13 @@ class Main extends Application 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 + 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()); @@ -492,17 +502,15 @@ class Main extends Application { 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); + 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); + 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()) @@ -516,8 +524,12 @@ class Main extends Application 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)) + 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; @@ -555,8 +567,7 @@ class Main extends Application } 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); + 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; @@ -570,8 +581,8 @@ class Main extends Application { 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); + 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; @@ -671,7 +682,8 @@ class Main extends Application return false; } - if (!fence.reset() || !device.graphicsQueue.submitSynced(commandBuffer, imageAvailable, renderFinished, fence) + if (!fence.reset() + || !device.graphicsQueue.submitSynced(commandBuffer, imageAvailable, renderFinished, fence) || !fence.waitForever()) { fail("Failed to submit Vulkan draw commands: " + VK.getLastError()); @@ -933,10 +945,10 @@ class Main extends Application { 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 + 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; } diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx index 0d3e63f448..67f27f7920 100644 --- a/tools/CommandLineTools.hx +++ b/tools/CommandLineTools.hx @@ -420,8 +420,7 @@ class CommandLineTools publishProject(); case "installer", "copy-if-newer": - - // deprecated? + // deprecated? default: Log.error("'" + command + "' is not a valid command"); @@ -511,7 +510,7 @@ class CommandLineTools case LINUX: var arguments = Sys.args(); - if (System.hostArchitecture == ARMV7 ) + if (System.hostArchitecture == ARMV7) { untyped $loader.path = $array(path + "LinuxArm/", $loader.path); } @@ -600,19 +599,16 @@ class CommandLineTools platform = new AndroidPlatform(command, project, targetFlags); case BLACKBERRY: - - // platform = new BlackBerryPlatform (command, project, targetFlags); + // platform = new BlackBerryPlatform (command, project, targetFlags); case IOS: platform = new IOSPlatform(command, project, targetFlags); case TIZEN: - - // platform = new TizenPlatform (command, project, targetFlags); + // platform = new TizenPlatform (command, project, targetFlags); case WEBOS: - - // platform = new WebOSPlatform (command, project, targetFlags); + // platform = new WebOSPlatform (command, project, targetFlags); case WINDOWS: platform = new WindowsPlatform(command, project, targetFlags); @@ -788,14 +784,22 @@ class CommandLineTools { var commands = [ - "config" => "Display or set command-line configuration values", "create" => "Create a new project or extension using templates", - "clean" => "Clean the specified project and target", "update" => "Copy assets for the specified project and target", - "build" => "Compile and package for the specified project and target", "run" => "Install and run for the specified project and target", - "test" => "Update, build and run in one command", "help" => "Show this information", - "trace" => "Trace output for the specifed project and target", "deploy" => "Archive and upload builds", - "display" => "Display information for the specified project and target", "rebuild" => "Recompile native binaries for libraries", - "install" => "Install a library from haxelib, plus dependencies", "remove" => "Remove a library from haxelib", - "upgrade" => "Upgrade a library from haxelib", "setup" => "Setup " + defaultLibraryName + " or a specific platform" + "config" => "Display or set command-line configuration values", + "create" => "Create a new project or extension using templates", + "clean" => "Clean the specified project and target", + "update" => "Copy assets for the specified project and target", + "build" => "Compile and package for the specified project and target", + "run" => "Install and run for the specified project and target", + "test" => "Update, build and run in one command", + "help" => "Show this information", + "trace" => "Trace output for the specifed project and target", + "deploy" => "Archive and upload builds", + "display" => "Display information for the specified project and target", + "rebuild" => "Recompile native binaries for libraries", + "install" => "Install a library from haxelib, plus dependencies", + "remove" => "Remove a library from haxelib", + "upgrade" => "Upgrade a library from haxelib", + "setup" => "Setup " + defaultLibraryName + " or a specific platform" ]; @@ -1841,7 +1845,9 @@ class CommandLineTools var projectDirectory = Path.directory(projectFile); var localRepository = Path.combine(projectDirectory, ".haxelib"); - if (FileSystem.exists(localRepository) && FileSystem.isDirectory(localRepository) && StringTools.startsWith(path, localRepository)) + if (FileSystem.exists(localRepository) + && FileSystem.isDirectory(localRepository) + && StringTools.startsWith(path, localRepository)) { args.push("-nolocalrepocheck"); } diff --git a/tools/RunScript.hx b/tools/RunScript.hx index 8b6060829e..4dcd97b71f 100644 --- a/tools/RunScript.hx +++ b/tools/RunScript.hx @@ -27,7 +27,16 @@ class RunScript if (!rebuildBinaries) return; - var platforms = ["Windows", "Mac", "Mac64", "MacArm64", "Linux", "Linux64", "LinuxArm", "LinuxArm64"]; + var platforms = [ + "Windows", + "Mac", + "Mac64", + "MacArm64", + "Linux", + "Linux64", + "LinuxArm", + "LinuxArm64" + ]; for (platform in platforms) { @@ -208,17 +217,17 @@ class RunScript if (args.indexOf("-eval") >= 0) { args.remove("-eval"); - Log.info("Experimental: executing `lime " + args.slice(0, args.length - 1).join(" ") - + "` using Eval (https://haxe.org/blog/eval/)"); + Log.info("Experimental: executing `lime " + args.slice(0, args.length - 1).join(" ") + "` using Eval (https://haxe.org/blog/eval/)"); var args = [ - "-D", "lime", - "-cp", toolsDirectory, - "-cp", Path.combine(toolsDirectory, "platforms"), - "-cp", Path.combine(limeDirectory, "src"), - "-lib", "format", - "-lib", "hxp", - "--run", "CommandLineTools"].concat(args); + "-D", "lime", + "-cp", toolsDirectory, + "-cp", Path.combine(toolsDirectory, "platforms"), + "-cp", Path.combine(limeDirectory, "src"), + "-lib", "format", + "-lib", "hxp", + "--run", "CommandLineTools" + ].concat(args); Sys.exit(runCommand("", "haxe", args)); } diff --git a/tools/SVGExport.hx b/tools/SVGExport.hx index 4bb62d0bdf..f83d2e23e9 100644 --- a/tools/SVGExport.hx +++ b/tools/SVGExport.hx @@ -79,7 +79,7 @@ class SVGExport case LINUX: var arguments = Sys.args(); - if ( System.hostArchitecture == ARMV7 ) + if (System.hostArchitecture == ARMV7) { untyped $loader.path = $array(path + "LinuxArm/", $loader.path); } diff --git a/tools/mpeg/audio/MpegAudioReader.hx b/tools/mpeg/audio/MpegAudioReader.hx index 91ba3f830b..81a0279828 100644 --- a/tools/mpeg/audio/MpegAudioReader.hx +++ b/tools/mpeg/audio/MpegAudioReader.hx @@ -102,14 +102,14 @@ class MpegAudioReader frames.push(frame); case Info(_): - // Discard info tag. + // Discard info tag. case GaplessInfo(giEncoderDelay, giEndPadding): encoderDelay = giEncoderDelay; endPadding = giEndPadding; case Unknown(_): - // Discard unknown bytes + // Discard unknown bytes case End: break; diff --git a/tools/platforms/AndroidPlatform.hx b/tools/platforms/AndroidPlatform.hx index 5adcb94ceb..2887c6a23c 100644 --- a/tools/platforms/AndroidPlatform.hx +++ b/tools/platforms/AndroidPlatform.hx @@ -162,8 +162,16 @@ class AndroidPlatform extends PlatformTarget for (architecture in architectures) { var minSDKVer = project.config.getInt("android.minimum-sdk-version", 21); - //PLATFORM define needed for older ndk and gcc toolchain - var haxeParams = [hxml, "-D", "android", "-D", 'PLATFORM_NUMBER=$minSDKVer', "-D", 'PLATFORM=android-$minSDKVer']; + // PLATFORM define needed for older ndk and gcc toolchain + var haxeParams = [ + hxml, + "-D", + "android", + "-D", + 'PLATFORM_NUMBER=$minSDKVer', + "-D", + 'PLATFORM=android-$minSDKVer' + ]; var cppParams = ["-Dandroid", '-DPLATFORM_NUMBER=$minSDKVer', '-DPLATFORM=android-$minSDKVer']; var path = sourceSet + "/jniLibs/armeabi"; var suffix = ".so"; @@ -301,7 +309,8 @@ class AndroidPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -357,8 +366,7 @@ class AndroidPlatform extends PlatformTarget public override function rebuild():Void { - var armv5 = (/*command == "rebuild" ||*/ - ArrayTools.containsValue(project.architectures, Architecture.ARMV5) + var armv5 = (/*command == "rebuild" ||*/ ArrayTools.containsValue(project.architectures, Architecture.ARMV5) || ArrayTools.containsValue(project.architectures, Architecture.ARMV6)); var armv7 = (command == "rebuild" || ArrayTools.containsValue(project.architectures, Architecture.ARMV7)); var arm64 = (command == "rebuild" || ArrayTools.containsValue(project.architectures, Architecture.ARM64)); @@ -447,30 +455,43 @@ class AndroidPlatform extends PlatformTarget 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, - "android:versionName": project.meta.version, - "android:installLocation": project.config.getString("android.install-location", "auto") - }); + context.ANDROID_MANIFEST = project.config.getKeyValueArray("android.manifest", + { + "android:versionCode": project.meta.buildNumber, + "android:versionName": project.meta.version, + "android:installLocation": project.config.getString("android.install-location", "auto") + }); context.ANDROID_MANIFEST_CHILDREN = project.config.get("android.manifest").xmlChildren; - context.ANDROID_APPLICATION = project.config.getKeyValueArray("android.application", { - "android:label": project.meta.title, - "android:allowBackup": "true", - "android:theme": "@android:style/Theme.NoTitleBar" + (project.window.fullscreen ? ".Fullscreen" : ""), - "android:hardwareAccelerated": "true", - "android:allowNativeHeapPointerTagging": context.ANDROID_TARGET_SDK_VERSION >= 30 ? "false" : null - }); + context.ANDROID_APPLICATION = project.config.getKeyValueArray("android.application", + { + "android:label": project.meta.title, + "android:allowBackup": "true", + "android:theme": "@android:style/Theme.NoTitleBar" + (project.window.fullscreen ? ".Fullscreen" : ""), + "android:hardwareAccelerated": "true", + "android:allowNativeHeapPointerTagging": context.ANDROID_TARGET_SDK_VERSION >= 30 ? "false" : null + }); context.ANDROID_APPLICATION_CHILDREN = project.config.get("android.application").xmlChildren; - context.ANDROID_ACTIVITY = project.config.getKeyValueArray("android.activity", { - "android:name": "MainActivity", - "android:exported": "true", - "android:launchMode": "singleTask", - "android:label": project.meta.title, - "android:configChanges": project.config.getArrayString("android.configChanges", - ["layoutDirection", "locale", "orientation", "uiMode", "screenLayout", "screenSize", "smallestScreenSize", "keyboard", "keyboardHidden", "navigation"]) - .join("|"), - "android:screenOrientation": project.window.orientation == PORTRAIT ? "sensorPortrait" : (project.window.orientation == LANDSCAPE ? "sensorLandscape" : null) - }); + context.ANDROID_ACTIVITY = project.config.getKeyValueArray("android.activity", + { + "android:name": "MainActivity", + "android:exported": "true", + "android:launchMode": "singleTask", + "android:label": project.meta.title, + "android:configChanges": project.config.getArrayString("android.configChanges", + [ + "layoutDirection", + "locale", + "orientation", + "uiMode", + "screenLayout", + "screenSize", + "smallestScreenSize", + "keyboard", + "keyboardHidden", + "navigation" + ]).join("|"), + "android:screenOrientation": project.window.orientation == PORTRAIT ? "sensorPortrait" : (project.window.orientation == LANDSCAPE ? "sensorLandscape" : null) + }); context.ANDROID_ACTIVITY_CHILDREN = project.config.get("android.activity").xmlChildren; context.ANDROID_ACCEPT_FILE_INTENT = project.config.getArrayString("android.accept-file-intent", []); @@ -544,9 +565,7 @@ class AndroidPlatform extends PlatformTarget } } } - catch (e:Dynamic) - { - } + catch (e:Dynamic) {} } if (Reflect.hasField(context, "KEY_STORE")) context.KEY_STORE = StringTools.replace(context.KEY_STORE, "\\", "\\\\"); @@ -606,7 +625,7 @@ class AndroidPlatform extends PlatformTarget && !context.HAS_ICON) { context.HAS_ICON = true; - context.ANDROID_APPLICATION.push({ key: "android:icon", value: "@drawable/icon" }); + context.ANDROID_APPLICATION.push({key: "android:icon", value: "@drawable/icon"}); } } diff --git a/tools/platforms/FlashPlatform.hx b/tools/platforms/FlashPlatform.hx index 7fd57cd39e..e2fa792214 100644 --- a/tools/platforms/FlashPlatform.hx +++ b/tools/platforms/FlashPlatform.hx @@ -173,7 +173,8 @@ class FlashPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -312,21 +313,20 @@ class FlashPlatform extends PlatformTarget } /*private function getIcon (size:Int, targetPath:String):Void { - - var icon = icons.findIcon (size, size); - - if (icon != "") { - - System.copyIfNewer (icon, targetPath); - - } else { - - icons.updateIcon (size, size, targetPath); - - } - - }*/ - + + var icon = icons.findIcon (size, size); + + if (icon != "") { + + System.copyIfNewer (icon, targetPath); + + } else { + + icons.updateIcon (size, size, targetPath); + + } + + }*/ @ignore public override function install():Void {} @ignore public override function rebuild():Void {} diff --git a/tools/platforms/HTML5Platform.hx b/tools/platforms/HTML5Platform.hx index e998836661..498b7cb8b8 100644 --- a/tools/platforms/HTML5Platform.hx +++ b/tools/platforms/HTML5Platform.hx @@ -209,7 +209,8 @@ class HTML5Platform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); diff --git a/tools/platforms/IOSPlatform.hx b/tools/platforms/IOSPlatform.hx index 915463819f..b5e5931a44 100644 --- a/tools/platforms/IOSPlatform.hx +++ b/tools/platforms/IOSPlatform.hx @@ -409,7 +409,7 @@ class IOSPlatform extends PlatformTarget if (allowInsecureHTTP != "*" && allowInsecureHTTP != "true") { - var sites:Array<{domain: String}> = []; + var sites:Array<{domain:String}> = []; if (allowInsecureHTTP != "false") { @@ -446,7 +446,8 @@ class IOSPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -867,7 +868,6 @@ class IOSPlatform extends PlatformTarget context.HAS_LAUNCH_IMAGE = has_launch_image; }*/ - @ignore public override function install():Void {} @ignore public override function trace():Void {} diff --git a/tools/platforms/LinuxPlatform.hx b/tools/platforms/LinuxPlatform.hx index 094b0a9022..0bccbbc624 100644 --- a/tools/platforms/LinuxPlatform.hx +++ b/tools/platforms/LinuxPlatform.hx @@ -122,7 +122,9 @@ class LinuxPlatform extends PlatformTarget for (architecture in project.architectures) { - if (!targetFlags.exists("32") && !targetFlags.exists("x86_32") && (architecture == Architecture.X64 || architecture == Architecture.ARM64)) + if (!targetFlags.exists("32") + && !targetFlags.exists("x86_32") + && (architecture == Architecture.X64 || architecture == Architecture.ARM64)) { is64 = true; } @@ -198,7 +200,8 @@ class LinuxPlatform extends PlatformTarget } else { - ProjectHelper.copyLibrary(project, ndll, "Linux" + (( System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64)?"Arm":"") + (is64 ? "64" : ""), "", + ProjectHelper.copyLibrary(project, ndll, + "Linux" + ((System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64) ? "Arm" : "") + (is64 ? "64" : ""), "", (ndll.haxelib != null && (ndll.haxelib.name == "hxcpp" || ndll.haxelib.name == "hxlibc")) ? ".dll" : ".ndll", applicationDirectory, project.debug, targetSuffix); @@ -212,9 +215,13 @@ class LinuxPlatform extends PlatformTarget if (noOutput) return; - NekoHelper.createExecutable(project.templatePaths, "linux" + (( System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64)?"Arm":"") + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + NekoHelper.createExecutable(project.templatePaths, + "linux" + + ((System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64) ? "Arm" : "") + + (is64 ? "64" : ""), + targetDirectory + + "/obj/ApplicationMain.n", executablePath); NekoHelper.copyLibraries(project.templatePaths, "linux" + (is64 ? "64" : ""), applicationDirectory); - } else if (targetType == "hl") { @@ -230,12 +237,15 @@ class LinuxPlatform extends PlatformTarget var command = [ compiler, "-O3", - "-o", executablePath, + "-o", + executablePath, "-std=c11", "-Wl,-rpath,$ORIGIN", - "-I", Path.combine(targetDirectory, "obj"), + "-I", + Path.combine(targetDirectory, "obj"), Path.combine(targetDirectory, "obj/ApplicationMain.c"), - "-L", applicationDirectory, + "-L", + applicationDirectory, // gcc 14 and clang 22 made incompatible-pointer-types an // error instead of a warning, but it's required for // assignment to Dynamic in Haxe @@ -416,7 +426,7 @@ class LinuxPlatform extends PlatformTarget { // var project = project.clone (); - if(targetFlags.exists('rpi')) + if (targetFlags.exists('rpi')) { project.haxedefs.set("rpi", 1); } @@ -441,7 +451,8 @@ class LinuxPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -473,7 +484,7 @@ class LinuxPlatform extends PlatformTarget { var commands:Array> = []; - if (targetFlags.exists('rpi') && System.hostArchitecture == ARM64 ) + if (targetFlags.exists('rpi') && System.hostArchitecture == ARM64) { commands.push([ "-Dlinux", @@ -506,14 +517,9 @@ class LinuxPlatform extends PlatformTarget // TODO: Support single binary commands.push(["-Dlinux", "-DHXCPP_M64", "-Dhashlink"]); } - else if (System.hostArchitecture == ARM64 ) + else if (System.hostArchitecture == ARM64) { - commands.push([ - "-Dlinux", - "-Dtoolchain=linux", - "-DBINDIR=LinuxArm64", - "-DHXCPP_ARM64", - ]); + commands.push(["-Dlinux", "-Dtoolchain=linux", "-DBINDIR=LinuxArm64", "-DHXCPP_ARM64",]); } else { @@ -590,7 +596,9 @@ class LinuxPlatform extends PlatformTarget if (ndll.path == null || ndll.path == "") { - context.ndlls[i].path = NDLL.getLibraryPath(ndll, "Linux" + (( System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64) ? "Arm" : "") + (is64 ? "64" : ""), "lib", ".a", project.debug); + context.ndlls[i].path = NDLL.getLibraryPath(ndll, + "Linux" + ((System.hostArchitecture == ARMV7 || System.hostArchitecture == ARM64) ? "Arm" : "") + (is64 ? "64" : ""), "lib", ".a", + project.debug); } } } diff --git a/tools/platforms/MacPlatform.hx b/tools/platforms/MacPlatform.hx index f2c0b3b6bd..c883bbf68b 100644 --- a/tools/platforms/MacPlatform.hx +++ b/tools/platforms/MacPlatform.hx @@ -231,13 +231,16 @@ class MacPlatform extends PlatformTarget // if we ever support ARM or Universal binaries, this will // need to be handled differently. var command = [ - "arch", "-x86_64", + "arch", + "-x86_64", compiler, "-O3", - "-o", executablePath, + "-o", + executablePath, "-std=c11", "-Wl,-rpath,@executable_path", - "-I", Path.combine(targetDirectory, "obj"), + "-I", + Path.combine(targetDirectory, "obj"), Path.combine(targetDirectory, "obj/ApplicationMain.c"), // gcc 14 and clang 22 made incompatible-pointer-types an // error instead of a warning, but it's required for @@ -264,7 +267,12 @@ class MacPlatform extends PlatformTarget // when launched inside an .app file, the executable // can't find the library files unless we tell // it to search specifically from @executable_path - System.runCommand("", "install_name_tool", ["-change", Path.withoutDirectory(file), "@executable_path/" + Path.withoutDirectory(file), executablePath]); + System.runCommand("", "install_name_tool", [ + "-change", + Path.withoutDirectory(file), + "@executable_path/" + Path.withoutDirectory(file), + executablePath + ]); default: } } @@ -367,7 +375,10 @@ class MacPlatform extends PlatformTarget } } - if (System.hostPlatform != WINDOWS && targetType != "nodejs" && targetType != "java" && sys.FileSystem.exists(executablePath)) + if (System.hostPlatform != WINDOWS + && targetType != "nodejs" + && targetType != "java" + && sys.FileSystem.exists(executablePath)) { System.runCommand("", "chmod", ["755", executablePath]); } @@ -410,7 +421,8 @@ class MacPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -632,10 +644,7 @@ class MacPlatform extends PlatformTarget // these are the known directories where Homebrew installs its dependencies // we may need to add more in the future, but this seems to be enough for now - var homebrewDirs = [ - "/usr/local/opt/", - "/usr/local/Cellar/" - ]; + var homebrewDirs = ["/usr/local/opt/", "/usr/local/Cellar/"]; // first, collect all executables, hdlls, and dylibs that were built // by BuildHashlink.xml @@ -700,7 +709,10 @@ class MacPlatform extends PlatformTarget continue; } } - if (Lambda.exists(homebrewDirs, function(dirPath:String):Bool { return StringTools.startsWith(resolvedLibPath, dirPath); })) + if (Lambda.exists(homebrewDirs, function(dirPath:String):Bool + { + return StringTools.startsWith(resolvedLibPath, dirPath); + })) { homebrewDependencyPaths.push(libPath); pathsToSearchForHomebrewDependencies.push(resolvedLibPath); diff --git a/tools/platforms/TVOSPlatform.hx b/tools/platforms/TVOSPlatform.hx index 331805dd94..39e0b629d0 100644 --- a/tools/platforms/TVOSPlatform.hx +++ b/tools/platforms/TVOSPlatform.hx @@ -357,7 +357,8 @@ class TVOSPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -638,7 +639,6 @@ class TVOSPlatform extends PlatformTarget context.HAS_LAUNCH_IMAGE = has_launch_image; }*/ - @ignore public override function install():Void {} @ignore public override function trace():Void {} diff --git a/tools/platforms/WebAssemblyPlatform.hx b/tools/platforms/WebAssemblyPlatform.hx index 11281fb8de..47e30643bc 100644 --- a/tools/platforms/WebAssemblyPlatform.hx +++ b/tools/platforms/WebAssemblyPlatform.hx @@ -118,7 +118,19 @@ class WebAssemblyPlatform extends PlatformTarget } var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; - var args = [hxml, "-D", "webassembly", "-D", "wasm", "-D", "emscripten", "-D", "webgl", "-D", "static_link"]; + var args = [ + hxml, + "-D", + "webassembly", + "-D", + "wasm", + "-D", + "emscripten", + "-D", + "webgl", + "-D", + "static_link" + ]; if (Log.verbose) { @@ -135,7 +147,13 @@ class WebAssemblyPlatform extends PlatformTarget project.path(sdkPath); - System.runCommand("", "emcc", ["-c", "-fwasm-exceptions", targetDirectory + "/obj/Main.cpp", "-o", targetDirectory + "/obj/Main.o"], true, false, true); + System.runCommand("", "emcc", [ + "-c", + "-fwasm-exceptions", + targetDirectory + "/obj/Main.cpp", + "-o", + targetDirectory + "/obj/Main.o" + ], true, false, true); args = ["Main.o"]; @@ -159,9 +177,7 @@ class WebAssemblyPlatform extends PlatformTarget prefix = "lib"; } - args = args.concat([ - prefix + "ApplicationMain" + (project.debug ? "-debug" : "") + ".a" - ]); + args = args.concat([prefix + "ApplicationMain" + (project.debug ? "-debug" : "") + ".a"]); if (!project.targetFlags.exists("asmjs")) { @@ -188,19 +204,19 @@ class WebAssemblyPlatform extends PlatformTarget } } - // Fix Rendering - args.push("-s"); - args.push("MIN_WEBGL_VERSION=2"); - args.push("-s"); - args.push("MAX_WEBGL_VERSION=2"); + // Fix Rendering + args.push("-s"); + args.push("MIN_WEBGL_VERSION=2"); + args.push("-s"); + args.push("MAX_WEBGL_VERSION=2"); - // Fix GC - args.push("--Wno-limited-postlink-optimizations"); - // https://github.com/HaxeFoundation/hxcpp/blob/767fe94d19a041147c4f65dea02c89cb206a0758/toolchain/emscripten-toolchain.xml#L29-L33 - args.push("-s"); - args.push("BINARYEN_EXTRA_PASSES='--spill-pointers'"); + // Fix GC + args.push("--Wno-limited-postlink-optimizations"); + // https://github.com/HaxeFoundation/hxcpp/blob/767fe94d19a041147c4f65dea02c89cb206a0758/toolchain/emscripten-toolchain.xml#L29-L33 + args.push("-s"); + args.push("BINARYEN_EXTRA_PASSES='--spill-pointers'"); - args.push("-fwasm-exceptions"); + args.push("-fwasm-exceptions"); // set initial size // args.push("-s"); @@ -209,31 +225,32 @@ class WebAssemblyPlatform extends PlatformTarget args.push("-s"); args.push("STACK_SIZE=1MB"); - args.push("-s"); - args.push("FETCH=1"); + args.push("-s"); + args.push("FETCH=1"); // args.push("-s"); // args.push("SAFE_HEAP=1"); if (project.targetFlags.exists("final")) { - args.push("-O3"); + args.push("-O3"); } else if (!project.debug) { - args.push("-O2"); + args.push("-O2"); } else { - args.push("-O1"); + args.push("-O1"); } args.push("-s"); args.push("ALLOW_MEMORY_GROWTH=1"); - if(project.targetFlags.exists("websocket")) { - args.push("-lwebsocket.js"); - } + if (project.targetFlags.exists("websocket")) + { + args.push("-lwebsocket.js"); + } if (project.targetFlags.exists("minify")) { @@ -334,7 +351,8 @@ class WebAssemblyPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index de9f8ec17b..fd59564832 100644 --- a/tools/platforms/WindowsPlatform.hx +++ b/tools/platforms/WindowsPlatform.hx @@ -260,7 +260,15 @@ class WindowsPlatform extends PlatformTarget // start by finding visual studio var programFilesX86 = Sys.getEnv("ProgramFiles(x86)"); var vswhereCommand = programFilesX86 + "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; - var vswhereOutput = System.runProcess("", vswhereCommand, ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild", "-property", "installationPath"]); + var vswhereOutput = System.runProcess("", vswhereCommand, [ + "-latest", + "-products", + "*", + "-requires", + "Microsoft.Component.MSBuild", + "-property", + "installationPath" + ]); var visualStudioPath = StringTools.trim(vswhereOutput); // then, find MSBuild inside visual studio var msBuildPath = visualStudioPath + "\\MSBuild\\Current\\Bin\\MSBuild.exe"; @@ -332,8 +340,7 @@ class WindowsPlatform extends PlatformTarget { ProjectHelper.copyLibrary(project, ndll, "Windows" + (is64 ? "64" : ""), "", ".hdll", applicationDirectory, project.debug, targetSuffix); - ProjectHelper.copyLibrary(project, ndll, "Windows" + (is64 ? "64" : ""), "", ".lib", applicationDirectory, project.debug, - ".lib"); + ProjectHelper.copyLibrary(project, ndll, "Windows" + (is64 ? "64" : ""), "", ".lib", applicationDirectory, project.debug, ".lib"); } else { @@ -378,10 +385,12 @@ class WindowsPlatform extends PlatformTarget command = [ "gcc", "-O3", - "-o", executablePath, + "-o", + executablePath, "-std=c11", "-Wl,-subsystem,windows", - "-I", Path.combine(targetDirectory, "obj"), + "-I", + Path.combine(targetDirectory, "obj"), Path.combine(targetDirectory, "obj/ApplicationMain.c"), "C:/Windows/System32/dbghelp.dll", // gcc 14 and clang 22 made incompatible-pointer-types an @@ -405,13 +414,31 @@ class WindowsPlatform extends PlatformTarget // start by finding visual studio var programFilesX86 = Sys.getEnv("ProgramFiles(x86)"); var vswhereCommand = programFilesX86 + "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; - var vswhereOutput = System.runProcess("", vswhereCommand, ["-latest", "-products", "*", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath"]); + var vswhereOutput = System.runProcess("", vswhereCommand, [ + "-latest", + "-products", + "*", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", + "installationPath" + ]); var visualStudioPath = StringTools.trim(vswhereOutput); var vcvarsallPath = visualStudioPath + "\\VC\\Auxiliary\\Build\\vcvarsall.bat"; // this command sets up the environment variables and things that visual studio requires - var vcvarsallCommand = [vcvarsallPath, "x64"].map(function(arg:String):String { return ~/([&|\(\)<>\^ ])/g.replace(arg, "^$1"); }); + var vcvarsallCommand = [vcvarsallPath, "x64"].map(function(arg:String):String + { + return ~/([&|\(\)<>\^ ])/g.replace(arg, "^$1"); + }); // this command runs the cl.exe c compiler from visual studio - var clCommand = ["cl.exe", "/Ox", "/Fe:" + executablePath, "-I", Path.combine(targetDirectory, "obj"), Path.combine(targetDirectory, "obj/ApplicationMain.c")]; + var clCommand = [ + "cl.exe", + "/Ox", + "/Fe:" + executablePath, + "-I", + Path.combine(targetDirectory, "obj"), + Path.combine(targetDirectory, "obj/ApplicationMain.c") + ]; for (file in System.readDirectory(applicationDirectory)) { switch Path.extension(file) @@ -424,7 +451,10 @@ class WindowsPlatform extends PlatformTarget } clCommand.push("/link"); clCommand.push("/subsystem:windows"); - clCommand = clCommand.map(function(arg:String):String { return ~/([&|\(\)<>\^ ])/g.replace(arg, "^$1"); }); + clCommand = clCommand.map(function(arg:String):String + { + return ~/([&|\(\)<>\^ ])/g.replace(arg, "^$1"); + }); // combine both commands into one command = ["cmd.exe", "/s", "/c", vcvarsallCommand.join(" ") + " && " + clCommand.join(" ")]; } @@ -736,7 +766,8 @@ class WindowsPlatform extends PlatformTarget // modified more recently than the .hxml, then the .hxml cannot be // considered valid anymore. it may cause errors in editors like vscode. if (FileSystem.exists(path) - && (project.projectFilePath == null || !FileSystem.exists(project.projectFilePath) + && (project.projectFilePath == null + || !FileSystem.exists(project.projectFilePath) || (FileSystem.stat(path).mtime.getTime() > FileSystem.stat(project.projectFilePath).mtime.getTime()))) { return File.getContent(path); @@ -781,7 +812,8 @@ class WindowsPlatform extends PlatformTarget if (targetType == "hl") { // default to 64 bit, just like upstream Hashlink releases - if (!targetFlags.exists("32") && !targetFlags.exists("x86_32") + if (!targetFlags.exists("32") + && !targetFlags.exists("x86_32") && (System.hostArchitecture == X64 || targetFlags.exists("64") || targetFlags.exists("x86_64"))) { commands.push(["-Dwindows", "-DHXCPP_M64", "-Dhashlink"]); @@ -793,7 +825,8 @@ class WindowsPlatform extends PlatformTarget } else { - if (!targetFlags.exists("64") && !targetFlags.exists("x86_64") + if (!targetFlags.exists("64") + && !targetFlags.exists("x86_64") && (command == "rebuild" || System.hostArchitecture == X86 || (targetType != "cpp" && targetType != "winrt"))) { if (targetType == "winrt") @@ -810,7 +843,8 @@ class WindowsPlatform extends PlatformTarget // as previous Windows builds. For now, force -64 to be done last // so that it can be debugged in a default "rebuild" - if (!targetFlags.exists("32") && !targetFlags.exists("x86_32") + if (!targetFlags.exists("32") + && !targetFlags.exists("x86_32") && System.hostArchitecture == X64 && (command != "rebuild" || targetType == "cpp" || targetType == "neko" || targetType == "winrt")) { diff --git a/tools/utils/PlatformSetup.hx b/tools/utils/PlatformSetup.hx index 2ba158cb00..5d64d37e70 100644 --- a/tools/utils/PlatformSetup.hx +++ b/tools/utils/PlatformSetup.hx @@ -366,8 +366,7 @@ class PlatformSetup setupAndroid(); case "blackberry": - - // setupBlackBerry (); + // setupBlackBerry (); case "html5": Log.println("\x1b[0;3mNo additional configuration is required.\x1b[0m"); @@ -392,15 +391,13 @@ class PlatformSetup } case "tizen": - - // setupTizen (); + // setupTizen (); case "webassembly", "wasm", "emscripten": setupWebAssembly(); case "webos": - - // setupWebOS (); + // setupWebOS (); case "electron": setupElectron(); @@ -1236,9 +1233,12 @@ class PlatformSetup public static function setupHL():Void { var message = "Absolute path to a custom version of HashLink."; - if (ConfigHelper.getConfigValue("HL_PATH") == null) { + if (ConfigHelper.getConfigValue("HL_PATH") == null) + { message += " Leave empty to use Lime's default bundled version."; - } else { + } + else + { message += " Leave empty to keep the currently configured version. To restore Lime's default bundled version, run the command: lime config remove HL_PATH"; } getDefineValue("HL_PATH", message); @@ -1274,8 +1274,25 @@ class PlatformSetup "extendedKeyUsage=critical,codeSigning", ].join("\n")); System.runCommand("", "openssl", [ - "req", "-x509", "-newkey", "rsa:4096", "-keyout", key, "-nodes", "-days", "365", "-subj", "/CN=hl-cert", "-outform", "der", "-out", - cert, "-extensions", "v3_req", "-config", openSSLConf + "req", + "-x509", + "-newkey", + "rsa:4096", + "-keyout", + key, + "-nodes", + "-days", + "365", + "-subj", + "/CN=hl-cert", + "-outform", + "der", + "-out", + cert, + "-extensions", + "v3_req", + "-config", + openSSLConf ], true, false, true); System.runCommand("", "sudo", [ "security", From ab7d396451801bb36da7deab254446fd7fa53d0e Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 23 Jun 2026 14:09:50 -0700 Subject: [PATCH 069/251] Bytes.cpp: constructor with no arguments should not call _initializeBytes() on HashLink --- project/src/utils/Bytes.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/project/src/utils/Bytes.cpp b/project/src/utils/Bytes.cpp index e0136147f6..9cf89dbd40 100644 --- a/project/src/utils/Bytes.cpp +++ b/project/src/utils/Bytes.cpp @@ -40,7 +40,9 @@ namespace lime { Bytes::Bytes () { + #ifndef LIME_HASHLINK _initializeBytes (); + #endif b = 0; length = 0; @@ -181,22 +183,22 @@ namespace lime { } - void Bytes::Set(value bytes) { - + void Bytes::Set(value bytes) { + int newLength = 0; unsigned char* newB = 0; bool isNull = val_is_null(bytes); - + if (!isNull) { - + //here we can extract the values before calling our mutex to avoid potential deadlock or contention value lengthVal = val_field(bytes, id_length); value bVal = val_field(bytes, id_b); - + newLength = val_int(lengthVal); - + if (newLength > 0) { - + if (val_is_string(bVal)) { newB = (unsigned char*)val_string(bVal); } else { @@ -204,7 +206,7 @@ namespace lime { } } } - + //and now it should be save to lock mutex.Lock(); @@ -229,7 +231,7 @@ namespace lime { usingHaxeValue = false; } - + if (isNull) { length = 0; b = 0; @@ -239,7 +241,7 @@ namespace lime { length = newLength; b = newB; } - + mutex.Unlock(); } From 36cf62a089a05bc988eeb43888cfaa97142ad96a Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Sun, 28 Jun 2026 16:38:14 -0400 Subject: [PATCH 070/251] Tools: Avoid duplicate haxelib include processing in HXP wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track haxelib include files that are already expanded while parsing Project.xml, and skip re-expanding those same includes during the HXP post-load haxelib pass. This preserves normal XML behavior and direct HXP haxelib handdling, while allowing a project.hxp wrapper to merge an existing project.xml without duplicating assets from haxelib include.xml files (such as Flixel’s embedded assets) --- src/lime/tools/HXProject.hx | 32 ++++++++++++++++++++++++++++++ src/lime/tools/ProjectXMLParser.hx | 1 + 2 files changed, 33 insertions(+) diff --git a/src/lime/tools/HXProject.hx b/src/lime/tools/HXProject.hx index c87cf3dc06..f114920708 100644 --- a/src/lime/tools/HXProject.hx +++ b/src/lime/tools/HXProject.hx @@ -50,6 +50,7 @@ class HXProject extends Script public var platformType:PlatformType; public var postBuildCallbacks:Array; public var preBuildCallbacks:Array; + @:noCompletion public var processedHaxelibIncludes:Array; public var samplePaths:Array; public var sources:Array; public var splashScreens:Array; @@ -220,6 +221,7 @@ class HXProject extends Script ndlls = new Array(); postBuildCallbacks = new Array(); preBuildCallbacks = new Array(); + processedHaxelibIncludes = new Array(); sources = new Array(); samplePaths = new Array(); splashScreens = new Array(); @@ -323,6 +325,7 @@ class HXProject extends Script project.platformType = platformType; project.postBuildCallbacks = postBuildCallbacks.copy(); project.preBuildCallbacks = preBuildCallbacks.copy(); + project.processedHaxelibIncludes = processedHaxelibIncludes.copy(); project.samplePaths = samplePaths.copy(); project.sources = sources.copy(); @@ -925,6 +928,15 @@ class HXProject extends Script excludeArchitectures = ArrayTools.concatUnique(excludeArchitectures, project.excludeArchitectures); haxeflags = ArrayTools.concatUnique(haxeflags, project.haxeflags); haxelibs = ArrayTools.concatUnique(haxelibs, project.haxelibs, true, "name"); + if (processedHaxelibIncludes == null) + { + processedHaxelibIncludes = new Array(); + } + + if (project.processedHaxelibIncludes != null) + { + processedHaxelibIncludes = ArrayTools.concatUnique(processedHaxelibIncludes, project.processedHaxelibIncludes); + } icons = ArrayTools.concatUnique(icons, project.icons); javaPaths = ArrayTools.concatUnique(javaPaths, project.javaPaths, true); @@ -991,6 +1003,11 @@ class HXProject extends Script // #if lime @:noCompletion private static function processHaxelibs(project:HXProject, userDefines:Map):Void { + if (project.processedHaxelibIncludes == null) + { + project.processedHaxelibIncludes = new Array(); + } + var haxelibs = project.haxelibs.copy(); project.haxelibs = []; @@ -999,6 +1016,11 @@ class HXProject extends Script var validatePath = Haxelib.getPath(haxelib, true); project.haxelibs.push(haxelib); + if (ArrayTools.containsValue(project.processedHaxelibIncludes, getHaxelibIncludeKey(haxelib))) + { + continue; + } + var includeProject = HXProject.fromHaxelib(haxelib, userDefines); if (includeProject != null) @@ -1016,6 +1038,16 @@ class HXProject extends Script } } + @:noCompletion public static function getHaxelibIncludeKey(haxelib:Haxelib):String + { + if (haxelib.version != null && haxelib.version != "") + { + return haxelib.name + ":" + haxelib.version; + } + + return haxelib.name; + } + @:noCompletion private static function resolveClass(name:String):Class { var type = Type.resolveClass(name); diff --git a/src/lime/tools/ProjectXMLParser.hx b/src/lime/tools/ProjectXMLParser.hx index 83b5ec4ef8..3cf69bd9ef 100644 --- a/src/lime/tools/ProjectXMLParser.hx +++ b/src/lime/tools/ProjectXMLParser.hx @@ -1120,6 +1120,7 @@ class ProjectXMLParser extends HXProject } } + ArrayTools.addUnique(processedHaxelibIncludes, HXProject.getHaxelibIncludeKey(haxelib)); merge(includeProject); } From 53c8685ddd593b338824f7d5538d65a1e0cabfec Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Mon, 29 Jun 2026 08:00:20 -0400 Subject: [PATCH 071/251] Restore RAF pacing for 60fps HTML5 apps Preserve the existing HTML5 frame-rate behavior when application-level frame timing is configured. The HTML5 window backend has historically treated frame rates of 60fps or higher as unthrottled RAF pacing and the newer application-level frame timing path converted the default 60fps value into a fixed 16.66ms frame period instead, which could amplify browser RAF jitter during wheel input? --- .../_internal/backend/html5/HTML5Application.hx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index 356683065c..99279c350c 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -276,7 +276,18 @@ class HTML5Application public function configureFrameTiming(profile:FrameProfile, frameRate:Float, options:FrameOptions):Void { - framePeriod = frameRate > 0 ? (1000.0 / frameRate) : -1; + if (frameRate >= 60) + { + framePeriod = -1; + } + else if (frameRate > 0) + { + framePeriod = 1000.0 / frameRate; + } + else + { + framePeriod = 1000; + } } public function exec():Int From 81ed872a581c6389a368c8825a86d7f151bf1023 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 2 Jul 2026 12:12:24 -0400 Subject: [PATCH 072/251] Add issue reporting guidelines to CONTRIBUTING Adds an 'Issue Reporting Guidelines' section to CONTRIBUTING.md that explains how to create focused, reproducible bug reports. --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c483f354e6..ae8c283921 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,38 @@ We welcome your feedback and input in how to make Lime better! If you are interested in discussing new features, the direction the project or how to integrate some change, please open an issue so we can talk about. +## Issue Reporting Guidelines + +Please keep bug reports focused, reproducible and actionable. A good issue should describe one specific problem and include enough information for maintainers to reproduce it without guessing. + +Before opening an issue: + + 1. Search existing open and closed issues to avoid duplicates. + + 2. Test with the latest stable release and, when possible, the current development branch. + + 3. Reduce the problem to the smallest project or code sample that still reproduces it. + +Bug reports should include: + + 1. The exact Lime version, OpenFL version if applicable, Haxe version and target/runtime. + + 2. The operating system, architecture and relevant hardware or driver details. + + 3. A minimal project or code sample, including `project.xml` or `project.hxp`. + + 4. Exact steps to reproduce the problem. + + 5. The expected behavior and the actual behavior. + + 6. Any relevant logs, console output, screenshots or videos. + +Please do not combine multiple unrelated problems in one issue. Open one issue per behavior so each report can be reproduced, discussed and fixed independently. + +Performance, timing and rendering reports need especially clear reproduction material. Include a minimal project, the exact frame rate/vsync/window settings, how the result was measured and whether the behavior reproduces across targets, machines or drivers. + +Issues based only on broad observations, speculation, generated code that has not been verified, or project-specific behavior without a minimal reproduction may be closed until enough information is provided. + 1. Fork the repository 2. Make the desired change From a607c7549e917ba66696bdf921849c11ee0c9b69 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 2 Jul 2026 12:18:31 -0400 Subject: [PATCH 073/251] Add bug report issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 138 ++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + 2 files changed, 139 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..45995eb1b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,138 @@ +name: Bug report +description: Report a focused, reproducible Lime bug +title: "[Bug]: " +labels: [] +body: + - type: markdown + attributes: + value: | + Please report one specific problem per issue. Reports without enough information to reproduce may be closed until the missing details are provided. + + - type: checkboxes + id: checks + attributes: + label: Preflight Checklist + options: + - label: I searched existing open and closed issues for duplicates. + required: true + - label: I tested the latest stable Lime release or the current development branch where possible. + required: true + - label: I reduced this to the smallest project or code sample that still reproduces the issue. + required: true + - label: This issue describes one specific behavior, not several unrelated observations. + required: true + + - type: textarea + id: summary + attributes: + label: Problem Description + description: Describe the specific behavior that appears to be wrong. + validations: + required: true + + - type: textarea + id: versions + attributes: + label: Version Information + description: Include exact versions. Do not write "latest" by itself. + value: | + Lime version: + OpenFL version, if applicable: + Haxe version: + Target/runtime: + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment + description: Include relevant OS, architecture, hardware and driver details. + value: | + OS: + Architecture: + GPU/driver, if relevant: + Display refresh rate, if relevant: + validations: + required: true + + - type: textarea + id: repro + attributes: + label: Minimal Reproduction + description: Attach or link a minimal project, or paste the smallest code sample that reproduces the problem. Include project.xml or project.hxp. + placeholder: | + Link to minimal project: + + project.xml / project.hxp: + + Relevant source: + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: List exact steps needed to reproduce the issue from a clean checkout/project. + placeholder: | + 1. + 2. + 3. + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: What should happen? + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual Behavior + description: What happens instead? + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs and Output + description: Paste relevant console output, stack traces or build logs. + render: text + validations: + required: false + + - type: textarea + id: media + attributes: + label: Screenshots or Videos + description: Attach screenshots or videos only if they help demonstrate the reproduced behavior. They do not replace a minimal reproduction. + validations: + required: false + + - type: textarea + id: timing + attributes: + label: Performance, Timing or Rendering Details + description: If this is about frame pacing, timing or rendering, explain how you measured it and list frame rate, vsync, window/fullscreen and display settings. + placeholder: | + Frame rate: + Vsync setting: + Window/fullscreen mode: + Measurement method: + Reproduces on other targets/machines/drivers: + validations: + required: false + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any other focused context that may help reproduce or diagnose this issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..3ba13e0cec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false From 9778682d1223b70a1df8d29dc8dad31820bdfce5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Thu, 2 Jul 2026 13:03:45 -0400 Subject: [PATCH 074/251] Add feature request issue template --- .github/ISSUE_TEMPLATE/feature_request.yml | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000..143721ab44 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,87 @@ +name: Feature request +description: Propose a focused Lime feature or behavior change +title: "[Feature]: " +labels: [] +body: + - type: markdown + attributes: + value: | + Please use this form for focused feature proposals. If you are reporting broken behavior, use the bug report form instead. + + - type: checkboxes + id: checks + attributes: + label: Preflight Checklist + options: + - label: I searched existing open and closed issues for similar proposals. + required: true + - label: This request describes one focused feature or behavior change. + required: true + - label: This is not a bug report or a request for help debugging project-specific code. + required: true + + - type: textarea + id: problem + attributes: + label: Problem or Use Case + description: What problem would this feature solve? Who needs it, and when? + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposed Behavior + description: Describe the exact behavior, API, project setting or workflow change you are proposing. + validations: + required: true + + - type: textarea + id: targets + attributes: + label: Affected Targets or Backends + description: List the targets, runtimes or backends this proposal affects. + placeholder: | + Native SDL: + HTML5: + HashLink: + HXCPP: + Other: + validations: + required: true + + - type: textarea + id: compatibility + attributes: + label: Compatibility and Defaults + description: Explain whether this should be default behavior, opt-in behavior or a breaking change. Include any compatibility concerns. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: What existing options, workarounds or alternative designs have you considered? + validations: + required: false + + - type: textarea + id: examples + attributes: + label: Example Usage + description: Show how a project would use this feature, if applicable. + placeholder: | + project.xml / project.hxp: + + Haxe code: + validations: + required: false + + - type: textarea + id: additional + attributes: + label: Additional Context + description: Add any focused context, links or prior discussion that may help evaluate the proposal. + validations: + required: false From eb5bf13ddbe1e94ee6da67e406fd045dcd9946e5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 8 Jul 2026 01:43:46 -0400 Subject: [PATCH 075/251] Comment out tracing of defaultPath in FileDialog Comment out trace statement for defaultPath. --- src/lime/ui/FileDialog.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime/ui/FileDialog.hx b/src/lime/ui/FileDialog.hx index 31a1a349b2..709e9dc864 100644 --- a/src/lime/ui/FileDialog.hx +++ b/src/lime/ui/FileDialog.hx @@ -200,7 +200,7 @@ class FileDialog var path = null; #if (!macro && lime_cffi) - trace(defaultPath); + // trace(defaultPath); path = CFFI.stringValue(NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath)); #end From 33aedb57f48e08762061e0c0874521e64fda6877 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Sun, 12 Jul 2026 17:45:15 -0400 Subject: [PATCH 076/251] EventMacro: Use platform specific rethrow Replace generic `throw e` with platform-specific rethrow mechanisms in event dispatcher catch blocks. This ensures exceptions are properly rethrown on cpp, neko, hl, and js targets using their respective library APIs (cpp.Lib.rethrow, neko.Lib.rethrow, hl.Api.rethrow, js.Lib.rethrow). --- src/lime/_internal/macros/EventMacro.hx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lime/_internal/macros/EventMacro.hx b/src/lime/_internal/macros/EventMacro.hx index eae7aad1b2..b02ee73f43 100644 --- a/src/lime/_internal/macros/EventMacro.hx +++ b/src/lime/_internal/macros/EventMacro.hx @@ -87,6 +87,27 @@ class EventMacro args.push({name: argName, type: typeArgs[i].t.toComplexType()}); } + var rethrow = if (Context.defined("cpp")) + { + macro cpp.Lib.rethrow(e); + } + else if (Context.defined("neko")) + { + macro neko.Lib.rethrow(e); + } + else if (Context.defined("hl")) + { + macro hl.Api.rethrow(e); + } + else if (Context.defined("js")) + { + macro js.Lib.rethrow(); + } + else + { + macro throw e; + } + var dispatch = macro { var previousTimestamp = __timestamp; @@ -121,7 +142,7 @@ class EventMacro catch (e:Dynamic) { __timestamp = previousTimestamp; - throw e; + $rethrow; } __timestamp = previousTimestamp; @@ -161,7 +182,7 @@ class EventMacro catch (e:Dynamic) { __timestamp = previousTimestamp; - throw e; + $rethrow; } __timestamp = previousTimestamp; From 11afac0333394005cd79781136fe7094b9d320c5 Mon Sep 17 00:00:00 2001 From: Chris Speciale Date: Wed, 15 Jul 2026 08:22:19 -0400 Subject: [PATCH 077/251] Event: Preserve listener exception call sites Keep timestamps as the mosst recent dispatch value, removing catch/rethrow wrappers that altered call stacks and debugger behavior. Add coverage for nested dispatch and listener exceptions. --- src/lime/_internal/macros/EventMacro.hx | 112 ++++++------------------ src/lime/app/Event.hx | 4 +- tests/unit/src/app/EventTest.hx | 22 ++++- 3 files changed, 48 insertions(+), 90 deletions(-) diff --git a/src/lime/_internal/macros/EventMacro.hx b/src/lime/_internal/macros/EventMacro.hx index b02ee73f43..cca5bdd70b 100644 --- a/src/lime/_internal/macros/EventMacro.hx +++ b/src/lime/_internal/macros/EventMacro.hx @@ -87,106 +87,46 @@ class EventMacro args.push({name: argName, type: typeArgs[i].t.toComplexType()}); } - var rethrow = if (Context.defined("cpp")) - { - macro cpp.Lib.rethrow(e); - } - else if (Context.defined("neko")) - { - macro neko.Lib.rethrow(e); - } - else if (Context.defined("hl")) - { - macro hl.Api.rethrow(e); - } - else if (Context.defined("js")) - { - macro js.Lib.rethrow(); - } - else - { - macro throw e; - } - - var dispatch = macro + var dispatchListeners = macro { - var previousTimestamp = __timestamp; - __timestamp = lime.system.System.getTimer(); - canceled = false; + var listeners = __listeners; + var repeat = __repeat; + var i = 0; - try + while (i < listeners.length) { - var listeners = __listeners; - var repeat = __repeat; - var i = 0; + listeners[i]($a{argNames}); - while (i < listeners.length) + if (!repeat[i]) { - listeners[i]($a{argNames}); - - if (!repeat[i]) - { - this.remove(cast listeners[i]); - } - else - { - i++; - } + this.remove(cast listeners[i]); + } + else + { + i++; + } - if (canceled) - { - break; - } + if (canceled) + { + break; } } - catch (e:Dynamic) - { - __timestamp = previousTimestamp; - $rethrow; - } + }; - __timestamp = previousTimestamp; - } + // Keep listener exceptions on the original dispatch path without a cleanup wrapper. + var dispatch = macro + { + __timestamp = lime.system.System.getTimer(); + canceled = false; + $dispatchListeners; + }; var timestampDispatch = macro { - var previousTimestamp = __timestamp; __timestamp = timestamp; canceled = false; - - try - { - var listeners = __listeners; - var repeat = __repeat; - var i = 0; - - while (i < listeners.length) - { - listeners[i]($a{argNames}); - - if (!repeat[i]) - { - this.remove(cast listeners[i]); - } - else - { - i++; - } - - if (canceled) - { - break; - } - } - } - catch (e:Dynamic) - { - __timestamp = previousTimestamp; - $rethrow; - } - - __timestamp = previousTimestamp; - } + $dispatchListeners; + }; var i = 0; var field; diff --git a/src/lime/app/Event.hx b/src/lime/app/Event.hx index bdca9898f0..b6d648f070 100644 --- a/src/lime/app/Event.hx +++ b/src/lime/app/Event.hx @@ -31,8 +31,8 @@ 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. + The timestamp of the most recent dispatch, in milliseconds. + Before the first dispatch, this returns the current timer value. **/ public var timestamp(get, never):Int; diff --git a/tests/unit/src/app/EventTest.hx b/tests/unit/src/app/EventTest.hx index 87d7c07f0c..2cdc48c3c0 100644 --- a/tests/unit/src/app/EventTest.hx +++ b/tests/unit/src/app/EventTest.hx @@ -44,7 +44,7 @@ class EventTest extends Test Assert.equals(1234, observed); } - public function testNestedDispatchRestoresTimestamp():Void + public function testNestedDispatchUsesMostRecentTimestamp():Void { var event = new EventVoid>(); var timestamps:Array = []; @@ -58,11 +58,29 @@ class EventTest extends Test { nested = true; @:privateAccess event.__dispatchWithTimestamp(200, 2); - Assert.equals(100, event.timestamp); + Assert.equals(200, event.timestamp); } }); @:privateAccess event.__dispatchWithTimestamp(100, 1); Assert.same([100, 200], timestamps); + Assert.equals(200, event.timestamp); + } + + public function testListenerExceptionKeepsDispatchTimestamp():Void + { + var event = new EventVoid>(); + + event.add(function(_) + { + throw "listener failure"; + }); + + Assert.raises(function():Void + { + @:privateAccess event.__dispatchWithTimestamp(1234, 1); + }); + + Assert.equals(1234, event.timestamp); } } From ed28c736142fcd25ae99d21e1e47f1a918088406 Mon Sep 17 00:00:00 2001 From: "Enzo Persillet (Tutez)" Date: Sun, 19 Jul 2026 18:19:49 +0200 Subject: [PATCH 078/251] Fix XRandR dynamic library name on Linux --- project/lib/custom/sdl/include/SDL_config_linux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/lib/custom/sdl/include/SDL_config_linux.h b/project/lib/custom/sdl/include/SDL_config_linux.h index 54a9fe5b30..61e633f33b 100644 --- a/project/lib/custom/sdl/include/SDL_config_linux.h +++ b/project/lib/custom/sdl/include/SDL_config_linux.h @@ -273,7 +273,7 @@ /* #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR */ #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "libXinerama.so.1" #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "libXi.so.6" -#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "libxrandr.so.2" +#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "libXrandr.so.2" /* #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS */ /* #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE */ /* #undef SDL_VIDEO_DRIVER_X11_XCURSOR */ From 400127585c969c528e7d14fd597bc46239cd906d Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 17 Aug 2026 10:05:18 -0700 Subject: [PATCH 079/251] CommandLineTools: separate error message when the main class is not found in the root and no source path is specified (closes #2090) When no source path is specified, it is assumed that the root of the project is the source path, so it looks for the main class there. If the main class is not found in the root, it may be that the user forgot to specify a source path, or they may have forgot to create the main class. We don't really know what the user's intent was in this case, so the error message mentions both issues (main class not found, and the project.xml contains no element). --- tools/CommandLineTools.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx index 67f27f7920..9648df30e2 100644 --- a/tools/CommandLineTools.hx +++ b/tools/CommandLineTools.hx @@ -1784,11 +1784,16 @@ class CommandLineTools return null; } - if (project == null || (command != "rebuild" && project.sources.length == 0 && !FileSystem.exists(project.app.main + ".hx"))) + if (project == null) { Log.error("You must have a \"project.xml\" file or specify another valid project file when using the '" + command + "' command"); return null; } + else if (command != "rebuild" && project.sources.length == 0 && !FileSystem.exists(project.app.main + ".hx")) + { + Log.error("Main class \"" + project.app.main + "\" not found. Expected: " + Log.accentColor + FileSystem.absolutePath(project.app.main + ".hx") + Log.resetColor + "\nDid you mean to include a element in your \"project.xml\" file?"); + return null; + } if (config != null) { From ee346f67170c813bdb8b4dccbae31d146cd09a6e Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Thu, 20 Aug 2026 13:42:23 -0700 Subject: [PATCH 080/251] Font: Expose isBold and isItalic, which map to the font style flags This will be used by OpenFL to set the openfl.text.Font fontStyle property --- CHANGELOG.md | 1 + project/include/text/Font.h | 2 + project/src/ExternalInterface.cpp | 52 +++++++++++++++++++ project/src/text/Font.cpp | 14 +++++ .../_internal/backend/native/NativeCFFI.hx | 18 +++++++ src/lime/text/Font.hx | 14 +++++ 6 files changed, 101 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ddcb60e1..de59318df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Changelog - 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 `Font.isBold` and `Font.isItalic`. - 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. diff --git a/project/include/text/Font.h b/project/include/text/Font.h index 931f453a4b..d7f4731e66 100644 --- a/project/include/text/Font.h +++ b/project/include/text/Font.h @@ -59,6 +59,8 @@ namespace lime { int GetStrikethroughPosition (); int GetStrikethroughThickness (); int GetUnitsPerEM (); + bool IsBold (); + bool IsItalic (); int RenderGlyph (int index, Bytes *bytes, int offset = 0); int RenderGlyphWithFlags (int index, int loadFlags, Bytes *bytes, int offset = 0); int RenderGlyphs (value indices, Bytes *bytes); diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 2f6abcb4a8..403f5215b0 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -2556,6 +2556,54 @@ namespace lime { } + bool lime_font_is_bold (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->IsBold (); + #else + return false; + #endif + + } + + + HL_PRIM bool HL_NAME(hl_font_is_bold) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->IsBold (); + #else + return false; + #endif + + } + + + bool lime_font_is_italic (value fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + return font->IsItalic (); + #else + return false; + #endif + + } + + + HL_PRIM bool HL_NAME(hl_font_is_italic) (HL_CFFIPointer* fontHandle) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + return font->IsItalic (); + #else + return false; + #endif + + } + + value lime_font_load_bytes (value data) { #ifdef LIME_FREETYPE @@ -13369,6 +13417,8 @@ namespace lime { DEFINE_PRIME1 (lime_font_get_strikethrough_position); DEFINE_PRIME1 (lime_font_get_strikethrough_thickness); DEFINE_PRIME1 (lime_font_get_units_per_em); + DEFINE_PRIME1 (lime_font_is_bold); + DEFINE_PRIME1 (lime_font_is_italic); DEFINE_PRIME1 (lime_font_load); DEFINE_PRIME1 (lime_font_load_bytes); DEFINE_PRIME1 (lime_font_load_file); @@ -13677,6 +13727,8 @@ namespace lime { DEFINE_HL_PRIM (_I32, hl_font_get_strikethrough_position, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_font_get_strikethrough_thickness, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_font_get_units_per_em, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_font_is_bold, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_font_is_italic, _TCFFIPOINTER); // DEFINE_PRIME1 (lime_font_load); DEFINE_HL_PRIM (_TCFFIPOINTER, hl_font_load_bytes, _TBYTES); DEFINE_HL_PRIM (_TCFFIPOINTER, hl_font_load_file, _STRING); diff --git a/project/src/text/Font.cpp b/project/src/text/Font.cpp index a57be11df6..75e55d8f8d 100644 --- a/project/src/text/Font.cpp +++ b/project/src/text/Font.cpp @@ -1313,6 +1313,20 @@ namespace lime { } + bool Font::IsBold () { + + return ((FT_Face)face)->style_flags & FT_STYLE_FLAG_BOLD; + + } + + + bool Font::IsItalic () { + + return ((FT_Face)face)->style_flags & FT_STYLE_FLAG_ITALIC; + + } + + int Font::RenderGlyph(int index, Bytes *bytes, int offset) { if (FT_Load_Glyph((FT_Face)face, index, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_DEFAULT) == 0) diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 906d38d1fe..5260218253 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -162,6 +162,10 @@ class NativeCFFI @:cffi private static function lime_font_get_units_per_em(handle:Dynamic):Int; + @:cffi private static function lime_font_is_bold(handle:Dynamic):Bool; + + @:cffi private static function lime_font_is_italic(handle:Dynamic):Bool; + @:cffi private static function lime_font_load(data:Dynamic):Dynamic; @:cffi private static function lime_font_load_bytes(data:Dynamic):Dynamic; @@ -802,6 +806,8 @@ class NativeCFFI private static var lime_font_get_strikethrough_thickness = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_strikethrough_thickness", "oi", false)); private static var lime_font_get_units_per_em = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_font_get_units_per_em", "oi", false)); + private static var lime_font_is_bold = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_font_is_bold", "ob", false)); + private static var lime_font_is_italic = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_font_is_italic", "ob", false)); private static var lime_font_load = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_load", "oo", false)); private static var lime_font_load_bytes = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_load_bytes", "oo", false)); private static var lime_font_load_file = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_load_file", "oo", false)); @@ -1276,6 +1282,8 @@ class NativeCFFI private static var lime_font_get_strikethrough_position = CFFI.load("lime", "lime_font_get_strikethrough_position", 1); private static var lime_font_get_strikethrough_thickness = CFFI.load("lime", "lime_font_get_strikethrough_thickness", 1); private static var lime_font_get_units_per_em = CFFI.load("lime", "lime_font_get_units_per_em", 1); + private static var lime_font_is_bold = CFFI.load("lime", "lime_font_is_bold", 1); + private static var lime_font_is_italic = CFFI.load("lime", "lime_font_is_italic", 1); private static var lime_font_load = CFFI.load("lime", "lime_font_load", 1); private static var lime_font_load_bytes = CFFI.load("lime", "lime_font_load_bytes", 1); private static var lime_font_load_file = CFFI.load("lime", "lime_font_load_file", 1); @@ -1742,6 +1750,16 @@ class NativeCFFI return 0; } + @:hlNative("lime", "hl_font_is_bold") private static function lime_font_is_bold(handle:CFFIPointer):Bool + { + return false; + } + + @:hlNative("lime", "hl_font_is_italic") private static function lime_font_is_italic(handle:CFFIPointer):Bool + { + return false; + } + // @:hlNative("lime", "") private static function lime_font_load (data:Dynamic):Dynamic { return null; } @:hlNative("lime", "hl_font_load_bytes") private static function lime_font_load_bytes(data:Bytes):CFFIPointer { diff --git a/src/lime/text/Font.hx b/src/lime/text/Font.hx index 090499423f..071337e4fc 100644 --- a/src/lime/text/Font.hx +++ b/src/lime/text/Font.hx @@ -86,6 +86,16 @@ class Font */ public var unitsPerEM:Int; + /** + * Whether the font style is bold. + */ + public var isBold:Bool; + + /** + * Whether the font style is italic. + */ + public var isItalic:Bool; + @:noCompletion private var __fontID:String; @:noCompletion private var __fontPath:String; #if lime_cffi @@ -592,6 +602,8 @@ class Font underlinePosition = other.underlinePosition; underlineThickness = other.underlineThickness; unitsPerEM = other.unitsPerEM; + isBold = other.isBold; + isItalic = other.isItalic; __fontID = other.__fontID; __fontPath = other.__fontPath; @@ -649,6 +661,8 @@ class Font strikethroughPosition = NativeCFFI.lime_font_get_strikethrough_position(src); strikethroughThickness = NativeCFFI.lime_font_get_strikethrough_thickness(src); unitsPerEM = NativeCFFI.lime_font_get_units_per_em(src); + isBold = NativeCFFI.lime_font_is_bold(src); + isItalic = NativeCFFI.lime_font_is_italic(src); } #end From 4f03693d3436034c7fa1e80a457e476e4aa3fd26 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 21 Aug 2026 15:31:46 -0700 Subject: [PATCH 081/251] HTML5Application: if frameRate == 0, update on every requestAnimationFrame Followup to commit 53c8685ddd593b338824f7d5538d65a1e0cabfec --- src/lime/_internal/backend/html5/HTML5Application.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index 99279c350c..b4bac99707 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -276,7 +276,7 @@ class HTML5Application public function configureFrameTiming(profile:FrameProfile, frameRate:Float, options:FrameOptions):Void { - if (frameRate >= 60) + if (frameRate == 0 || frameRate >= 60) { framePeriod = -1; } From 41c428e4b5969ea96ab57730a8a8518694f58dae Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 25 Aug 2026 19:33:43 +0100 Subject: [PATCH 082/251] Fix sdl_sound missing definitions in macro context Without these guards, there are errors about the NativeCFFI functions not being defined: ``` .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:354: characters 15-42 : Class has no field lime_sdl_sound_stream_clear .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:391: characters 32-64 : Class has no field lime_sdl_sound_stream_from_bytes .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:395: characters 32-63 : Class has no field lime_sdl_sound_stream_from_file .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:457: characters 36-64 : Class has no field lime_sdl_sound_stream_rewind .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:467: characters 35-61 : Class has no field lime_sdl_sound_stream_seek .../lime/src/lime/_internal/backend/native/NativeAudioSource.hx:735: characters 25-51 : Class has no field lime_sdl_sound_stream_read .../lime/src/lime/system/Clipboard.hx:27: characters 31-54 : Unknown<0> cannot be constructed ``` --- src/lime/_internal/backend/native/NativeAudioSource.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lime/_internal/backend/native/NativeAudioSource.hx b/src/lime/_internal/backend/native/NativeAudioSource.hx index 51c587d73b..00e9f148ea 100644 --- a/src/lime/_internal/backend/native/NativeAudioSource.hx +++ b/src/lime/_internal/backend/native/NativeAudioSource.hx @@ -348,7 +348,7 @@ class NativeAudioSource private function clearSDLSoundStream():Void { - #if lime_sdl_sound + #if (lime_sdl_sound && !macro) if (sdlSoundStream != null) { NativeCFFI.lime_sdl_sound_stream_clear(sdlSoundStream); @@ -383,7 +383,7 @@ class NativeAudioSource private function openSDLSoundStream():Bool { - #if lime_sdl_sound + #if (lime_sdl_sound && !macro) clearSDLSoundStream(); if (parent.buffer.__srcSDLSoundBytes != null) @@ -441,7 +441,7 @@ class NativeAudioSource private function resetSDLSoundStream(time:Int):Bool { - #if lime_sdl_sound + #if (lime_sdl_sound && !macro) if (time < 0) { time = 0; @@ -721,7 +721,7 @@ class NativeAudioSource private function readSDLSoundBuffer(length:Int):Int { - #if lime_sdl_sound + #if (lime_sdl_sound && !macro) if (sdlSoundStream == null || length <= 0 || streamByteRate <= 0) { return 0; From 61592fc9c39c281fbfb768447de372aef24e1080 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 14 Jul 2026 13:49:36 +0100 Subject: [PATCH 083/251] [tools] Support wine for running windows programs --- tools/platforms/WindowsPlatform.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx index fd59564832..06aaed1bab 100644 --- a/tools/platforms/WindowsPlatform.hx +++ b/tools/platforms/WindowsPlatform.hx @@ -974,6 +974,11 @@ class WindowsPlatform extends PlatformTarget arguments = arguments.concat(["-livereload"]); System.runCommand(applicationDirectory, Path.withoutDirectory(executablePath), arguments); } + else + { + arguments = [Path.withoutDirectory(executablePath)].concat(arguments.concat(["-livereload"])); + System.runCommand(applicationDirectory, "wine", arguments); + } } public override function update():Void From 47161e47f4a325687346caceb75399e2f526b5b1 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 28 Aug 2026 09:19:06 -0700 Subject: [PATCH 084/251] PlatformTarget: add new `-noupdate` flag for `lime build` and `lime test` commands to optionally skip update phase --- src/lime/tools/PlatformTarget.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lime/tools/PlatformTarget.hx b/src/lime/tools/PlatformTarget.hx index b752ac16f9..0926d67040 100644 --- a/src/lime/tools/PlatformTarget.hx +++ b/src/lime/tools/PlatformTarget.hx @@ -97,7 +97,8 @@ class PlatformTarget rebuild(); } - if (command == "update" || command == "build" || command == "test") + if (command == "update" + || ((command == "build" || command == "test") && !targetFlags.exists("noupdate"))) { logCommand("update"); From e7df283d53880c947877e420d7f464ceebb20b0a Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Sat, 29 Aug 2026 12:05:53 -0700 Subject: [PATCH 085/251] CommandLineTools: add -noupdate flag to help for build and test commands Followup to commit 47161e47f4a325687346caceb75399e2f526b5b1 --- tools/CommandLineTools.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx index 9648df30e2..b71d102921 100644 --- a/tools/CommandLineTools.hx +++ b/tools/CommandLineTools.hx @@ -990,6 +990,11 @@ class CommandLineTools Log.println(" \x1b[1m-clean\x1b[0m -- Add a \"clean\" action before running the current command"); } + if (command == "build" || command == "test") + { + Log.println(" \x1b[1m-noupdate\x1b[0m -- Disable the \"update\" action before running the current command"); + } + Log.println(" \x1b[1m-nocolor\x1b[0m -- Disable ANSI format codes in output"); if (command == "run" || command == "test") From 838b9254cdbe30718dcf30d1ede5f306499b9945 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 4 Sep 2026 14:42:58 -0700 Subject: [PATCH 086/251] Window: add onDeviceDisplayScaleChange event, used by native and html5 targets Dispatched on html5 when window.devicePixelRatio changes (checked with a matchMedia() change listener). Dispatched on native when SDL2 dispatches a window resize, which can happen when the width and height have not changed, but the display scale has changed. SDL2 doesn't have a separate event for display scale changes, but will notify the window of a resize. SDL3 will have a dedicated event for display scale changes, though. Includes the define lime_disable_window_scale_change to restore the previous behavior temporarily until apps or libraries can be updated to fully support dynamic display scale changes. The latest OpenFL develop should handle it pretty gracefully, even without listening for the event, but may have some edge cases where it doesn't detect scale changes. --- .../_internal/backend/html5/HTML5Window.hx | 36 +++++++++++++++++-- .../backend/native/NativeApplication.hx | 11 ++++++ src/lime/ui/Window.hx | 1 + 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index e36aa53e34..8bffd2fcbd 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -59,6 +59,7 @@ class HTML5Window private var cacheElementHeight:Float; private var cacheElementWidth:Float; + private var cacheElementScale:Float; private var cacheMouseX:Float; private var cacheMouseY:Float; private var cursor:MouseCursor; @@ -70,6 +71,9 @@ class HTML5Window private var requestedFullscreen:Bool; private var resizeElement:Bool; private var scale = 1.0; + #if !lime_disable_window_scale_change + private var devicePixelRatioMediaQuery:js.html.MediaQueryList; + #end private var setHeight:Int; private var setWidth:Int; private var textInputEnabled:Bool; @@ -112,6 +116,10 @@ class HTML5Window parent.__scale = scale; + #if !lime_disable_window_scale_change + watchDevicePixelRatio(); + #end + setWidth = Reflect.hasField(attributes, "width") ? attributes.width : 0; setHeight = Reflect.hasField(attributes, "height") ? attributes.height : 0; parent.__width = setWidth; @@ -171,6 +179,7 @@ class HTML5Window cacheElementWidth = parent.__width; cacheElementHeight = parent.__height; + cacheElementScale = scale; resizeElement = true; } @@ -1350,6 +1359,27 @@ class HTML5Window return value; } + #if !lime_disable_window_scale_change + private function watchDevicePixelRatio():Void + { + scale = Browser.window.devicePixelRatio; + if (parent.__scale != scale) + { + parent.__scale = scale; + parent.onDisplayScaleChange.dispatch(); + updateSize(); + } + if (devicePixelRatioMediaQuery != null) + { + devicePixelRatioMediaQuery.removeEventListener("change", watchDevicePixelRatio); + devicePixelRatioMediaQuery = null; + } + var mediaQueryString = '(resolution: ${scale}dppx)'; + devicePixelRatioMediaQuery = Browser.window.matchMedia(mediaQueryString); + devicePixelRatioMediaQuery.addEventListener("change", watchDevicePixelRatio); + } + #end + private function updateSize():Void { if (!parent.__resizable) return; @@ -1368,10 +1398,12 @@ class HTML5Window elementHeight = Browser.window.innerHeight; } - if (elementWidth != cacheElementWidth || elementHeight != cacheElementHeight) + var scaleChanged = scale != cacheElementScale; + if (elementWidth != cacheElementWidth || elementHeight != cacheElementHeight || scaleChanged) { cacheElementWidth = elementWidth; cacheElementHeight = elementHeight; + cacheElementScale = scale; var stretch = resizeElement || (setWidth == 0 && setHeight == 0); @@ -1379,7 +1411,7 @@ class HTML5Window { if (stretch) { - if (parent.__width != elementWidth || parent.__height != elementHeight) + if (parent.__width != elementWidth || parent.__height != elementHeight || scaleChanged) { parent.__width = Std.int(elementWidth); parent.__height = Std.int(elementHeight); diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index ad45bbaba0..b17d2b34fa 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -644,6 +644,17 @@ class NativeApplication window.onMove.dispatch(windowEventInfo.x, windowEventInfo.y); case WINDOW_RESIZE: + #if !lime_disable_window_scale_change + #if (lime_cffi && !macro) + // SDL2 reports scale changes as window resizes + var newScale = NativeCFFI.lime_window_get_scale(window.__backend.handle); + if (window.__scale != newScale) + { + window.__scale = newScale; + window.onDisplayScaleChange.dispatch(); + } + #end + #end window.__width = windowEventInfo.width; window.__height = windowEventInfo.height; window.onResize.dispatch(windowEventInfo.width, windowEventInfo.height); diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index eb364c4bcd..ffae6b7b40 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -141,6 +141,7 @@ class Window public var onShow(default, null) = new EventVoid>(); public var onTextEdit(default, null) = new EventInt->Int->Void>(); public var onTextInput(default, null) = new EventVoid>(); + public var onDisplayScaleChange(default, null) = new EventVoid>(); public var opacity(get, set):Float; public var parameters:Dynamic; public var resizable(get, set):Bool; From 333c8c4fd2bef93beebb98f787bbda5f6106205d Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 4 Sep 2026 17:09:06 -0700 Subject: [PATCH 087/251] HTML5Window: Haxe 3 compatibility --- src/lime/_internal/backend/html5/HTML5Window.hx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index 8bffd2fcbd..ff168f9da6 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -1371,12 +1371,20 @@ class HTML5Window } if (devicePixelRatioMediaQuery != null) { + #if haxe4 devicePixelRatioMediaQuery.removeEventListener("change", watchDevicePixelRatio); + #else + devicePixelRatioMediaQuery.removeListener(watchDevicePixelRatio); + #end devicePixelRatioMediaQuery = null; } var mediaQueryString = '(resolution: ${scale}dppx)'; devicePixelRatioMediaQuery = Browser.window.matchMedia(mediaQueryString); + #if haxe4 devicePixelRatioMediaQuery.addEventListener("change", watchDevicePixelRatio); + #else + devicePixelRatioMediaQuery.addListener(watchDevicePixelRatio); + #end } #end From 6c74f4de1438a437386019fab6c5015687ea830c Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 4 Sep 2026 18:23:14 -0700 Subject: [PATCH 088/251] HTML5Window: more Haxe 3 compat --- src/lime/_internal/backend/html5/HTML5Window.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index ff168f9da6..6a35b2f796 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -1360,7 +1360,7 @@ class HTML5Window } #if !lime_disable_window_scale_change - private function watchDevicePixelRatio():Void + private function watchDevicePixelRatio(?e:Dynamic):Void { scale = Browser.window.devicePixelRatio; if (parent.__scale != scale) From 25da0ea1c729a39ad862a70d1ac11a9660ee67c6 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 14 Sep 2026 16:13:13 -0700 Subject: [PATCH 089/251] actions: macOS Intel has a separate job from macOS ARM64 now because changes to Homebrew --- .github/workflows/main.yml | 94 ++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3ea16a4a54..7e8e29d5af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -233,6 +233,73 @@ jobs: macos: runs-on: macos-14 + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - uses: krdlab/setup-haxe@v2 + with: + haxe-version: 4.3.7 + + - 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 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 (macOS) + run: | + lime rebuild macos -clean -release -arm64 -nocolor -verbose -nocffi + + - uses: actions/upload-artifact@v7 + with: + name: MacArm64-NDLL + path: | + ndll/MacArm64/ + !**/.gitignore + if-no-files-found: error + + - name: Run unit tests + working-directory: tests/unit + run: | + lime test neko -release -verbose -nocolor + lime test mac -arm64 -release -verbose -nocolor + + - name: Install samples + run: | + haxelib git lime-samples https://github.com/openfl/lime-samples --quiet + + # - name: Build HelloWorld sample + # run: | + # lime create HelloWorld -verbose -nocolor + # lime build HelloWorld macos -release -verbose -nocolor + + - name: Build SimpleImage sample + run: | + lime create SimpleImage -verbose -nocolor + lime build SimpleImage macos -arm64 -release -verbose -nocolor + + - name: Build SimpleAudio sample + run: | + lime create SimpleAudio -verbose -nocolor + lime build SimpleAudio macos -arm64 -release -verbose -nocolor + + macos-intel: + runs-on: macos-15-intel steps: - uses: actions/checkout@v6 @@ -251,10 +318,6 @@ jobs: run: | set -euxo pipefail - if [ ! -x /usr/local/bin/brew ]; then - NONINTERACTIVE=1 arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - fi - rm -f /usr/local/bin/2to3* rm -f /usr/local/bin/idle3* rm -f /usr/local/bin/pydoc3* @@ -262,7 +325,7 @@ jobs: rm -f /usr/local/bin/pip3* for attempt in 1 2 3; do - if arch -x86_64 /usr/local/bin/brew update && arch -x86_64 /usr/local/bin/brew install jpeg-turbo libpng libuv libvorbis; then + if /usr/local/bin/brew update && /usr/local/bin/brew install jpeg-turbo libpng libuv libvorbis; then break fi if [ "$attempt" -eq 3 ]; then @@ -287,8 +350,7 @@ jobs: - name: Rebuild Lime (macOS) run: | - lime rebuild macos -clean -release -64 -nocolor -verbose -nocffi - lime rebuild macos -clean -release -arm64 -nocolor -verbose -nocffi + lime rebuild macos -clean -release -x86_64 -nocolor -verbose -nocffi - name: Rebuild Lime (HashLink macOS) run: | @@ -302,14 +364,6 @@ jobs: !**/.gitignore if-no-files-found: error - - uses: actions/upload-artifact@v7 - with: - name: MacArm64-NDLL - path: | - ndll/MacArm64/ - !**/.gitignore - if-no-files-found: error - - uses: actions/upload-artifact@v7 with: name: Mac64-Hashlink @@ -322,7 +376,7 @@ jobs: run: | lime test neko -release -verbose -nocolor lime test hl -release -verbose -nocolor - lime test mac -release -verbose -nocolor + lime test mac -x86_64 -release -verbose -nocolor - name: Install samples run: | @@ -336,12 +390,12 @@ jobs: - name: Build SimpleImage sample run: | lime create SimpleImage -verbose -nocolor - lime build SimpleImage macos -release -verbose -nocolor + lime build SimpleImage macos -x86_64 -release -verbose -nocolor - name: Build SimpleAudio sample run: | lime create SimpleAudio -verbose -nocolor - lime build SimpleAudio macos -release -verbose -nocolor + lime build SimpleAudio macos -x86_64 -release -verbose -nocolor windows: runs-on: windows-latest @@ -604,7 +658,7 @@ jobs: lime build SimpleAudio ios -release -nosign -verbose -nocolor -eval package-haxelib: - needs: [linux, vulkan-smoke, macos, windows, android, ios] + needs: [linux, vulkan-smoke, macos, macos-intel, windows, android, ios] runs-on: ubuntu-22.04 steps: @@ -1064,7 +1118,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, vulkan-smoke, macos, neko-samples, windows] + needs: [package-haxelib, docs, android, flash-samples, air-samples, hashlink-samples, hashlinkc-samples, html5-samples, ios, linux, vulkan-smoke, macos, macos-intel, neko-samples, windows] if: ${{ github.repository == 'openfl/lime' && github.event_name != 'pull_request' }} steps: - name: Notify Discord From d8c3e0ae6908e9ace9f5e1dd1adc2f587a013616 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 15 Sep 2026 09:41:41 -0700 Subject: [PATCH 090/251] WebAssemblyPlatform: switch from emcc to em++ because newer Emscripten doesn't like C++ with emcc --- tools/platforms/WebAssemblyPlatform.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/platforms/WebAssemblyPlatform.hx b/tools/platforms/WebAssemblyPlatform.hx index 47e30643bc..9343bd4dea 100644 --- a/tools/platforms/WebAssemblyPlatform.hx +++ b/tools/platforms/WebAssemblyPlatform.hx @@ -147,7 +147,7 @@ class WebAssemblyPlatform extends PlatformTarget project.path(sdkPath); - System.runCommand("", "emcc", [ + System.runCommand("", "em++", [ "-c", "-fwasm-exceptions", targetDirectory + "/obj/Main.cpp", @@ -289,7 +289,7 @@ class WebAssemblyPlatform extends PlatformTarget // args.push ("../bin/index.html"); - System.runCommand(targetDirectory + "/obj", "emcc", args, true, false, true); + System.runCommand(targetDirectory + "/obj", "em++", args, true, false, true); if (FileSystem.exists(outputFile)) { From dc53043274a51d13e34998662cd243cfcb2e4e58 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 15 Sep 2026 09:43:40 -0700 Subject: [PATCH 091/251] WebAssemblyPlatform: add --profiling-funcs to fix failed to find stack pointer error --- tools/platforms/WebAssemblyPlatform.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/platforms/WebAssemblyPlatform.hx b/tools/platforms/WebAssemblyPlatform.hx index 9343bd4dea..c40a2aa99b 100644 --- a/tools/platforms/WebAssemblyPlatform.hx +++ b/tools/platforms/WebAssemblyPlatform.hx @@ -215,6 +215,8 @@ class WebAssemblyPlatform extends PlatformTarget // https://github.com/HaxeFoundation/hxcpp/blob/767fe94d19a041147c4f65dea02c89cb206a0758/toolchain/emscripten-toolchain.xml#L29-L33 args.push("-s"); args.push("BINARYEN_EXTRA_PASSES='--spill-pointers'"); + // https://github.com/HaxeFoundation/hxcpp/commit/d7781f795158a4b6043138b61507ab99fe1ff2d7 + args.push("--profiling-funcs"); args.push("-fwasm-exceptions"); From b94ac06bc8235b76c13e4bd38d39e330b309beee Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 15 Sep 2026 10:10:29 -0700 Subject: [PATCH 092/251] actions: add webassembly --- .github/workflows/main.yml | 65 +++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e8e29d5af..fb9d84bb8a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -508,6 +508,68 @@ jobs: !**/.gitignore if-no-files-found: error + webassembly: + runs-on: ubuntu-22.04 + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - name: Install Emscripten NDK + uses: emscripten-core/setup-emsdk@v16 + + - 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.168.zip --location https://github.com/HaxeFoundation/hxcpp/releases/download/v4.3.168/hxcpp-4.3.168.zip + haxelib install ../hxcpp-4.3.168.zip --quiet + haxelib install format --quiet + haxelib install hxp --quiet + + - name: Prepare Lime + run: | + haxelib dev lime ${{ github.workspace }} + haxelib run lime setup -alias -y -nocffi -eval + + - name: Configure Emscripten support + run: | + lime config EMSCRIPTEN_SDK $EMSDK/upstream/emscripten -eval + lime config -eval + + - name: Rebuild Lime (WebAssembly) + run: | + lime rebuild webassembly -release -nocolor -verbose -nocffi -eval + + - uses: actions/upload-artifact@v7 + with: + name: Emscripten-NDLL + path: | + ndll/Emscripten/ + !**/.gitignore + if-no-files-found: error + + - name: Install samples + run: | + haxelib git lime-samples https://github.com/openfl/lime-samples --quiet + + - name: Build SimpleImage sample + run: | + lime create SimpleImage -verbose -nocolor -eval + lime build SimpleImage webassembly -release -verbose -nocolor -eval + + - name: Build SimpleAudio sample + run: | + lime create SimpleAudio -verbose -nocolor -eval + lime build SimpleAudio webassembly -release -verbose -nocolor -eval + android: runs-on: ubuntu-22.04 strategy: @@ -598,6 +660,7 @@ jobs: working-directory: tests/vulkan-smoke run: | lime build android -release -verbose -nocolor -eval + ios: runs-on: macos-14 steps: @@ -1118,7 +1181,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, vulkan-smoke, macos, macos-intel, neko-samples, windows] + needs: [package-haxelib, docs, android, flash-samples, air-samples, hashlink-samples, hashlinkc-samples, html5-samples, ios, linux, vulkan-smoke, macos, macos-intel, neko-samples, webassembly, windows] if: ${{ github.repository == 'openfl/lime' && github.event_name != 'pull_request' }} steps: - name: Notify Discord From e8f636af553f048f7b2c6a3321328592a91c4265 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 15 Sep 2026 10:57:23 -0700 Subject: [PATCH 093/251] actions: remove unnecessary dependency of package-haxelib, and add missing dependency of notify --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fb9d84bb8a..a6a96f25dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -721,7 +721,7 @@ jobs: lime build SimpleAudio ios -release -nosign -verbose -nocolor -eval package-haxelib: - needs: [linux, vulkan-smoke, macos, macos-intel, windows, android, ios] + needs: [linux, macos, macos-intel, windows, android, ios] runs-on: ubuntu-22.04 steps: @@ -1181,7 +1181,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, vulkan-smoke, macos, macos-intel, neko-samples, webassembly, windows] + needs: [package-haxelib, docs, android, flash-samples, air-samples, hashlink-samples, hashlinkc-samples, html5-samples, ios, linux, linux-arm64, vulkan-smoke, macos, macos-intel, neko-samples, webassembly, windows] if: ${{ github.repository == 'openfl/lime' && github.event_name != 'pull_request' }} steps: - name: Notify Discord From 9fb6b2bae2ab41a5c2f4ec50ac1d3df347948c86 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 22 Sep 2026 13:27:53 -0700 Subject: [PATCH 094/251] BuildHashlink.xml: configure compiler paths for ARM64 macOS Lime tools still forces x86_64 for HashLink, but this is a step toward supporting it. --- project/BuildHashlink.xml | 68 ++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/project/BuildHashlink.xml b/project/BuildHashlink.xml index 7123640ee1..0efa2fbfab 100644 --- a/project/BuildHashlink.xml +++ b/project/BuildHashlink.xml @@ -1,5 +1,7 @@ - +
+ +
@@ -114,7 +116,14 @@ - +
+
+ +
+
+ +
+
@@ -127,10 +136,21 @@ - - - - +
+
+ + + + +
+
+ + + + +
+
+ @@ -257,7 +277,14 @@
- +
+
+ +
+
+ +
+
@@ -363,10 +390,20 @@ - - - - +
+
+ + + + +
+
+ + + + +
+
@@ -408,7 +445,14 @@ - +
+
+ +
+
+ +
+
From 69e9cbca43588191faa38b1dd9ce0c0d204ab90b Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 22 Sep 2026 13:49:48 -0700 Subject: [PATCH 095/251] MacPlatform: change how HashLink/C macOS applications are compiled to support new Xcode in macOS 27 Golden Gate. Previously, we appended `arch -x86_64` to the compiler command to force it to run in Rosetta. However, the newer compiler seems to always default to ARM64 now, even when running through Rosetta. Instead, pass `-arch x86_64` as a compiler option to the C++ compiler, which works whether using Rosetta or not Eventually, we'll want to support ARM64 HashLink apps, and whe that's posisble, we can use `-arch arm64`. --- tools/platforms/MacPlatform.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/platforms/MacPlatform.hx b/tools/platforms/MacPlatform.hx index c883bbf68b..d2c47ed3a2 100644 --- a/tools/platforms/MacPlatform.hx +++ b/tools/platforms/MacPlatform.hx @@ -226,14 +226,14 @@ class MacPlatform extends PlatformTarget var compiler = project.targetFlags.exists("clang") ? "clang" : "gcc"; // the libraries were compiled as x86_64, so if the build is // happening on ARM64 instead, we need to ensure that the - // same architecture is used for the executable, so we wrap our - // compiler command with the `arch -x86_64` command. + // same architecture is used for the executable, so we specify + // the `-arch x86_64` option in the compiler command. // if we ever support ARM or Universal binaries, this will // need to be handled differently. var command = [ - "arch", - "-x86_64", compiler, + "-arch", + "x86_64", "-O3", "-o", executablePath, From 6e8bf81e32c3e4125ace8d591300f2c4b101873a Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 22 Sep 2026 13:53:15 -0700 Subject: [PATCH 096/251] HashlinkHelper: add new option that allows copying ARM64 binaries, defaults to false --- src/lime/tools/HashlinkHelper.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lime/tools/HashlinkHelper.hx b/src/lime/tools/HashlinkHelper.hx index 879f180bcc..b011dc20c7 100644 --- a/src/lime/tools/HashlinkHelper.hx +++ b/src/lime/tools/HashlinkHelper.hx @@ -52,7 +52,7 @@ class HashlinkHelper } } - public static function copyHashlink(project:HXProject, targetDirectory:String, applicationDirectory:String, executablePath:String, ?is64 = true) + public static function copyHashlink(project:HXProject, targetDirectory:String, applicationDirectory:String, executablePath:String, ?is64 = true, ?isArm = false) { var platform = project.target; var bindir = switch project.target @@ -65,6 +65,10 @@ class HashlinkHelper Sys.exit(1); ""; }; + if (isArm) + { + bindir += "Arm"; + } if (is64) { bindir += "64"; From b6a8c696c91a12f7616f3def1648a05d47853c75 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Tue, 22 Sep 2026 14:06:31 -0700 Subject: [PATCH 097/251] MacPlatform: if -arm64 flag is passed when target is hl or hlc, compile Apple Silicon binaries (references #2103) Until now, HashLink was Intel only. Even with this change, we still default to Intel for HashLink on Apple Silicon because HashLink doesn't fully support ARM64 yet. They're working on getting JIT working on ARM64 still. However, this will make it possible for Lime users to start testing, even if things are currently incomplete. Running `lime rebuild hl -arm64` on macOS will build the hl executable and .hdlls for Apple Silicon and place them in the appropriate MacArm64 directories. I observed that `lime test hl -arm64` crashes with a segmentation fault. However, `lime test hlc -arm64` runs successfully. --- tools/platforms/MacPlatform.hx | 47 ++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/tools/platforms/MacPlatform.hx b/tools/platforms/MacPlatform.hx index d2c47ed3a2..f31d206983 100644 --- a/tools/platforms/MacPlatform.hx +++ b/tools/platforms/MacPlatform.hx @@ -219,21 +219,21 @@ class MacPlatform extends PlatformTarget // ensure that the shell script is replaced by the template executable System.deleteFile(executablePath); - HashlinkHelper.copyHashlink(project, targetDirectory, executableDirectory, executablePath, true); + + // hashlink doesn't fully support arm64 yet, so even on + // arm64 machines, we're still defaulting to x86_64. + var isArm64 = targetFlags.exists("arm64"); + + HashlinkHelper.copyHashlink(project, targetDirectory, executableDirectory, executablePath, true, isArm64); if (project.targetFlags.exists("hlc")) { - var compiler = project.targetFlags.exists("clang") ? "clang" : "gcc"; - // the libraries were compiled as x86_64, so if the build is - // happening on ARM64 instead, we need to ensure that the - // same architecture is used for the executable, so we specify - // the `-arch x86_64` option in the compiler command. - // if we ever support ARM or Universal binaries, this will - // need to be handled differently. + var compiler = targetFlags.exists("clang") ? "clang" : "gcc"; + var arch = isArm64 ? "arm64" : "x86_64"; var command = [ compiler, "-arch", - "x86_64", + arch, "-O3", "-o", executablePath, @@ -459,8 +459,14 @@ class MacPlatform extends PlatformTarget case X64: if (targetFlags.exists("hl")) { - // TODO: Support single binary - commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_M64", "-Dhashlink"]); + if (targetFlags.exists("arm64")) + { + commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_ARM64", "-Dhashlink"]); + } + else + { + commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_M64", "-Dhashlink"]); + } } else if (targetFlags.exists("arm64")) { @@ -479,8 +485,16 @@ class MacPlatform extends PlatformTarget case ARM64: if (targetFlags.exists("hl")) { - // hashlink doesn't support arm64 macs yet - commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_ARCH=x86_64", "-Dhashlink"]); + // hashlink doesn't fully support arm64 yet, so even on + // arm64 machines, we're still defaulting to x86_64. + if (targetFlags.exists("arm64")) + { + commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_ARM64", "-Dhashlink"]); + } + else + { + commands.push(["-Dmac", "-DHXCPP_CLANG", "-DHXCPP_ARCH=x86_64", "-Dhashlink"]); + } } else if (targetFlags.exists("64") || targetFlags.exists("x86_64")) { @@ -607,7 +621,12 @@ class MacPlatform extends PlatformTarget { if (targetFlags.exists("hl")) { - // hashlink doesn't support arm64 macs yet + // hashlink doesn't fully support arm64 yet, so even on + // arm64 machines, we're still defaulting to x86_64. + if (targetFlags.exists("arm64")) + { + return "Arm64"; + } return "64"; } return targetArchitecture == X64 ? "64" : targetArchitecture == ARM64 ? "Arm64" : ""; From be864166b9b52647750268f085b75d94bda75fc7 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 24 Aug 2026 15:50:57 -0700 Subject: [PATCH 098/251] Stem darkening: Optionally enable a feature to increase readabilty and contrast of text --- project/include/text/Font.h | 2 + project/src/ExternalInterface.cpp | 69 +++++++++++++++++++ project/src/text/Font.cpp | 25 +++++++ .../_internal/backend/native/NativeCFFI.hx | 12 ++++ src/lime/text/Font.hx | 39 +++++++++++ 5 files changed, 147 insertions(+) diff --git a/project/include/text/Font.h b/project/include/text/Font.h index d7f4731e66..1c39f2ef01 100644 --- a/project/include/text/Font.h +++ b/project/include/text/Font.h @@ -65,6 +65,8 @@ namespace lime { int RenderGlyphWithFlags (int index, int loadFlags, Bytes *bytes, int offset = 0); int RenderGlyphs (value indices, Bytes *bytes); void SetSize (size_t size, size_t dpi); + void SetStemDarkening (bool enable); + void SetStemDarkeningParameters (int params[]); void* library; void* face; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 403f5215b0..c55c2d83c4 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -2899,6 +2899,71 @@ namespace lime { } + void lime_font_set_stem_darkening (value fontHandle, bool enable) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)val_data (fontHandle); + font->SetStemDarkening (enable); + #endif + + } + + + HL_PRIM void HL_NAME(hl_font_set_stem_darkening) (HL_CFFIPointer* fontHandle, bool enable) { + + #ifdef LIME_FREETYPE + Font *font = (Font*)fontHandle->ptr; + font->SetStemDarkening (enable); + #endif + + } + + + void lime_font_set_stem_darkening_parameters (value fontHandle, value params) { + + #ifdef LIME_FREETYPE + int length = val_array_size (params); + if (length != 8) + { + return; + } + + int darkeningParams[8] = { + val_int (val_array_i (params, 0)), + val_int (val_array_i (params, 1)), + val_int (val_array_i (params, 2)), + val_int (val_array_i (params, 3)), + val_int (val_array_i (params, 4)), + val_int (val_array_i (params, 5)), + val_int (val_array_i (params, 6)), + val_int (val_array_i (params, 7)) + }; + + Font *font = (Font*)val_data (fontHandle); + font->SetStemDarkeningParameters(darkeningParams); + #endif + + } + + + HL_PRIM void HL_NAME(hl_font_set_stem_darkening_parameters) (HL_CFFIPointer* fontHandle, hl_varray* params) { + + #ifdef LIME_FREETYPE + int length = params->size; + if (length != 8) + { + return; + } + + int* paramValues = hl_aptr (params, int); + + Font *font = (Font*)fontHandle->ptr; + font->SetStemDarkeningParameters(paramValues); + #endif + + } + + void lime_gamepad_add_mappings (value mappings) { int length = val_array_size (mappings); @@ -13428,6 +13493,8 @@ namespace lime { DEFINE_PRIME4 (lime_font_render_glyph_with_flags); DEFINE_PRIME3 (lime_font_render_glyphs); DEFINE_PRIME3v (lime_font_set_size); + DEFINE_PRIME2v (lime_font_set_stem_darkening); + DEFINE_PRIME2v (lime_font_set_stem_darkening_parameters); DEFINE_PRIME1v (lime_gamepad_add_mappings); DEFINE_PRIME2v (lime_gamepad_event_manager_register); DEFINE_PRIME1 (lime_gamepad_get_device_guid); @@ -13738,6 +13805,8 @@ namespace lime { DEFINE_HL_PRIM (_TBYTES, hl_font_render_glyph_with_flags, _TCFFIPOINTER _I32 _I32 _TBYTES); DEFINE_HL_PRIM (_TBYTES, hl_font_render_glyphs, _TCFFIPOINTER _ARR _TBYTES); DEFINE_HL_PRIM (_VOID, hl_font_set_size, _TCFFIPOINTER _I32 _I32); + DEFINE_HL_PRIM (_VOID, hl_font_set_stem_darkening, _TCFFIPOINTER _BOOL); + DEFINE_HL_PRIM (_VOID, hl_font_set_stem_darkening_parameters, _TCFFIPOINTER _ARR); DEFINE_HL_PRIM (_VOID, hl_gamepad_add_mappings, _ARR); DEFINE_HL_PRIM (_VOID, hl_gamepad_event_manager_register, _FUN(_VOID, _NO_ARG) _TGAMEPAD_EVENT); DEFINE_HL_PRIM (_BYTES, hl_gamepad_get_device_guid, _I32); diff --git a/project/src/text/Font.cpp b/project/src/text/Font.cpp index 75e55d8f8d..ac600e1ab6 100644 --- a/project/src/text/Font.cpp +++ b/project/src/text/Font.cpp @@ -15,6 +15,7 @@ #include FT_TRUETYPE_TABLES_H #include FT_GLYPH_H #include FT_OUTLINE_H +#include FT_MODULE_H #endif #ifdef GetGlyphIndices @@ -1506,4 +1507,28 @@ namespace lime { } + void Font::SetStemDarkening (bool enable) + { + + FT_Bool no_darkening = enable ? 0 : 1; + + FT_Property_Set((FT_Library)library, "cff", "no-stem-darkening", &no_darkening); + FT_Property_Set((FT_Library)library, "autofitter", "no-stem-darkening", &no_darkening); + FT_Property_Set((FT_Library)library, "t1cid", "no-stem-darkening", &no_darkening); + FT_Property_Set((FT_Library)library, "type1", "no-stem-darkening", &no_darkening); + + } + + + void Font::SetStemDarkeningParameters (int params[]) + { + + FT_Property_Set((FT_Library)library, "cff", "darkening-parameters", params); + FT_Property_Set((FT_Library)library, "autofitter", "darkening-parameters", params); + FT_Property_Set((FT_Library)library, "t1cid", "darkening-parameters", params); + FT_Property_Set((FT_Library)library, "type1", "darkening-parameters", params); + + } + + } diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 5260218253..aa440642b8 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -184,6 +184,10 @@ class NativeCFFI @:cffi private static function lime_font_set_size(handle:Dynamic, size:Int, dpi:Int):Void; + @:cffi private static function lime_font_set_stem_darkening(handle:Dynamic, enable:Bool):Void; + + @:cffi private static function lime_font_set_stem_darkening_parameters(handle:Dynamic, params:Array):Void; + @:cffi private static function lime_gamepad_add_mappings(mappings:Dynamic):Void; @:cffi private static function lime_gamepad_get_device_guid(id:Int):Dynamic; @@ -822,6 +826,8 @@ class NativeCFFI private static var lime_font_render_glyphs = new cpp.Callablecpp.Object->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_font_render_glyphs", "oooo", false)); private static var lime_font_set_size = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_font_set_size", "oiiv", false)); + private static var lime_font_set_stem_darkening = new cpp.CallableBool->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_font_set_stem_darkening", "obv", false)); + private static var lime_font_set_stem_darkening_parameters = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_font_set_stem_darkening_parameters", "oov", false)); private static var lime_gamepad_add_mappings = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_gamepad_add_mappings", "ov", false)); private static var lime_gamepad_get_device_guid = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_gamepad_get_device_guid", "io", @@ -1293,6 +1299,8 @@ class NativeCFFI private static var lime_font_render_glyph_with_flags = CFFI.load("lime", "lime_font_render_glyph_with_flags", 4); private static var lime_font_render_glyphs = CFFI.load("lime", "lime_font_render_glyphs", 3); private static var lime_font_set_size = CFFI.load("lime", "lime_font_set_size", 3); + private static var lime_font_set_stem_darkening = CFFI.load("lime", "lime_font_set_stem_darkening", 2); + private static var lime_font_set_stem_darkening_parameters = CFFI.load("lime", "lime_font_set_stem_darkening_parameters", 2); private static var lime_gamepad_add_mappings = CFFI.load("lime", "lime_gamepad_add_mappings", 1); private static var lime_gamepad_get_device_guid = CFFI.load("lime", "lime_gamepad_get_device_guid", 1); private static var lime_gamepad_get_device_name = CFFI.load("lime", "lime_gamepad_get_device_name", 1); @@ -1800,6 +1808,10 @@ class NativeCFFI @:hlNative("lime", "hl_font_set_size") private static function lime_font_set_size(handle:CFFIPointer, size:Int, dpi:Int):Void {} + @:hlNative("lime", "hl_font_set_stem_darkening") private static function lime_font_set_stem_darkening(handle:CFFIPointer, enable:Bool):Void {} + + @:hlNative("lime", "hl_font_set_stem_darkening_parameters") private static function lime_font_set_stem_darkening_parameters(handle:CFFIPointer, params:hl.NativeArray):Void {} + @:hlNative("lime", "hl_gamepad_add_mappings") private static function lime_gamepad_add_mappings(mappings:hl.NativeArray):Void {} @:hlNative("lime", "hl_gamepad_get_device_guid") private static function lime_gamepad_get_device_guid(id:Int):hl.Bytes diff --git a/src/lime/text/Font.hx b/src/lime/text/Font.hx index 071337e4fc..e1a7611e19 100644 --- a/src/lime/text/Font.hx +++ b/src/lime/text/Font.hx @@ -96,6 +96,45 @@ class Font */ public var isItalic:Bool; + public var stemDarkening(default, set):Bool; + + private function set_stemDarkening(enable:Bool):Bool + { + if (stemDarkening == enable) { + return stemDarkening; + } + stemDarkening = enable; + #if (lime_cffi && !macro) + NativeCFFI.lime_font_set_stem_darkening(src, enable); + #end + return stemDarkening; + } + + public var stemDarkeningParameters(default, set):Array; + + private function set_stemDarkeningParameters(params:Array):Array + { + if (params == null || params.length != 8) + { + throw "Darking parameters length must be exactly 8"; + } + if (stemDarkeningParameters == params) + { + return stemDarkeningParameters; + } + stemDarkeningParameters = params; + #if (lime_cffi && !macro) + #if hl + var _params = new hl.NativeArray(params.length); + for (i in 0...params.length) + _params[i] = params[i]; + var params = _params; + #end + NativeCFFI.lime_font_set_stem_darkening_parameters(src, params); + #end + return stemDarkeningParameters; + } + @:noCompletion private var __fontID:String; @:noCompletion private var __fontPath:String; #if lime_cffi From 746739ab28edb58379c1fb5e80fe96efb9e0f616 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 28 Sep 2026 09:19:16 -0700 Subject: [PATCH 099/251] Font: docs for stemDarkening and stemDarkeningParameters --- src/lime/text/Font.hx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/lime/text/Font.hx b/src/lime/text/Font.hx index e1a7611e19..c0bdd4af75 100644 --- a/src/lime/text/Font.hx +++ b/src/lime/text/Font.hx @@ -96,6 +96,17 @@ class Font */ public var isItalic:Bool; + /** + May be used enable stem darkening when rendering this font. Stem + darkening is designed to increase legibility of a font. If a font's stem + is measured to be narrower than the specified minimum threshold, it will + be "darkened" by making it a bit bolder. + + This property enables affects the font rendering engine on native + targets only. On other targets, enabling stem darkening has no effect. + + @see `Font.stemDarkeningParameters` + **/ public var stemDarkening(default, set):Bool; private function set_stemDarkening(enable:Bool):Bool @@ -110,6 +121,22 @@ class Font return stemDarkening; } + /** + Configure the stem darkening parameters, which is an array of exactly + eight integers, consisting of four pairs of x and y values. The x value + is the stem width, and the y value is the darkening amount. The units of + each value is 1/1000th of a pixel (so 0.5 pixel would be passed as a + value of `500`). + + All values must be positive. Each stem width (x) value must be larger + than the previous stem width value. Each darkening amount (y) value must + be smaller than the previous darkening amount value. + + For complete details, see the + [FreeType darkening-parameters documentation](https://freetype.org/freetype2/docs/reference/ft2-properties.html#darkening-parameters). + + @see `Font.stemDarkening` + **/ public var stemDarkeningParameters(default, set):Array; private function set_stemDarkeningParameters(params:Array):Array From 8523c55ed025df1e27968acad3102fa4261d6352 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 28 Sep 2026 13:06:24 -0700 Subject: [PATCH 100/251] HTML5Application: prefer document visibilitychange event on iOS Safari over window blur/focus events (closes #2104) As noted in the comment, blur/focus are not dispatched consistently or reliably in Safari on iOS. Browsers on other operating systems always dispatch blur/focus, including desktop Safari. Keep the existing events elsewhere because blur/focus events also cover things like a window going into the background on desktop, which won't result in visibilitychange being dispatched. We're only special casing iOS browsers because they need to support the bare minimum behavior when switching tabs or apps. Co-Authored-By: mallyskies --- .../backend/html5/HTML5Application.hx | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index b4bac99707..72757286ae 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -37,6 +37,7 @@ class HTML5Application private var lastUpdate:Float; private var nextUpdate:Float; private var parent:Application; + private var preferVisibilityChange:Bool; #if stats private var stats:Dynamic; #end @@ -50,6 +51,31 @@ class HTML5Application nextUpdate = 0; framePeriod = -1; + // mobile Safari sometimes dispatches the blur event, but completely + // skips the matching focus event. for instance, when opening the tab + // switcher and returning to the exact same tab. it may depend on which + // type of HTML element has focus, though. + // + // sometimes, mobile Safari doesn't dispatch the blur and focus events + // at all! however, it always dispatches the visibilitychange event when + // switching to a different tab, or to a different app, so we prefer to + // use visibilitychange instead, but only on iOS. + // + // on desktop, we should continue to use the blur and focus events + // because the page will be considered to remain visible when losing + // focus to another app. the visibilitychange event seems to be + // dispatched on desktop when changing tabs only. desktop Safari behaves + // like other desktop browsers. + // + // Note: Android behaves more similarly to desktop than to iOS. + + preferVisibilityChange = js.Lib.typeof(Browser.document.visibilityState) == "string" + && ~/(iPad|iPhone|iPod).*OS/gi.match(Browser.window.navigator.userAgent); + if (preferVisibilityChange) + { + hidden = Browser.document.hidden; + } + AudioManager.init(); accelerometer = Sensor.registerSensor(SensorType.ACCELEROMETER, 0); } @@ -298,6 +324,7 @@ class HTML5Application Browser.window.addEventListener("blur", handleWindowEvent, false); Browser.window.addEventListener("resize", handleWindowEvent, false); Browser.window.addEventListener("beforeunload", handleWindowEvent, false); + Browser.document.addEventListener("visibilitychange", handleWindowEvent, false); if (Reflect.hasField(Browser.window, "Accelerometer")) { @@ -491,7 +518,7 @@ class HTML5Application switch (event.type) { case "focus": - if (hidden) + if (!preferVisibilityChange && hidden) { parent.window.onFocusIn.dispatch(); parent.window.onActivate.dispatch(); @@ -499,7 +526,7 @@ class HTML5Application } case "blur": - if (!hidden) + if (!preferVisibilityChange && !hidden) { parent.window.onFocusOut.dispatch(); parent.window.onDeactivate.dispatch(); @@ -507,23 +534,17 @@ class HTML5Application } case "visibilitychange": - if (Browser.document.hidden) + if (Browser.document.hidden && !hidden) { - if (!hidden) - { - parent.window.onFocusOut.dispatch(); - parent.window.onDeactivate.dispatch(); - hidden = true; - } + parent.window.onFocusOut.dispatch(); + parent.window.onDeactivate.dispatch(); + hidden = true; } - else + else if (!Browser.document.hidden && hidden) { - if (hidden) - { - parent.window.onFocusIn.dispatch(); - parent.window.onActivate.dispatch(); - hidden = false; - } + parent.window.onFocusIn.dispatch(); + parent.window.onActivate.dispatch(); + hidden = false; } case "resize": From f67f444ad4d9087bccf17eac5f57bb79c9ff2fb7 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Mon, 28 Sep 2026 14:49:09 -0700 Subject: [PATCH 101/251] HTML5Application: js.Lib.typeof() didn't exist in Haxe 3 Followup to commit 8523c55ed025df1e27968acad3102fa4261d6352 --- src/lime/_internal/backend/html5/HTML5Application.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index 72757286ae..1ee545a916 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -69,8 +69,13 @@ class HTML5Application // // Note: Android behaves more similarly to desktop than to iOS. + #if haxe4 preferVisibilityChange = js.Lib.typeof(Browser.document.visibilityState) == "string" && ~/(iPad|iPhone|iPod).*OS/gi.match(Browser.window.navigator.userAgent); + #else + preferVisibilityChange = untyped __js__ ('typeof document.visibilityState === "string"') + && ~/(iPad|iPhone|iPod).*OS/gi.match(Browser.window.navigator.userAgent); + #end if (preferVisibilityChange) { hidden = Browser.document.hidden; From 07dce8288d89527b4d86b34ff906963dbb9b5e7a Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:23:01 -0400 Subject: [PATCH 102/251] Fix Windows input and window pacing --- project/Build.xml | 1 + project/src/backend/sdl/SDLApplication.cpp | 256 +++++++++++++-------- project/src/backend/sdl/SDLApplication.h | 11 +- project/src/backend/sdl/SDLWindow.cpp | 77 ++++--- 4 files changed, 212 insertions(+), 133 deletions(-) diff --git a/project/Build.xml b/project/Build.xml index 84ef070811..4a41e9bde9 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -457,6 +457,7 @@ + diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 5b089f52b2..0031fa3a8c 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -31,6 +31,32 @@ namespace lime #if defined(HX_WINDOWS) && !defined(HX_WINRT) static SDL_atomic_t s_nativeModalLoopDepth; static SDL_atomic_t s_inModalEventWatch; + + // Restore native callback state even if a dispatched callback throws. + class ScopedModalWatch { + bool entered; + public: + ScopedModalWatch():entered(SDL_AtomicCAS(&s_inModalEventWatch, 0, 1) != 0) {} + ~ScopedModalWatch() { if (entered) SDL_AtomicSet(&s_inModalEventWatch, 0); } + bool Entered() const { return entered; } + }; + + class ScopedModalGC { + bool wasBlocking; + public: + ScopedModalGC():wasBlocking(SDL_AtomicGet(&s_waitEventBlocking) != 0) { + if (wasBlocking) { + System::GCExitBlocking(); + SDL_AtomicSet(&s_waitEventBlocking, 0); + } + } + ~ScopedModalGC() { + if (wasBlocking) { + System::GCEnterBlocking(); + SDL_AtomicSet(&s_waitEventBlocking, 1); + } + } + }; #endif SDLApplication::SDLApplication() @@ -42,6 +68,7 @@ namespace lime displayRefreshRate = 60.0; initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_TIMER | SDL_INIT_JOYSTICK; firstTime = true; + mouseCaptureRequested = false; #if defined(LIME_MOJOAL) || defined(LIME_OPENALSOFT) initFlags |= SDL_INIT_AUDIO; #endif @@ -66,8 +93,6 @@ namespace lime #if defined(HX_WINDOWS) && !defined(HX_WINRT) modalWatchInstalled = false; mainThreadID = SDL_ThreadID(); - pendingResizeDispatchSkips = 0; - pendingWatchRenderSkips = 0; #endif framePeriod = 1000.0 / 60.0; @@ -402,11 +427,11 @@ namespace lime return 0; // Prevent re-entry if rendering queues another window event. - if (!SDL_AtomicCAS(&s_inModalEventWatch, 0, 1)) + ScopedModalWatch watch; + if (!watch.Entered()) return 0; application->PumpOneFrameFromWatch(event); - SDL_AtomicSet(&s_inModalEventWatch, 0); return 0; } @@ -417,47 +442,26 @@ namespace lime return; bool isResizeEvent = false; - bool isExposeEvent = false; if (watchEvent && watchEvent->type == SDL_WINDOWEVENT) { isResizeEvent = (watchEvent->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || watchEvent->window.event == SDL_WINDOWEVENT_RESIZED); - isExposeEvent = (watchEvent->window.event == SDL_WINDOWEVENT_EXPOSED); } double now = GetCurrentTimeMs(); bool frameDue = IsFrameDue(now); - bool isResizeOrExposeEvent = (isResizeEvent || isExposeEvent); if (!frameDue && !isResizeEvent) return; - bool exitedBlocking = false; - if (SDL_AtomicGet(&s_waitEventBlocking)) - { - System::GCExitBlocking(); - SDL_AtomicSet(&s_waitEventBlocking, 0); - exitedBlocking = true; - } + ScopedModalGC gc; if (isResizeEvent) { ProcessWindowEvent(watchEvent); - pendingResizeDispatchSkips++; } if (frameDue) { DispatchFrame(now); - - if (watchEvent && isResizeOrExposeEvent) - { - pendingWatchRenderSkips++; - } - } - - if (exitedBlocking) - { - System::GCEnterBlocking(); - SDL_AtomicSet(&s_waitEventBlocking, 1); } } #endif @@ -658,79 +662,28 @@ namespace lime case SDL_WINDOWEVENT_EXPOSED: ProcessWindowEvent(event); - - if (!inBackground) + // Rendering is scheduled by Update, or by the watch while a native + // modal loop owns the thread. Do not consume a frame without drawing. +#if !defined(HX_WINDOWS) || defined(HX_WINRT) { - bool skipImmediateRender = false; -#if defined(HX_WINDOWS) && !defined(HX_WINRT) - if (pendingWatchRenderSkips > 0) - { - pendingWatchRenderSkips--; - skipImmediateRender = true; - } - - if (SDL_AtomicGet(&s_waitEventBlocking)) - { - PumpOneFrameFromWatch(); - } - else -#endif - { - double now = GetCurrentTimeMs(); - bool frameDue = IsFrameDue(now); - if (frameDue) - { - DispatchFrame(now, !skipImmediateRender); - } - } + double now = GetCurrentTimeMs(); + if (!inBackground && IsFrameDue(now)) DispatchFrame(now); } - +#endif break; case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_RESIZED: - { - - bool skipResizeDispatch = false; - bool skipImmediateRender = false; #if defined(HX_WINDOWS) && !defined(HX_WINRT) - if (pendingResizeDispatchSkips > 0) - { - pendingResizeDispatchSkips--; - skipResizeDispatch = true; - } - if (pendingWatchRenderSkips > 0) - { - pendingWatchRenderSkips--; - skipImmediateRender = true; - } -#endif - if (!skipResizeDispatch) + ProcessWindowEvent(event, true); +#else + ProcessWindowEvent(event); { - ProcessWindowEvent(event); + double now = GetCurrentTimeMs(); + if (!inBackground && IsFrameDue(now)) DispatchFrame(now); } - - if (!inBackground) - { -#if defined(HX_WINDOWS) && !defined(HX_WINRT) - if (SDL_AtomicGet(&s_waitEventBlocking)) - { - PumpOneFrameFromWatch(); - } - else #endif - { - double now = GetCurrentTimeMs(); - bool frameDue = IsFrameDue(now); - if (frameDue) - { - DispatchFrame(now, !skipImmediateRender); - } - } - } - break; - } case SDL_WINDOWEVENT_CLOSE: @@ -768,8 +721,7 @@ namespace lime nextUpdate = lastUpdate; firstTime = true; #if defined(HX_WINDOWS) && !defined(HX_WINRT) - pendingResizeDispatchSkips = 0; - pendingWatchRenderSkips = 0; + dispatchedWindowSizes.clear(); SDL_AtomicSet(&s_nativeModalLoopDepth, 0); #endif CalibrateSleepGuard(true); @@ -1061,7 +1013,18 @@ namespace lime case SDL_MOUSEBUTTONDOWN: - SDL_CaptureMouse(SDL_TRUE); + // SDL 2.0.22+ captures while buttons are held, before queued events + // reach Lime. Replaying capture here can recapture after SDL has + // already processed a complete down/up batch. Keep the legacy + // path for older SDL, touch-synthesized mouse events (excluded + // by SDL auto capture), and applications that disable it. +#if defined(HX_WINDOWS) && !defined(HX_WINRT) && SDL_VERSION_ATLEAST(2, 0, 22) + if (event->button.which == SDL_TOUCH_MOUSEID || !SDL_GetHintBoolean(SDL_HINT_MOUSE_AUTO_CAPTURE, SDL_TRUE)) +#endif + { + SDL_CaptureMouse(SDL_TRUE); + mouseCaptureRequested = true; + } mouseEvent.type = MOUSE_DOWN; mouseEvent.button = event->button.button - 1; @@ -1072,7 +1035,14 @@ namespace lime case SDL_MOUSEBUTTONUP: - SDL_CaptureMouse(SDL_FALSE); +#if defined(HX_WINDOWS) && !defined(HX_WINRT) && SDL_VERSION_ATLEAST(2, 0, 22) + // Release our own request even if the hint changed while held. + if (mouseCaptureRequested || event->button.which == SDL_TOUCH_MOUSEID || !SDL_GetHintBoolean(SDL_HINT_MOUSE_AUTO_CAPTURE, SDL_TRUE)) +#endif + { + SDL_CaptureMouse(SDL_FALSE); + mouseCaptureRequested = false; + } mouseEvent.type = MOUSE_UP; mouseEvent.button = event->button.button - 1; @@ -1206,7 +1176,28 @@ namespace lime } } - void SDLApplication::ProcessWindowEvent(SDL_Event *event) +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + bool SDLApplication::PrepareResizeEvent(SDL_Event *event, bool currentSize) + { + // SDL coalesces its own events, but directly pushed live-resize events + // can still contain older sizes. Reconcile queued events to current native + // dimensions; the watch uses its immediate dimensions before SDL updates. + if (currentSize) + { + SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); + if (window) + SDL_GetWindowSize(window, &event->window.data1, &event->window.data2); + } + std::pair size(event->window.data1, event->window.data2); + std::map>::iterator previous = dispatchedWindowSizes.find(event->window.windowID); + if (previous != dispatchedWindowSizes.end() && previous->second == size) + return false; + dispatchedWindowSizes[event->window.windowID] = size; + return true; + } +#endif + + void SDLApplication::ProcessWindowEvent(SDL_Event *event, bool currentSize) { if (WindowEvent::callback) @@ -1256,6 +1247,9 @@ namespace lime case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_RESIZED: +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + if (!PrepareResizeEvent(event, currentSize)) return; +#endif windowEvent.type = WINDOW_RESIZE; windowEvent.width = event->window.data1; windowEvent.height = event->window.data2; @@ -1267,7 +1261,18 @@ namespace lime } windowEvent.windowID = event->window.windowID; +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + try { + WindowEvent::Dispatch(&windowEvent); + } catch (...) { + // A failed resize callback must be retryable at the same dimensions. + if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event->window.event == SDL_WINDOWEVENT_RESIZED) + dispatchedWindowSizes.erase(event->window.windowID); + throw; + } +#else WindowEvent::Dispatch(&windowEvent); +#endif } } @@ -1314,6 +1319,9 @@ namespace lime void SDLApplication::UnregisterWindow(SDLWindow *window) { +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + if (window) dispatchedWindowSizes.erase(window->GetID()); +#endif windows.erase (std::remove (windows.begin (), windows.end (), window), windows.end ()); RefreshVSyncState (); } @@ -1358,23 +1366,57 @@ namespace lime SDL_Event event; event.type = -1; +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + bool pumpedEvents = false; + bool handledEvent = false; +#endif + #if (!defined(IPHONE) && !defined(EMSCRIPTEN)) - if (active && !firstTime && requestedUncapMode != MAIN_LOOP_UNCAP_HARD && WaitEvent(&event)) + if (active && !firstTime && requestedUncapMode != MAIN_LOOP_UNCAP_HARD) { - - HandleEvent(&event); - event.type = -1; - if (!active) - return active; +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + // Windows WaitEvent always pumps before returning. Do not pump the OS again + // merely to drain the SDL events that it has already collected. + pumpedEvents = true; +#endif + if (WaitEvent(&event)) + { +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + handledEvent = event.type != SDL_USEREVENT; +#endif + HandleEvent(&event); + event.type = -1; + if (!active) + return active; + } } firstTime = false; #endif +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + if (!pumpedEvents) + SDL_PumpEvents(); + + // Snapshot the batch size without dequeuing it. New arrivals cannot extend this + // turn indefinitely, preserving a finite cycle in uncapped modes too. Fetch + // one event at a time so SYSWMEVENT storage and early-exit payload ownership + // remain valid. Uncapped modes must not yield after every event just because + // IsFrameDue is always true; they drain this finite batch instead. + int queuedEvents = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); + while (queuedEvents-- > 0) + { + if (handledEvent && !schedulerUnthrottled && IsFrameDue(GetCurrentTimeMs())) + break; + if (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) != 1) + break; + handledEvent = true; +#else while (SDL_PollEvent(&event)) { +#endif HandleEvent(&event); event.type = -1; @@ -1656,6 +1698,22 @@ namespace lime for (;;) { +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + // The initial pump above already provided fresh input. Once the frame + // deadline is reached, do not start another potentially costly OS pump. + if (!schedulerUnthrottled && IsFrameDue(GetCurrentTimeMs())) + { + SDL_zero(*event); + event->type = SDL_USEREVENT; + if (isBlocking) + { + SDL_AtomicSet(&s_waitEventBlocking, 0); + System::GCExitBlocking(); + } + return 1; + } +#endif + SDL_PumpEvents(); switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index 397aa7ebc2..4037cbaeb2 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include #include @@ -72,7 +74,10 @@ namespace lime { void ProcessSensorEvent (SDL_Event* event); void ProcessTextEvent (SDL_Event* event); void ProcessTouchEvent (SDL_Event* event); - void ProcessWindowEvent (SDL_Event* event); + void ProcessWindowEvent (SDL_Event* event, bool currentSize = false); +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + bool PrepareResizeEvent (SDL_Event* event, bool currentSize); +#endif void UpdateSleepGuard (Uint32 requestedMs, Uint32 elapsedMs); int WaitEvent (SDL_Event* event); @@ -140,6 +145,7 @@ namespace lime { double lastUpdate; Uint32 lastSleepCalibration; MouseEvent mouseEvent; + bool mouseCaptureRequested; double nextUpdate; OrientationEvent orientationEvent; Uint64 performanceFrequency; @@ -163,8 +169,7 @@ namespace lime { #if defined(HX_WINDOWS) && !defined(HX_WINRT) bool modalWatchInstalled; Uint32 mainThreadID; - int pendingResizeDispatchSkips; - int pendingWatchRenderSkips; + std::map> dispatchedWindowSizes; #endif }; diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index d38ce8ae4a..ac89fa42cd 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -7,6 +7,9 @@ #ifdef HX_WINDOWS #include #include +#ifndef HX_WINRT +#include +#endif #undef CreateWindow #endif @@ -31,7 +34,10 @@ namespace lime { static bool displayModeSet = false; #if defined (HX_WINDOWS) && !defined (HX_WINRT) - static const wchar_t* LIME_SDL_OLD_RESIZE_WNDPROC_PROP = L"LimeSDL.OldResizeWndProc"; + static const UINT_PTR LIME_SDL_RESIZE_SUBCLASS_ID = 1; + // Outside the documented WM_MOUSEMOVE key/button bits. Never reaches SDL. + static const WPARAM LIME_SDL_CAPTION_WAKE_TAG = (WPARAM)0x4C490000; + static const wchar_t* LIME_SDL_IN_SIZE_MOVE_PROP = L"LimeSDL.InSizeMove"; static const wchar_t* LIME_SDL_WINDOW_ID_PROP = L"LimeSDL.WindowID"; static const wchar_t* LIME_SDL_LAST_RESIZE_WIDTH_PROP = L"LimeSDL.LastResizeWidth"; static const wchar_t* LIME_SDL_LAST_RESIZE_HEIGHT_PROP = L"LimeSDL.LastResizeHeight"; @@ -107,15 +113,39 @@ namespace lime { } - static LRESULT CALLBACK LimeResizeWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + static void ClearResizeEventProperties (HWND hwnd) { + + if (RemovePropW (hwnd, LIME_SDL_IN_SIZE_MOVE_PROP)) SDLApplication::ExitNativeModalLoop (); + RemovePropW (hwnd, LIME_SDL_WINDOW_ID_PROP); + RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_WIDTH_PROP); + RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_HEIGHT_PROP); + RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_TICK_PROP); + } + + static LRESULT CALLBACK LimeResizeWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR subclassID, DWORD_PTR referenceData) { + + if (message == WM_MOUSEMOVE && wParam == LIME_SDL_CAPTION_WAKE_TAG && lParam == 0) { + + // This message only wakes Windows' pre-drag mouse wait. Do not turn + // it into game input or move the application's remembered pointer. + return 0; + + } else if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION) { + + // DefWindowProc otherwise waits about 500 ms for caption drag intent + // before WM_ENTERSIZEMOVE, where SDL's modal timer finally starts. + // A posted zero-position move wakes that wait. Tag our message so + // the existing window chain never interprets it as physical input. + PostMessageW (hwnd, WM_MOUSEMOVE, LIME_SDL_CAPTION_WAKE_TAG, 0); - if (message == WM_ENTERSIZEMOVE) { + } else if (message == WM_ENTERSIZEMOVE) { - SDLApplication::EnterNativeModalLoop (); + if (!GetPropW (hwnd, LIME_SDL_IN_SIZE_MOVE_PROP) && SetPropW (hwnd, LIME_SDL_IN_SIZE_MOVE_PROP, (HANDLE)1)) + SDLApplication::EnterNativeModalLoop (); } else if (message == WM_EXITSIZEMOVE) { - SDLApplication::ExitNativeModalLoop (); + if (RemovePropW (hwnd, LIME_SDL_IN_SIZE_MOVE_PROP)) SDLApplication::ExitNativeModalLoop (); } else if (message == WM_SIZING) { @@ -132,14 +162,12 @@ namespace lime { } - WNDPROC oldWndProc = (WNDPROC)GetPropW (hwnd, LIME_SDL_OLD_RESIZE_WNDPROC_PROP); - if (oldWndProc) { - - return CallWindowProc (oldWndProc, hwnd, message, wParam, lParam); - + if (message == WM_NCDESTROY) { + RemoveWindowSubclass (hwnd, LimeResizeWndProc, subclassID); + ClearResizeEventProperties (hwnd); } - return DefWindowProc (hwnd, message, wParam, lParam); + return DefSubclassProc (hwnd, message, wParam, lParam); } @@ -153,14 +181,11 @@ namespace lime { HWND hwnd = wminfo.info.win.window; if (!hwnd) return; - if (GetPropW (hwnd, LIME_SDL_OLD_RESIZE_WNDPROC_PROP)) return; - - SetLastError (0); - LONG_PTR previous = SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR)LimeResizeWndProc); - if (previous == 0 && GetLastError () != 0) return; - - SetPropW (hwnd, LIME_SDL_OLD_RESIZE_WNDPROC_PROP, (HANDLE)previous); - SetPropW (hwnd, LIME_SDL_WINDOW_ID_PROP, (HANDLE)(UINT_PTR)SDL_GetWindowID (sdlWindow)); + DWORD_PTR data; + if (GetWindowSubclass (hwnd, LimeResizeWndProc, LIME_SDL_RESIZE_SUBCLASS_ID, &data)) return; + if (!SetPropW (hwnd, LIME_SDL_WINDOW_ID_PROP, (HANDLE)(UINT_PTR)SDL_GetWindowID (sdlWindow))) return; + if (!SetWindowSubclass (hwnd, LimeResizeWndProc, LIME_SDL_RESIZE_SUBCLASS_ID, 0)) + ClearResizeEventProperties (hwnd); } @@ -175,18 +200,8 @@ namespace lime { HWND hwnd = wminfo.info.win.window; if (!hwnd) return; - WNDPROC oldWndProc = (WNDPROC)GetPropW (hwnd, LIME_SDL_OLD_RESIZE_WNDPROC_PROP); - if (oldWndProc) { - - SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); - - } - - RemovePropW (hwnd, LIME_SDL_WINDOW_ID_PROP); - RemovePropW (hwnd, LIME_SDL_OLD_RESIZE_WNDPROC_PROP); - RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_WIDTH_PROP); - RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_HEIGHT_PROP); - RemovePropW (hwnd, LIME_SDL_LAST_RESIZE_TICK_PROP); + if (RemoveWindowSubclass (hwnd, LimeResizeWndProc, LIME_SDL_RESIZE_SUBCLASS_ID)) + ClearResizeEventProperties (hwnd); } From 35ae186958cb48b51bf5f915ff3206d51535d531 Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 10:11:07 -0400 Subject: [PATCH 103/251] Fix SDL frame timing and event handling --- project/src/ExternalInterface.cpp | 31 ++ project/src/backend/sdl/SDLApplication.cpp | 276 ++++++++++++------ project/src/backend/sdl/SDLApplication.h | 13 + .../backend/native/NativeApplication.hx | 36 +++ .../_internal/backend/native/NativeCFFI.hx | 11 + 5 files changed, 272 insertions(+), 95 deletions(-) diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index c55c2d83c4..88426295cc 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -9,6 +9,9 @@ #include #include +#ifdef LIME_SDL +#include "backend/sdl/SDLApplication.h" +#endif #include #include #include @@ -1504,6 +1507,30 @@ namespace lime { } + void lime_application_set_modal_callbacks (value application, value update, value render, value window, value rethrow) { +#if defined(LIME_SDL) && defined(HX_WINDOWS) && !defined(HX_WINRT) + ((SDLApplication*)val_data(application))->SetModalCallbacks(new ValuePointer(update), new ValuePointer(render), new ValuePointer(window), new ValuePointer(rethrow)); +#endif + } + + HL_PRIM void HL_NAME(hl_application_set_modal_callbacks) (HL_CFFIPointer* application, vclosure* update, vclosure* render, vclosure* window, vclosure* rethrow) { +#if defined(LIME_SDL) && defined(HX_WINDOWS) && !defined(HX_WINRT) + ((SDLApplication*)application->ptr)->SetModalCallbacks(new ValuePointer(update), new ValuePointer(render), new ValuePointer(window), new ValuePointer(rethrow)); +#endif + } + + void lime_application_defer_modal_exception (value application) { +#if defined(LIME_SDL) && defined(HX_WINDOWS) && !defined(HX_WINRT) + ((SDLApplication*)val_data(application))->DeferModalException(); +#endif + } + + HL_PRIM void HL_NAME(hl_application_defer_modal_exception) (HL_CFFIPointer* application) { +#if defined(LIME_SDL) && defined(HX_WINDOWS) && !defined(HX_WINRT) + ((SDLApplication*)application->ptr)->DeferModalException(); +#endif + } + void lime_application_set_frame_rate (value application, double frameRate) { Application* app = (Application*)val_data (application); @@ -13443,6 +13470,8 @@ namespace lime { DEFINE_PRIME1 (lime_application_quit); DEFINE_PRIME6v (lime_application_set_main_loop); DEFINE_PRIME2v (lime_application_set_frame_rate); + DEFINE_PRIME5v (lime_application_set_modal_callbacks); + DEFINE_PRIME1v (lime_application_defer_modal_exception); DEFINE_PRIME2v (lime_application_set_vsync_mode); DEFINE_PRIME1 (lime_application_update); DEFINE_PRIME2 (lime_audio_load); @@ -13756,6 +13785,8 @@ namespace lime { DEFINE_HL_PRIM (_I32, hl_application_quit, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_application_set_main_loop, _TCFFIPOINTER _I32 _F64 _I32 _I32 _I32); DEFINE_HL_PRIM (_VOID, hl_application_set_frame_rate, _TCFFIPOINTER _F64); + DEFINE_HL_PRIM (_VOID, hl_application_set_modal_callbacks, _TCFFIPOINTER _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG)); + DEFINE_HL_PRIM (_VOID, hl_application_defer_modal_exception, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_application_set_vsync_mode, _TCFFIPOINTER _I32); DEFINE_HL_PRIM (_BOOL, hl_application_update, _TCFFIPOINTER); DEFINE_HL_PRIM (_TAUDIOBUFFER, hl_audio_load_bytes, _TBYTES _TAUDIOBUFFER); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 0031fa3a8c..46adc8b562 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -2,6 +2,8 @@ #include "SDLGamepad.h" #include "SDLJoystick.h" #include +#include +#include #include #ifdef HX_MACOS @@ -57,14 +59,36 @@ namespace lime } } }; + + class ScopedModalCallbacks { + ValuePointer* update; + ValuePointer* render; + ValuePointer* window; + public: + ScopedModalCallbacks(ValuePointer** callbacks):update(ApplicationEvent::callback),render(RenderEvent::callback),window(WindowEvent::callback) + { + ApplicationEvent::callback = callbacks[0]; + RenderEvent::callback = callbacks[1]; + WindowEvent::callback = callbacks[2]; + } + ~ScopedModalCallbacks() + { + ApplicationEvent::callback = update; + RenderEvent::callback = render; + WindowEvent::callback = window; + } + }; #endif SDLApplication::SDLApplication() { + active = false; allowBusyWait = true; busyWaitOnly = false; currentUpdate = 0.0; + deltaRemainder = 0.0; + dispatchedFrames = 0; displayRefreshRate = 60.0; initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_TIMER | SDL_INIT_JOYSTICK; firstTime = true; @@ -79,6 +103,9 @@ namespace lime printf("Could not initialize SDL: %s.\n", SDL_GetError()); } + // Lime's cancelable window-close callback owns last-window termination. + SDL_SetHintWithPriority(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, "0", SDL_HINT_OVERRIDE); + #ifdef LIME_SDL_SOUND if (!Sound_Init ()) { @@ -92,6 +119,9 @@ namespace lime currentApplication = this; #if defined(HX_WINDOWS) && !defined(HX_WINRT) modalWatchInstalled = false; + modalExceptionPending = false; + for (int i = 0; i < 4; ++i) + modalCallbacks[i] = 0; mainThreadID = SDL_ThreadID(); #endif @@ -100,6 +130,14 @@ namespace lime lastSleepCalibration = 0; nextUpdate = 0.0; performanceFrequency = SDL_GetPerformanceFrequency(); + clockStartCounter = SDL_GetPerformanceCounter(); +#if SDL_VERSION_ATLEAST(2, 0, 18) + clockStartTicks = SDL_GetTicks64(); +#else + clockStartTicks = 0; +#endif + clockLastTicks = SDL_GetTicks(); + clockElapsedTicks = 0; realVSyncActive = false; requestedBusyWaitMode = MAIN_LOOP_BUSY_WAIT_AUTO; requestedFrameRate = 60.0; @@ -160,9 +198,13 @@ namespace lime } nextUpdate += framePeriod; - while (nextUpdate <= currentUpdate) + if (nextUpdate <= currentUpdate) { - nextUpdate += framePeriod; + double skippedPeriods = std::floor((currentUpdate - nextUpdate) / framePeriod) + 1.0; + nextUpdate += skippedPeriods * framePeriod; + // Rounding at a large clock value must not leave the deadline due. + if (nextUpdate <= currentUpdate) + nextUpdate = std::nextafter(currentUpdate, (std::numeric_limits::infinity)()); } } @@ -294,12 +336,22 @@ namespace lime double SDLApplication::GetCurrentTimeMs() const { - if (useHighResolutionTimer && performanceFrequency != 0) + if (performanceFrequency != 0) { - return ((double)SDL_GetPerformanceCounter() * 1000.0) / (double)performanceFrequency; + // Both precision modes use the same epoch; only their resolution differs. + double now = ((double)(SDL_GetPerformanceCounter() - clockStartCounter) * 1000.0) / (double)performanceFrequency; + return useHighResolutionTimer ? now : std::floor(now); } - return (double)SDL_GetTicks(); + // Extend legacy ticks without requiring a newer SDL minimum version. +#if SDL_VERSION_ATLEAST(2, 0, 18) + return (double)(SDL_GetTicks64() - clockStartTicks); +#else + Uint32 ticks = SDL_GetTicks(); + clockElapsedTicks += (Uint32)(ticks - clockLastTicks); + clockLastTicks = ticks; + return (double)clockElapsedTicks; +#endif } double SDLApplication::GetDisplayRefreshRate() const @@ -321,15 +373,29 @@ namespace lime void SDLApplication::DispatchFrame(double now, bool renderFrame) { - currentUpdate = now; +#if defined(IPHONE) || defined(EMSCRIPTEN) + int top = 0; + gc_set_top_of_stack(&top, false); +#endif + + currentUpdate = (std::max)(now, lastUpdate); applicationEvent.type = UPDATE; double delta = currentUpdate - lastUpdate; if (delta < 0.0) delta = 0.0; - applicationEvent.deltaTime = (int)(delta + 0.5); + double elapsed = delta + deltaRemainder; + double rounded = std::floor(elapsed + 0.5); + if (rounded > (double)(std::numeric_limits::max)()) + { + rounded = (double)(std::numeric_limits::max)(); + elapsed = rounded; + } + applicationEvent.deltaTime = (int)rounded; + deltaRemainder = elapsed - rounded; lastUpdate = currentUpdate; + dispatchedFrames++; AdvanceNextUpdate(); @@ -387,6 +453,8 @@ namespace lime SDL_DelEventWatch(ModalEventWatch, this); modalWatchInstalled = false; } + for (int i = 0; i < 4; ++i) + delete modalCallbacks[i]; #endif } @@ -418,12 +486,14 @@ namespace lime return 0; SDLApplication *application = (SDLApplication *)userdata; - if (!application || !application->active || inBackground) + if (!application || SDL_ThreadID() != application->mainThreadID) + return 0; + if (!application->active || inBackground) return 0; if (SDL_AtomicGet(&s_waitEventBlocking) == 0 && SDL_AtomicGet(&s_nativeModalLoopDepth) == 0) return 0; - if (SDL_ThreadID() != application->mainThreadID) + if (application->modalExceptionPending || application->modalNativeException || !application->modalCallbacks[3]) return 0; // Prevent re-entry if rendering queues another window event. @@ -431,10 +501,52 @@ namespace lime if (!watch.Entered()) return 0; - application->PumpOneFrameFromWatch(event); + try + { + ScopedModalCallbacks callbacks(application->modalCallbacks); + application->PumpOneFrameFromWatch(event); + } + catch (...) + { + application->modalNativeException = std::current_exception(); + } return 0; } + void SDLApplication::SetModalCallbacks(ValuePointer* update, ValuePointer* render, ValuePointer* window, ValuePointer* rethrow) + { + for (int i = 0; i < 4; ++i) + delete modalCallbacks[i]; + modalCallbacks[0] = update; + modalCallbacks[1] = render; + modalCallbacks[2] = window; + modalCallbacks[3] = rethrow; + } + + void SDLApplication::DeferModalException() + { + modalExceptionPending = true; + } + + void SDLApplication::CheckModalException(bool blocking) + { + if (!modalExceptionPending && !modalNativeException) + return; + if (blocking) + { + SDL_AtomicSet(&s_waitEventBlocking, 0); + System::GCExitBlocking(); + } + if (modalNativeException) + { + std::exception_ptr exception = modalNativeException; + modalNativeException = std::exception_ptr(); + std::rethrow_exception(exception); + } + modalExceptionPending = false; + modalCallbacks[3]->Call(); + } + void SDLApplication::PumpOneFrameFromWatch(SDL_Event *watchEvent) { @@ -507,16 +619,6 @@ namespace lime switch (event->type) { - case SDL_USEREVENT: - - if (!inBackground) - { - - DispatchFrame(GetCurrentTimeMs()); - } - - break; - case SDL_APP_WILLENTERBACKGROUND: inBackground = true; @@ -531,6 +633,9 @@ namespace lime case SDL_APP_DIDENTERFOREGROUND: + lastUpdate = GetCurrentTimeMs(); + nextUpdate = lastUpdate; + deltaRemainder = 0.0; windowEvent.type = WINDOW_ACTIVATE; WindowEvent::Dispatch(&windowEvent); @@ -688,19 +793,6 @@ namespace lime case SDL_WINDOWEVENT_CLOSE: ProcessWindowEvent(event); - - // Avoid handling SDL_QUIT if in response to window.close - SDL_Event event; - - if (SDL_PollEvent(&event)) - { - - if (event.type != SDL_QUIT) - { - - HandleEvent(&event); - } - } break; } @@ -717,6 +809,7 @@ namespace lime { active = true; + deltaRemainder = 0.0; lastUpdate = GetCurrentTimeMs(); nextUpdate = lastUpdate; firstTime = true; @@ -1264,6 +1357,8 @@ namespace lime #if defined(HX_WINDOWS) && !defined(HX_WINRT) try { WindowEvent::Dispatch(&windowEvent); + if (modalExceptionPending && (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event->window.event == SDL_WINDOWEVENT_RESIZED)) + dispatchedWindowSizes.erase(event->window.windowID); } catch (...) { // A failed resize callback must be retryable at the same dimensions. if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event->window.event == SDL_WINDOWEVENT_RESIZED) @@ -1363,6 +1458,10 @@ namespace lime bool SDLApplication::Update() { +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + CheckModalException(); +#endif + Uint64 framesBeforeEvents = dispatchedFrames; SDL_Event event; event.type = -1; @@ -1373,7 +1472,7 @@ namespace lime #if (!defined(IPHONE) && !defined(EMSCRIPTEN)) - if (active && !firstTime && requestedUncapMode != MAIN_LOOP_UNCAP_HARD) + if (active && (inBackground || (!firstTime && requestedUncapMode != MAIN_LOOP_UNCAP_HARD))) { #if defined(HX_WINDOWS) && !defined(HX_WINRT) // Windows WaitEvent always pumps before returning. Do not pump the OS again @@ -1383,7 +1482,10 @@ namespace lime if (WaitEvent(&event)) { #if defined(HX_WINDOWS) && !defined(HX_WINRT) - handledEvent = event.type != SDL_USEREVENT; + CheckModalException(); +#endif +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + handledEvent = true; #endif HandleEvent(&event); event.type = -1; @@ -1399,6 +1501,7 @@ namespace lime #if defined(HX_WINDOWS) && !defined(HX_WINRT) if (!pumpedEvents) SDL_PumpEvents(); + CheckModalException(); // Snapshot the batch size without dequeuing it. New arrivals cannot extend this // turn indefinitely, preserving a finite cycle in uncapped modes too. Fetch @@ -1420,34 +1523,21 @@ namespace lime HandleEvent(&event); event.type = -1; +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + CheckModalException(); +#endif if (!active) return active; } currentUpdate = GetCurrentTimeMs(); -#if defined(IPHONE) || defined(EMSCRIPTEN) - - if (IsFrameDue(currentUpdate)) + if (!inBackground && dispatchedFrames == framesBeforeEvents && IsFrameDue(currentUpdate)) { - event.type = SDL_USEREVENT; - HandleEvent(&event); - event.type = -1; + DispatchFrame(currentUpdate); } -#else - - if (IsFrameDue(currentUpdate)) - { - - event.type = SDL_USEREVENT; - HandleEvent(&event); - event.type = -1; - } - -#endif - return active; } @@ -1474,6 +1564,16 @@ namespace lime int SDLApplication::WaitEvent(SDL_Event *event) { + if (inBackground) + { + System::GCEnterBlocking(); + SDL_AtomicSet(&s_waitEventBlocking, 1); + int result = SDL_WaitEventTimeout(event, 100); + SDL_AtomicSet(&s_waitEventBlocking, 0); + System::GCExitBlocking(); + return result; + } + #if defined(HX_MACOS) || defined(ANDROID) for (;;) @@ -1485,9 +1585,24 @@ namespace lime if (schedulerUnthrottled || remaining <= 0.0) { - SDL_zero(*event); - event->type = SDL_USEREVENT; - return 1; + return 0; + } + + if (allowBusyWait && busyWaitOnly) + { + System::GCEnterBlocking(); + while ((nextUpdate - GetCurrentTimeMs()) > 0.0) + { + SDL_PumpEvents(); + int result = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); + if (result != 0) + { + System::GCExitBlocking(); + return result == 1 ? 1 : 0; + } + } + System::GCExitBlocking(); + return 0; } int waitMs = (int)(remaining + 0.999); @@ -1524,35 +1639,8 @@ namespace lime if (result == -1) return 0; - if (allowBusyWait && !busyWaitOnly) + if (allowBusyWait) UpdateSleepGuard((Uint32)waitMs, waitElapsed); - - if (allowBusyWait && busyWaitOnly) - { - - while ((nextUpdate - GetCurrentTimeMs()) > 0.0) - { - - SDL_PumpEvents(); - - switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) - { - - case -1: - return 0; - - case 1: - return 1; - - default: - break; - } - } - - SDL_zero(*event); - event->type = SDL_USEREVENT; - return 1; - } } #else @@ -1565,6 +1653,9 @@ namespace lime SDL_PumpEvents(); +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + CheckModalException(isBlocking); +#endif switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) { @@ -1601,15 +1692,12 @@ namespace lime if (schedulerUnthrottled || remaining <= 0.0) { - SDL_zero(*event); - event->type = SDL_USEREVENT; - if (isBlocking) { SDL_AtomicSet(&s_waitEventBlocking, 0); System::GCExitBlocking(); } - return 1; + return 0; } if (!allowBusyWait) @@ -1703,19 +1791,20 @@ namespace lime // deadline is reached, do not start another potentially costly OS pump. if (!schedulerUnthrottled && IsFrameDue(GetCurrentTimeMs())) { - SDL_zero(*event); - event->type = SDL_USEREVENT; if (isBlocking) { SDL_AtomicSet(&s_waitEventBlocking, 0); System::GCExitBlocking(); } - return 1; + return 0; } #endif SDL_PumpEvents(); +#if defined(HX_WINDOWS) && !defined(HX_WINRT) + CheckModalException(isBlocking); +#endif switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) { @@ -1742,15 +1831,12 @@ namespace lime if ((nextUpdate - GetCurrentTimeMs()) <= 0.0) { - SDL_zero(*event); - event->type = SDL_USEREVENT; - if (isBlocking) { SDL_AtomicSet(&s_waitEventBlocking, 0); System::GCExitBlocking(); } - return 1; + return 0; } break; diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index 4037cbaeb2..5103185429 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ namespace lime { #if defined(HX_WINDOWS) && !defined(HX_WINRT) static void EnterNativeModalLoop (); static void ExitNativeModalLoop (); + void SetModalCallbacks (ValuePointer* update, ValuePointer* render, ValuePointer* window, ValuePointer* rethrow); + void DeferModalException (); #endif private: @@ -64,6 +67,7 @@ namespace lime { #if defined(HX_WINDOWS) && !defined(HX_WINRT) void PumpOneFrameFromWatch (SDL_Event* watchEvent = 0); static int ModalEventWatch (void* userdata, SDL_Event* event); + void CheckModalException (bool blocking = false); #endif void ProcessClipboardEvent (SDL_Event* event); void ProcessDropEvent (SDL_Event* event); @@ -134,6 +138,8 @@ namespace lime { bool busyWaitOnly; ClipboardEvent clipboardEvent; double currentUpdate; + double deltaRemainder; + Uint64 dispatchedFrames; double displayRefreshRate; double framePeriod; Uint32 initFlags; @@ -149,6 +155,10 @@ namespace lime { double nextUpdate; OrientationEvent orientationEvent; Uint64 performanceFrequency; + Uint64 clockStartCounter; + Uint64 clockStartTicks; + mutable Uint32 clockLastTicks; + mutable Uint64 clockElapsedTicks; bool realVSyncActive; int requestedBusyWaitMode; double requestedFrameRate; @@ -168,6 +178,9 @@ namespace lime { std::vector windows; #if defined(HX_WINDOWS) && !defined(HX_WINRT) bool modalWatchInstalled; + ValuePointer* modalCallbacks[4]; + bool modalExceptionPending; + std::exception_ptr modalNativeException; Uint32 mainThreadID; std::map> dispatchedWindowSizes; #endif diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index b17d2b34fa..9f09c28cd3 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -65,6 +65,10 @@ class NativeApplication private var touchEventInfo = new TouchEventInfo(); private var unusedTouchesPool = new List(); private var windowEventInfo = new WindowEventInfo(); + #if (windows && !winrt) + private var modalException:Dynamic; + private var modalExceptionPending = false; + #end public var handle:Dynamic; @@ -134,6 +138,12 @@ class NativeApplication NativeCFFI.lime_text_event_manager_register(handleTextEvent, textEventInfo); NativeCFFI.lime_touch_event_manager_register(handleTouchEvent, touchEventInfo); NativeCFFI.lime_window_event_manager_register(handleWindowEvent, windowEventInfo); + #if (windows && !winrt) + NativeCFFI.lime_application_set_modal_callbacks(handle, + function() runModalCallback(handleApplicationEvent), + function() runModalCallback(handleRenderEvent), + function() runModalCallback(handleWindowEvent), rethrowModalException); + #end #if (ios || android) NativeCFFI.lime_orientation_event_manager_register(handleOrientationEvent, orientationEventInfo); @@ -205,6 +215,32 @@ class NativeApplication #end } + #if (windows && !winrt) + private function runModalCallback(callback:Void->Void):Void + { + if (modalExceptionPending) return; + try + { + callback(); + } + catch (exception:Dynamic) + { + // Keep the value rooted in Haxe; do not unwind through SDL/Win32. + modalException = exception; + modalExceptionPending = true; + NativeCFFI.lime_application_defer_modal_exception(handle); + } + } + + private function rethrowModalException():Void + { + var exception = modalException; + modalException = null; + modalExceptionPending = false; + throw exception; + } + #end + private function handleApplicationEvent():Void { switch (applicationEventInfo.type) diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index aa440642b8..a7e2d3d76e 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -68,6 +68,9 @@ class NativeCFFI @:cffi private static function lime_application_set_main_loop(handle:Dynamic, profile:Int, frameRate:Float, timePrecision:Int, busyWait:Int, uncapMode:Int):Void; + @:cffi private static function lime_application_set_modal_callbacks(handle:Dynamic, update:Dynamic, render:Dynamic, window:Dynamic, rethrow:Dynamic):Void; + @:cffi private static function lime_application_defer_modal_exception(handle:Dynamic):Void; + @:cffi private static function lime_application_set_frame_rate(handle:Dynamic, value:Float):Void; @:cffi private static function lime_application_set_vsync_mode(handle:Dynamic, value:Int):Void; @@ -726,6 +729,9 @@ class NativeCFFI private static var lime_application_quit = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_application_quit", "oi", false)); private static var lime_application_set_main_loop = new cpp.CallableInt->Float->Int->Int->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_set_main_loop", "oidiiiv", false)); + private static var lime_application_set_modal_callbacks = new cpp.Callablecpp.Object->cpp.Object->cpp.Object->cpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_set_modal_callbacks", "ooooov", false)); + private static var lime_application_defer_modal_exception = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_defer_modal_exception", "ov", false)); + private static var lime_application_set_frame_rate = new cpp.CallableFloat->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_set_frame_rate", "odv", false)); private static var lime_application_set_vsync_mode = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", @@ -1242,6 +1248,8 @@ class NativeCFFI private static var lime_application_quit = CFFI.load("lime", "lime_application_quit", 1); private static var lime_application_set_main_loop = CFFI.load("lime", "lime_application_set_main_loop", -1); private static var lime_application_set_frame_rate = CFFI.load("lime", "lime_application_set_frame_rate", 2); + private static var lime_application_set_modal_callbacks = CFFI.load("lime", "lime_application_set_modal_callbacks", 5); + private static var lime_application_defer_modal_exception = CFFI.load("lime", "lime_application_defer_modal_exception", 1); private static var lime_application_set_vsync_mode = CFFI.load("lime", "lime_application_set_vsync_mode", 2); private static var lime_application_update = CFFI.load("lime", "lime_application_update", 1); private static var lime_audio_load = CFFI.load("lime", "lime_audio_load", 2); @@ -1545,6 +1553,9 @@ class NativeCFFI @:hlNative("lime", "hl_application_set_main_loop") private static function lime_application_set_main_loop(handle:CFFIPointer, profile:Int, frameRate:Float, timePrecision:Int, busyWait:Int, uncapMode:Int):Void {} + @:hlNative("lime", "hl_application_set_modal_callbacks") private static function lime_application_set_modal_callbacks(handle:CFFIPointer, update:Void->Void, render:Void->Void, window:Void->Void, rethrow:Void->Void):Void {} + @:hlNative("lime", "hl_application_defer_modal_exception") private static function lime_application_defer_modal_exception(handle:CFFIPointer):Void {} + @:hlNative("lime", "hl_application_set_frame_rate") private static function lime_application_set_frame_rate(handle:CFFIPointer, value:Float):Void {} @:hlNative("lime", "hl_application_set_vsync_mode") private static function lime_application_set_vsync_mode(handle:CFFIPointer, value:Int):Void {} From e26a3973f5021f0ec9a0adbf0041a6893e2394fa Mon Sep 17 00:00:00 2001 From: "Enzo Persillet (Tutez)" Date: Fri, 8 May 2026 02:58:44 +0200 Subject: [PATCH 104/251] Ensure template asset destination directories exist --- src/lime/tools/AssetHelper.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lime/tools/AssetHelper.hx b/src/lime/tools/AssetHelper.hx index ed4bb6bdbb..ce77170240 100644 --- a/src/lime/tools/AssetHelper.hx +++ b/src/lime/tools/AssetHelper.hx @@ -90,6 +90,8 @@ class AssetHelper public static function copyAsset(asset:Asset, destination:String, context:Dynamic = null) { + System.mkdir(Path.directory(destination)); + if (asset.sourcePath != "") { System.copyFile(asset.sourcePath, destination, context, asset.type == TEMPLATE); From 2c64abbc2047119a052f2644c915fa2f7a639bbb Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 9 Oct 2026 09:50:21 -0700 Subject: [PATCH 105/251] LinuxPlatform: add window icon support (closes #2057) Co-authored-by: Tutez64 --- templates/haxe/ApplicationMain.hx | 11 +++++++++++ tools/platforms/LinuxPlatform.hx | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/templates/haxe/ApplicationMain.hx b/templates/haxe/ApplicationMain.hx index 66c445d16f..4b7dee6578 100644 --- a/templates/haxe/ApplicationMain.hx +++ b/templates/haxe/ApplicationMain.hx @@ -90,6 +90,17 @@ import ::APP_MAIN::; } app.createWindow(attributes); + #if (linux && sys) + var iconPath = lime.system.System.applicationDirectory + "/icon.png"; + if (sys.FileSystem.exists(iconPath)) + { + var icon = lime.graphics.Image.fromFile(iconPath); + if (icon != null && app.window != null) + { + app.window.setIcon(icon); + } + } + #end ::end:: #elseif air app.window.title = "::meta.title::"; diff --git a/tools/platforms/LinuxPlatform.hx b/tools/platforms/LinuxPlatform.hx index 0bccbbc624..d19a28e09f 100644 --- a/tools/platforms/LinuxPlatform.hx +++ b/tools/platforms/LinuxPlatform.hx @@ -13,6 +13,8 @@ import lime.tools.AssetType; import lime.tools.CPPHelper; import lime.tools.DeploymentHelper; import lime.tools.HXProject; +import lime.tools.IconHelper; +import lime.tools.Icon; import lime.tools.JavaHelper; import lime.tools.NekoHelper; import lime.tools.NodeJSHelper; @@ -618,7 +620,15 @@ class LinuxPlatform extends PlatformTarget ProjectHelper.recursiveSmartCopyTemplate(project, "cpp/static", targetDirectory + "/obj", context); } - // context.HAS_ICON = IconHelper.createIcon (project.icons, 256, 256, Path.combine (applicationDirectory, "icon.png")); + var icons = project.icons; + + if (icons.length == 0) + { + icons = [new Icon(System.findTemplate(project.templatePaths, "default/icon.svg"))]; + } + + context.HAS_ICON = IconHelper.createIcon(icons, 256, 256, Path.combine(applicationDirectory, "icon.png")); + copyProjectAssets(applicationDirectory); } From f67e27d58531868a2a9e7c45914f84263043278a Mon Sep 17 00:00:00 2001 From: "Enzo Persillet (Tutez)" Date: Sun, 12 Jul 2026 01:04:49 +0200 Subject: [PATCH 106/251] Fix PNG read buffer lifetime during memory decoding --- project/src/graphics/format/PNG.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/project/src/graphics/format/PNG.cpp b/project/src/graphics/format/PNG.cpp index c532bced6f..fa0ef8683d 100644 --- a/project/src/graphics/format/PNG.cpp +++ b/project/src/graphics/format/PNG.cpp @@ -21,21 +21,13 @@ namespace lime { ReadBuffer (const unsigned char* data, int length) : data (data), length (length), position (0) {} - bool Read (unsigned char* out, int count) { + bool Read (unsigned char* out, png_size_t count) { - if (position >= length) return false; + if (position > length || count > (png_size_t)(length - position)) return false; + if (count == 0) return true; - if (count > length - position) { - - memcpy (out, data + position, length - position); - position = length; - - } else { - - memcpy (out, data + position, count); - position += count; - - } + memcpy (out, data + position, count); + position += (int)count; return true; @@ -88,6 +80,7 @@ namespace lime { FILE_HANDLE* file = NULL; Bytes* data = NULL; + ReadBuffer buffer (NULL, 0); if (resource->path) { @@ -148,14 +141,14 @@ namespace lime { data = new Bytes (); data->ReadFile (resource->path); - ReadBuffer buffer (data->b, data->length); + buffer = ReadBuffer (data->b, data->length); png_set_read_fn (png_ptr, &buffer, user_read_data_fn); } } else { - ReadBuffer buffer (resource->data->b, resource->data->length); + buffer = ReadBuffer (resource->data->b, resource->data->length); png_set_read_fn (png_ptr, &buffer, user_read_data_fn); } From 95105f49da56278b81afd5d3066a731d77c53687 Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 15:21:07 -0400 Subject: [PATCH 107/251] NativeApplication: Guard the deferred modal exception CFFI call runModalCallback only checked for Windows, so typing NativeApplication without lime_cffi, such as from a macro, failed because NativeCFFI does not declare lime_application_defer_modal_exception there. --- src/lime/_internal/backend/native/NativeApplication.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 9f09c28cd3..10d3aa0bc6 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -228,7 +228,9 @@ class NativeApplication // Keep the value rooted in Haxe; do not unwind through SDL/Win32. modalException = exception; modalExceptionPending = true; + #if (!macro && lime_cffi) NativeCFFI.lime_application_defer_modal_exception(handle); + #end } } From c9087aaa8e2043b76707e70352b21ef281bcb5ba Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:09:23 -0400 Subject: [PATCH 108/251] SDL: Use the monotonic clock for timers on Linux The Linux SDL configuration did not define HAVE_CLOCK_GETTIME, so SDL fell back to gettimeofday for SDL_GetTicks and the performance counter. Lime's frame scheduling then followed the wall clock, and any backward clock step (NTP at boot, resume from suspend, WSL time sync) stopped frames from being dispatched until the wall clock caught up again. --- project/lib/custom/sdl/include/SDL_config_linux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/project/lib/custom/sdl/include/SDL_config_linux.h b/project/lib/custom/sdl/include/SDL_config_linux.h index 61e633f33b..e19f89b7e6 100644 --- a/project/lib/custom/sdl/include/SDL_config_linux.h +++ b/project/lib/custom/sdl/include/SDL_config_linux.h @@ -153,6 +153,7 @@ #define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 +#define HAVE_CLOCK_GETTIME 1 #define HAVE_SYSCONF 1 /* #undef HAVE_SYSCTLBYNAME */ From de344a305c5f2dd3f706b64bbc6ee12c0964bbbc Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:09:29 -0400 Subject: [PATCH 109/251] Menu: Add native menu bars and context menus Adds lime.ui.Menu and lime.ui.MenuItem, following the AIR model so that OpenFL's NativeMenu can be built on top of them: - Window.menu shows a menu bar on platforms where windows own one (Window.supportsMenu, currently Windows) - Application.menu sets the application menu bar on macOS (Application.supportsMenu) - Menu.popup() shows a context menu wherever Menu.isSupported is true Items support labels, mnemonics, separators, checked and enabled states, submenus and key equivalents. Selection is dispatched through MenuItem.onSelect and bubbles to each containing Menu.onSelect. The SDL backend implements Win32 menus, Cocoa menus, and GTK 3 context menus on Linux, which are loaded at runtime when available. Menu changes are sent to the native side as a snapshot and rebuilt there. --- project/Build.xml | 6 + project/include/app/Application.h | 1 + project/include/ui/Menu.h | 29 ++ project/include/ui/MenuEvent.h | 39 ++ project/include/ui/Window.h | 2 + project/src/ExternalInterface.cpp | 94 +++++ project/src/backend/sdl/SDLApplication.cpp | 35 ++ project/src/backend/sdl/SDLApplication.h | 4 + project/src/backend/sdl/SDLMenu.cpp | 209 +++++++++++ project/src/backend/sdl/SDLMenu.h | 69 ++++ project/src/backend/sdl/SDLMenuLinux.cpp | 353 ++++++++++++++++++ project/src/backend/sdl/SDLMenuMac.mm | 324 ++++++++++++++++ project/src/backend/sdl/SDLMenuWindows.cpp | 301 +++++++++++++++ project/src/backend/sdl/SDLWindow.cpp | 17 + project/src/backend/sdl/SDLWindow.h | 2 + project/src/ui/MenuEvent.cpp | 64 ++++ .../backend/flash/FlashApplication.hx | 3 + .../_internal/backend/flash/FlashWindow.hx | 5 + .../backend/html5/HTML5Application.hx | 3 + .../_internal/backend/html5/HTML5Window.hx | 5 + .../backend/native/NativeApplication.hx | 70 ++++ .../_internal/backend/native/NativeCFFI.hx | 47 +++ .../_internal/backend/native/NativeMenu.hx | 165 ++++++++ .../_internal/backend/native/NativeWindow.hx | 57 +++ src/lime/app/Application.hx | 57 +++ src/lime/ui/Menu.hx | 293 +++++++++++++++ src/lime/ui/MenuItem.hx | 257 +++++++++++++ src/lime/ui/Window.hx | 52 +++ 28 files changed, 2563 insertions(+) create mode 100644 project/include/ui/Menu.h create mode 100644 project/include/ui/MenuEvent.h create mode 100644 project/src/backend/sdl/SDLMenu.cpp create mode 100644 project/src/backend/sdl/SDLMenu.h create mode 100644 project/src/backend/sdl/SDLMenuLinux.cpp create mode 100644 project/src/backend/sdl/SDLMenuMac.mm create mode 100644 project/src/backend/sdl/SDLMenuWindows.cpp create mode 100644 project/src/ui/MenuEvent.cpp create mode 100644 src/lime/_internal/backend/native/NativeMenu.hx create mode 100644 src/lime/ui/Menu.hx create mode 100644 src/lime/ui/MenuItem.hx diff --git a/project/Build.xml b/project/Build.xml index 4a41e9bde9..d900bb5d8c 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -275,6 +275,10 @@ + + + + @@ -356,6 +360,7 @@ + @@ -482,6 +487,7 @@
+ diff --git a/project/include/app/Application.h b/project/include/app/Application.h index e7e5e7114a..2d2f5272a2 100644 --- a/project/include/app/Application.h +++ b/project/include/app/Application.h @@ -22,6 +22,7 @@ namespace lime { virtual int Quit () = 0; virtual void SetMainLoop (int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { SetFrameRate (frameRate); } virtual void SetFrameRate (double frameRate) = 0; + virtual bool SetMenu (const unsigned char* data, int length) { return false; } virtual void SetVSyncMode (int vsyncMode) {} virtual bool Update () = 0; diff --git a/project/include/ui/Menu.h b/project/include/ui/Menu.h new file mode 100644 index 0000000000..93ab6cd49f --- /dev/null +++ b/project/include/ui/Menu.h @@ -0,0 +1,29 @@ +#ifndef LIME_UI_MENU_H +#define LIME_UI_MENU_H + + +namespace lime { + + + enum MenuSupport { + + MENU_SUPPORT_POPUP = 0x01, + MENU_SUPPORT_WINDOW = 0x02, + MENU_SUPPORT_APPLICATION = 0x04 + + }; + + + class Menu { + + public: + + static int GetSupport (); + + }; + + +} + + +#endif diff --git a/project/include/ui/MenuEvent.h b/project/include/ui/MenuEvent.h new file mode 100644 index 0000000000..5b8ba05abc --- /dev/null +++ b/project/include/ui/MenuEvent.h @@ -0,0 +1,39 @@ +#ifndef LIME_UI_MENU_EVENT_H +#define LIME_UI_MENU_EVENT_H + + +#include +#include + + +namespace lime { + + + enum MenuEventType { + + MENU_SELECT + + }; + + + struct MenuEvent { + + hl_type* t; + int id; + MenuEventType type; + int windowID; + + static ValuePointer* callback; + static ValuePointer* eventObject; + + MenuEvent (); + + static void Dispatch (MenuEvent* event); + + }; + + +} + + +#endif diff --git a/project/include/ui/Window.h b/project/include/ui/Window.h index 81afa74fae..315f91525f 100644 --- a/project/include/ui/Window.h +++ b/project/include/ui/Window.h @@ -51,6 +51,7 @@ namespace lime { virtual int GetX () = 0; virtual int GetY () = 0; virtual void Move (int x, int y) = 0; + virtual int PopupMenu (const unsigned char* data, int length, int x, int y, bool atCursor) { return 0; } virtual void ReadPixels (ImageBuffer *buffer, Rectangle *rect) = 0; virtual void Resize (int width, int height) = 0; virtual void SetMinimumSize (int width, int height) = 0; @@ -61,6 +62,7 @@ namespace lime { virtual bool SetFullscreen (bool fullscreen) = 0; virtual void SetIcon (ImageBuffer *imageBuffer) = 0; virtual bool SetMaximized (bool minimized) = 0; + virtual bool SetMenu (const unsigned char* data, int length) { return false; } virtual bool SetMinimized (bool minimized) = 0; virtual void SetMouseLock (bool mouseLock) = 0; virtual void SetOpacity (float opacity) = 0; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 88426295cc..f3a171eec1 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -1547,6 +1549,23 @@ namespace lime { } + bool lime_application_set_menu (value application, value data) { + + Application* app = (Application*)val_data (application); + Bytes bytes (data); + return app->SetMenu (bytes.b, bytes.length); + + } + + + HL_PRIM bool HL_NAME(hl_application_set_menu) (HL_CFFIPointer* application, Bytes* data) { + + Application* app = (Application*)application->ptr; + return app->SetMenu (data ? data->b : 0, data ? data->length : 0); + + } + + void lime_application_set_main_loop (value application, int profile, double frameRate, int timePrecision, int busyWait, int uncapMode) { Application* app = (Application*)val_data (application); @@ -3952,6 +3971,36 @@ namespace lime { } + int lime_menu_get_support () { + + return Menu::GetSupport (); + + } + + + HL_PRIM int HL_NAME(hl_menu_get_support) () { + + return Menu::GetSupport (); + + } + + + void lime_menu_event_manager_register (value callback, value eventObject) { + + MenuEvent::callback = new ValuePointer (callback); + MenuEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_menu_event_manager_register) (vclosure* callback, MenuEvent* eventObject) { + + MenuEvent::callback = new ValuePointer (callback); + MenuEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + void lime_mouse_event_manager_register (value callback, value eventObject) { MouseEvent::callback = new ValuePointer (callback); @@ -13027,6 +13076,23 @@ namespace lime { } + int lime_window_popup_menu (value window, value data, int x, int y, bool atCursor) { + + Window* targetWindow = (Window*)val_data (window); + Bytes bytes (data); + return targetWindow->PopupMenu (bytes.b, bytes.length, x, y, atCursor); + + } + + + HL_PRIM int HL_NAME(hl_window_popup_menu) (HL_CFFIPointer* window, Bytes* data, int x, int y, bool atCursor) { + + Window* targetWindow = (Window*)window->ptr; + return targetWindow->PopupMenu (data ? data->b : 0, data ? data->length : 0, x, y, atCursor); + + } + + value lime_window_read_pixels (value window, value rect, value imageBuffer) { Window* targetWindow = (Window*)val_data (window); @@ -13217,6 +13283,23 @@ namespace lime { } + bool lime_window_set_menu (value window, value data) { + + Window* targetWindow = (Window*)val_data (window); + Bytes bytes (data); + return targetWindow->SetMenu (bytes.b, bytes.length); + + } + + + HL_PRIM bool HL_NAME(hl_window_set_menu) (HL_CFFIPointer* window, Bytes* data) { + + Window* targetWindow = (Window*)window->ptr; + return targetWindow->SetMenu (data ? data->b : 0, data ? data->length : 0); + + } + + bool lime_window_set_minimized (value window, bool minimized) { Window* targetWindow = (Window*)val_data (window); @@ -13472,6 +13555,7 @@ namespace lime { DEFINE_PRIME2v (lime_application_set_frame_rate); DEFINE_PRIME5v (lime_application_set_modal_callbacks); DEFINE_PRIME1v (lime_application_defer_modal_exception); + DEFINE_PRIME2 (lime_application_set_menu); DEFINE_PRIME2v (lime_application_set_vsync_mode); DEFINE_PRIME1 (lime_application_update); DEFINE_PRIME2 (lime_audio_load); @@ -13564,6 +13648,8 @@ namespace lime { DEFINE_PRIME0 (lime_locale_get_system_locale); DEFINE_PRIME2 (lime_lzma_compress); DEFINE_PRIME2 (lime_lzma_decompress); + DEFINE_PRIME2v (lime_menu_event_manager_register); + DEFINE_PRIME0 (lime_menu_get_support); DEFINE_PRIME2v (lime_mouse_event_manager_register); DEFINE_PRIME1v (lime_neko_execute); DEFINE_PRIME2v (lime_orientation_event_manager_register); @@ -13721,6 +13807,7 @@ namespace lime { DEFINE_PRIME1 (lime_window_get_x); DEFINE_PRIME1 (lime_window_get_y); DEFINE_PRIME3v (lime_window_move); + DEFINE_PRIME5 (lime_window_popup_menu); DEFINE_PRIME3 (lime_window_read_pixels); DEFINE_PRIME3v (lime_window_resize); DEFINE_PRIME3v (lime_window_set_minimum_size); @@ -13731,6 +13818,7 @@ namespace lime { DEFINE_PRIME2 (lime_window_set_fullscreen); DEFINE_PRIME2v (lime_window_set_icon); DEFINE_PRIME2 (lime_window_set_maximized); + DEFINE_PRIME2 (lime_window_set_menu); DEFINE_PRIME2 (lime_window_set_minimized); DEFINE_PRIME2v (lime_window_set_mouse_lock); DEFINE_PRIME2 (lime_window_set_resizable); @@ -13757,6 +13845,7 @@ namespace lime { #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 _I32) + #define _TMENU_EVENT _OBJ (_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) @@ -13787,6 +13876,7 @@ namespace lime { DEFINE_HL_PRIM (_VOID, hl_application_set_frame_rate, _TCFFIPOINTER _F64); DEFINE_HL_PRIM (_VOID, hl_application_set_modal_callbacks, _TCFFIPOINTER _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG) _FUN(_VOID, _NO_ARG)); DEFINE_HL_PRIM (_VOID, hl_application_defer_modal_exception, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_application_set_menu, _TCFFIPOINTER _TBYTES); DEFINE_HL_PRIM (_VOID, hl_application_set_vsync_mode, _TCFFIPOINTER _I32); DEFINE_HL_PRIM (_BOOL, hl_application_update, _TCFFIPOINTER); DEFINE_HL_PRIM (_TAUDIOBUFFER, hl_audio_load_bytes, _TBYTES _TAUDIOBUFFER); @@ -13878,6 +13968,8 @@ namespace lime { DEFINE_HL_PRIM (_BYTES, hl_locale_get_system_locale, _NO_ARG); DEFINE_HL_PRIM (_TBYTES, hl_lzma_compress, _TBYTES _TBYTES); DEFINE_HL_PRIM (_TBYTES, hl_lzma_decompress, _TBYTES _TBYTES); + DEFINE_HL_PRIM (_VOID, hl_menu_event_manager_register, _FUN (_VOID, _NO_ARG) _TMENU_EVENT); + DEFINE_HL_PRIM (_I32, hl_menu_get_support, _NO_ARG); DEFINE_HL_PRIM (_VOID, hl_mouse_event_manager_register, _FUN (_VOID, _NO_ARG) _TMOUSE_EVENT); // DEFINE_PRIME1v (lime_neko_execute); DEFINE_HL_PRIM (_VOID, hl_orientation_event_manager_register, _FUN (_VOID, _NO_ARG) _TORIENTATION_EVENT); @@ -14035,6 +14127,7 @@ namespace lime { DEFINE_HL_PRIM (_I32, hl_window_get_x, _TCFFIPOINTER); DEFINE_HL_PRIM (_I32, hl_window_get_y, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_window_move, _TCFFIPOINTER _I32 _I32); + DEFINE_HL_PRIM (_I32, hl_window_popup_menu, _TCFFIPOINTER _TBYTES _I32 _I32 _BOOL); DEFINE_HL_PRIM (_DYN, hl_window_read_pixels, _TCFFIPOINTER _TRECTANGLE _TIMAGEBUFFER); DEFINE_HL_PRIM (_VOID, hl_window_resize, _TCFFIPOINTER _I32 _I32); DEFINE_HL_PRIM (_VOID, hl_window_set_minimum_size, _TCFFIPOINTER _I32 _I32); @@ -14045,6 +14138,7 @@ namespace lime { DEFINE_HL_PRIM (_BOOL, hl_window_set_fullscreen, _TCFFIPOINTER _BOOL); DEFINE_HL_PRIM (_VOID, hl_window_set_icon, _TCFFIPOINTER _TIMAGEBUFFER); DEFINE_HL_PRIM (_BOOL, hl_window_set_maximized, _TCFFIPOINTER _BOOL); + DEFINE_HL_PRIM (_BOOL, hl_window_set_menu, _TCFFIPOINTER _TBYTES); DEFINE_HL_PRIM (_BOOL, hl_window_set_minimized, _TCFFIPOINTER _BOOL); DEFINE_HL_PRIM (_VOID, hl_window_set_mouse_lock, _TCFFIPOINTER _BOOL); DEFINE_HL_PRIM (_BOOL, hl_window_set_resizable, _TCFFIPOINTER _BOOL); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index 46adc8b562..a68ce3d953 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -1,6 +1,7 @@ #include "SDLApplication.h" #include "SDLGamepad.h" #include "SDLJoystick.h" +#include "SDLMenu.h" #include #include #include @@ -739,6 +740,11 @@ namespace lime break; #endif + case SDL_SYSWMEVENT: + + ProcessMenuEvent(event); + break; + case SDL_TEXTINPUT: case SDL_TEXTEDITING: @@ -802,6 +808,12 @@ namespace lime active = false; break; + + default: + + // Menu selections queued by SDLMenu use a registered event type + ProcessMenuEvent(event); + break; } } @@ -1086,6 +1098,23 @@ namespace lime } } + void SDLApplication::ProcessMenuEvent(SDL_Event *event) + { + + Uint32 windowID; + int id; + + if (MenuEvent::callback && SDLMenu::GetSelection(event, &windowID, &id)) + { + + menuEvent.type = MENU_SELECT; + menuEvent.id = id; + menuEvent.windowID = windowID; + + MenuEvent::Dispatch(&menuEvent); + } + } + void SDLApplication::ProcessMouseEvent(SDL_Event *event) { @@ -1439,6 +1468,12 @@ namespace lime ApplyMainLoopSettings(); } + bool SDLApplication::SetMenu(const unsigned char *data, int length) + { + + return SDLMenu::SetApplicationMenu(data, length); + } + void SDLApplication::SetVSyncMode(int vsyncMode) { diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index 5103185429..ca878ef268 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ namespace lime { virtual int Quit (); virtual void SetMainLoop (int profile, double frameRate, int timePrecision, int busyWait, int uncapMode); virtual void SetFrameRate (double frameRate); + virtual bool SetMenu (const unsigned char* data, int length); virtual void SetVSyncMode (int vsyncMode); virtual bool Update (); @@ -74,6 +76,7 @@ namespace lime { void ProcessGamepadEvent (SDL_Event* event); void ProcessJoystickEvent (SDL_Event* event); void ProcessKeyEvent (SDL_Event* event); + void ProcessMenuEvent (SDL_Event* event); void ProcessMouseEvent (SDL_Event* event); void ProcessSensorEvent (SDL_Event* event); void ProcessTextEvent (SDL_Event* event); @@ -150,6 +153,7 @@ namespace lime { KeyEvent keyEvent; double lastUpdate; Uint32 lastSleepCalibration; + MenuEvent menuEvent; MouseEvent mouseEvent; bool mouseCaptureRequested; double nextUpdate; diff --git a/project/src/backend/sdl/SDLMenu.cpp b/project/src/backend/sdl/SDLMenu.cpp new file mode 100644 index 0000000000..29f5ec0906 --- /dev/null +++ b/project/src/backend/sdl/SDLMenu.cpp @@ -0,0 +1,209 @@ +#include "SDLMenu.h" + + +namespace lime { + + + // Menu data is written by NativeMenu.hx as little-endian Int32 values: + // + // menu := itemCount, item[itemCount] + // item := id, flags, keyCode, keyModifiers, labelLength, label, [menu if flags & MENU_ITEM_SUBMENU] + // + // Labels are UTF-8, with "&" marking the mnemonic and "&&" for a literal ampersand. + + static const int MAX_MENU_DEPTH = 32; + static Uint32 selectionEventType = 0; + + + static bool ReadInt (const unsigned char* data, int length, int* position, int* result) { + + if (length - *position < 4) return false; + + const unsigned char* bytes = data + *position; + *result = (int)((Uint32)bytes[0] | ((Uint32)bytes[1] << 8) | ((Uint32)bytes[2] << 16) | ((Uint32)bytes[3] << 24)); + *position += 4; + return true; + + } + + + static bool ParseItems (const unsigned char* data, int length, int* position, std::vector* items, int depth) { + + int count; + + if (depth > MAX_MENU_DEPTH || !ReadInt (data, length, position, &count) || count < 0) return false; + + items->resize (count); + + for (int i = 0; i < count; i++) { + + SDLMenuItem* item = &(*items)[i]; + int labelLength; + + if (!ReadInt (data, length, position, &item->id) || !ReadInt (data, length, position, &item->flags) + || !ReadInt (data, length, position, &item->keyCode) || !ReadInt (data, length, position, &item->keyModifiers) + || !ReadInt (data, length, position, &labelLength) || labelLength < 0 || length - *position < labelLength) { + + return false; + + } + + item->label.assign ((const char*)(data + *position), labelLength); + *position += labelLength; + + if ((item->flags & MENU_ITEM_SUBMENU) && !ParseItems (data, length, position, &item->submenu, depth + 1)) { + + return false; + + } + + } + + return true; + + } + + + int Menu::GetSupport () { + + return SDLMenu::GetSupport (); + + } + + + std::string SDLMenu::GetLabel (const std::string& label, char mnemonicPrefix) { + + if (mnemonicPrefix == '&') return label; + + std::string result; + result.reserve (label.size ()); + + for (size_t i = 0; i < label.size (); i++) { + + char c = label[i]; + + if (c == '&') { + + if (i + 1 < label.size () && label[i + 1] == '&') { + + result += '&'; + i++; + + } else if (mnemonicPrefix) { + + result += mnemonicPrefix; + + } + + } else if (mnemonicPrefix && c == mnemonicPrefix) { + + result += mnemonicPrefix; + result += mnemonicPrefix; + + } else { + + result += c; + + } + + } + + return result; + + } + + + bool SDLMenu::GetSelection (SDL_Event* event, Uint32* windowID, int* id) { + + if (selectionEventType != 0 && event->type == selectionEventType) { + + *windowID = event->user.windowID; + *id = event->user.code; + return true; + + } + + return GetPlatformSelection (event, windowID, id); + + } + + + bool SDLMenu::Parse (const unsigned char* data, int length, std::vector* items) { + + int position = 0; + return data && length > 0 && ParseItems (data, length, &position, items, 0); + + } + + + void SDLMenu::PushSelection (Uint32 windowID, int id) { + + if (selectionEventType == 0) { + + selectionEventType = SDL_RegisterEvents (1); + + // SDLApplication treats SDL_USEREVENT as a frame request, so never share it + if (selectionEventType == SDL_USEREVENT) selectionEventType = SDL_RegisterEvents (1); + + if (selectionEventType == (Uint32)-1) { + + selectionEventType = 0; + return; + + } + + } + + SDL_Event event; + SDL_zero (event); + event.type = selectionEventType; + event.user.windowID = windowID; + event.user.code = id; + SDL_PushEvent (&event); + + } + + +#if !defined (LIME_SDL_MENU_WIN32) && !defined (LIME_SDL_MENU_COCOA) && !defined (LIME_SDL_MENU_GTK) + + bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { + + return false; + + } + + + int SDLMenu::GetSupport () { + + return 0; + + } + + + int SDLMenu::Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor) { + + return 0; + + } + + + void SDLMenu::Remove (SDL_Window* window) {} + + + bool SDLMenu::SetApplicationMenu (const unsigned char* data, int length) { + + return false; + + } + + + bool SDLMenu::SetWindowMenu (SDL_Window* window, const unsigned char* data, int length) { + + return false; + + } + +#endif + + +} diff --git a/project/src/backend/sdl/SDLMenu.h b/project/src/backend/sdl/SDLMenu.h new file mode 100644 index 0000000000..4fdc4f7e5e --- /dev/null +++ b/project/src/backend/sdl/SDLMenu.h @@ -0,0 +1,69 @@ +#ifndef LIME_SDL_MENU_H +#define LIME_SDL_MENU_H + + +#include +#include +#include +#include + +#if defined (HX_WINDOWS) && !defined (HX_WINRT) +#define LIME_SDL_MENU_WIN32 +#elif defined (HX_MACOS) +#define LIME_SDL_MENU_COCOA +#elif defined (HX_LINUX) && !defined (HX_ANDROID) && !defined (EMSCRIPTEN) +#define LIME_SDL_MENU_GTK +#endif + + +namespace lime { + + + enum SDLMenuItemFlags { + + MENU_ITEM_ENABLED = 0x01, + MENU_ITEM_CHECKED = 0x02, + MENU_ITEM_SEPARATOR = 0x04, + MENU_ITEM_SUBMENU = 0x08 + + }; + + + struct SDLMenuItem { + + int flags; + int id; + int keyCode; + int keyModifiers; + std::string label; + std::vector submenu; + + }; + + + class SDLMenu { + + public: + + static bool GetSelection (SDL_Event* event, Uint32* windowID, int* id); + static int GetSupport (); + static int Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor); + static void Remove (SDL_Window* window); + static bool SetApplicationMenu (const unsigned char* data, int length); + static bool SetWindowMenu (SDL_Window* window, const unsigned char* data, int length); + + static std::string GetLabel (const std::string& label, char mnemonicPrefix); + static bool Parse (const unsigned char* data, int length, std::vector* items); + static void PushSelection (Uint32 windowID, int id); + + private: + + static bool GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id); + + }; + + +} + + +#endif diff --git a/project/src/backend/sdl/SDLMenuLinux.cpp b/project/src/backend/sdl/SDLMenuLinux.cpp new file mode 100644 index 0000000000..bd9f31185b --- /dev/null +++ b/project/src/backend/sdl/SDLMenuLinux.cpp @@ -0,0 +1,353 @@ +#include "SDLMenu.h" + +#ifdef LIME_SDL_MENU_GTK + +// Lime's SDL backend uses the minimal SDL configuration, so enable the X11 window info explicitly +#ifndef SDL_VIDEO_DRIVER_X11 +#define SDL_VIDEO_DRIVER_X11 1 +#endif + +#include +#include +#include +#include + + +namespace lime { + + + // GTK 3 is loaded at runtime, so Lime has no build or link dependency on it. + // Only popup menus are supported: an SDL window cannot host a GTK menu bar. + + typedef void (*GCallbackFunc) (void); + typedef void (*GtkMenuPositionFunc) (void* menu, int* x, int* y, int* pushIn, void* userData); + + + struct GTKLibrary { + + bool initialized; + bool available; + + void (*gdk_set_allowed_backends) (const char*); + void* (*g_object_ref_sink) (void*); + void (*g_object_unref) (void*); + unsigned long (*g_signal_connect_data) (void*, const char*, GCallbackFunc, void*, void*, int); + void (*gtk_accel_label_set_accel) (void*, unsigned int, int); + void* (*gtk_bin_get_child) (void*); + void* (*gtk_check_menu_item_new_with_mnemonic) (const char*); + void (*gtk_check_menu_item_set_active) (void*, int); + void (*gtk_disable_setlocale) (void); + int (*gtk_events_pending) (void); + int (*gtk_init_check) (int*, char***); + void (*gtk_main) (void); + int (*gtk_main_iteration) (void); + void (*gtk_main_quit) (void); + void* (*gtk_menu_item_new_with_mnemonic) (const char*); + void (*gtk_menu_item_set_submenu) (void*, void*); + void* (*gtk_menu_new) (void); + void (*gtk_menu_popup) (void*, void*, void*, GtkMenuPositionFunc, void*, unsigned int, unsigned int); + void (*gtk_menu_shell_append) (void*, void*); + void* (*gtk_separator_menu_item_new) (void); + void (*gtk_widget_destroy) (void*); + void* (*gtk_widget_get_toplevel) (void*); + int (*gtk_widget_get_visible) (void*); + void (*gtk_widget_set_sensitive) (void*, int); + void (*gtk_widget_show_all) (void*); + int (*XFlush) (void*); + int (*XUngrabPointer) (void*, unsigned long); + + }; + + + struct PopupPosition { + + int x; + int y; + + }; + + + static GTKLibrary gtk; + static int popupSelection = 0; + + + static bool LoadGTK () { + + if (gtk.initialized) return gtk.available; + + gtk.initialized = true; + + void* library = dlopen ("libgtk-3.so.0", RTLD_NOW | RTLD_LOCAL); + + if (!library) return false; + + #define LIME_GTK_REQUIRE(name) gtk.name = (decltype (gtk.name))dlsym (library, #name); if (!gtk.name) return false; + #define LIME_GTK_OPTIONAL(name) gtk.name = (decltype (gtk.name))dlsym (library, #name); + + LIME_GTK_REQUIRE (g_object_ref_sink); + LIME_GTK_REQUIRE (g_object_unref); + LIME_GTK_REQUIRE (g_signal_connect_data); + LIME_GTK_REQUIRE (gtk_bin_get_child); + LIME_GTK_REQUIRE (gtk_check_menu_item_new_with_mnemonic); + LIME_GTK_REQUIRE (gtk_check_menu_item_set_active); + LIME_GTK_REQUIRE (gtk_events_pending); + LIME_GTK_REQUIRE (gtk_init_check); + LIME_GTK_REQUIRE (gtk_main); + LIME_GTK_REQUIRE (gtk_main_iteration); + LIME_GTK_REQUIRE (gtk_main_quit); + LIME_GTK_REQUIRE (gtk_menu_item_new_with_mnemonic); + LIME_GTK_REQUIRE (gtk_menu_item_set_submenu); + LIME_GTK_REQUIRE (gtk_menu_new); + LIME_GTK_REQUIRE (gtk_menu_popup); + LIME_GTK_REQUIRE (gtk_menu_shell_append); + LIME_GTK_REQUIRE (gtk_separator_menu_item_new); + LIME_GTK_REQUIRE (gtk_widget_destroy); + LIME_GTK_REQUIRE (gtk_widget_get_toplevel); + LIME_GTK_REQUIRE (gtk_widget_get_visible); + LIME_GTK_REQUIRE (gtk_widget_set_sensitive); + LIME_GTK_REQUIRE (gtk_widget_show_all); + + LIME_GTK_OPTIONAL (gdk_set_allowed_backends); + LIME_GTK_OPTIONAL (gtk_accel_label_set_accel); + LIME_GTK_OPTIONAL (gtk_disable_setlocale); + LIME_GTK_OPTIONAL (XFlush); + LIME_GTK_OPTIONAL (XUngrabPointer); + + #undef LIME_GTK_REQUIRE + #undef LIME_GTK_OPTIONAL + + // Keep the application's locale, and use the same windowing system as SDL + if (gtk.gtk_disable_setlocale) gtk.gtk_disable_setlocale (); + if (gtk.gdk_set_allowed_backends) gtk.gdk_set_allowed_backends ("x11"); + + if (!gtk.gtk_init_check (NULL, NULL)) return false; + + gtk.available = true; + return true; + + } + + + static unsigned int GetKeyval (int keyCode) { + + // Printable ASCII matches the GDK keysyms (SDL letter keycodes are lowercase) + if (keyCode >= 0x20 && keyCode < 0x7F) return (unsigned int)keyCode; + if (keyCode >= SDLK_F1 && keyCode <= SDLK_F12) return 0xFFBE + (keyCode - SDLK_F1); + if (keyCode >= SDLK_F13 && keyCode <= SDLK_F24) return 0xFFCA + (keyCode - SDLK_F13); + + switch (keyCode) { + + case SDLK_BACKSPACE: return 0xFF08; + case SDLK_TAB: return 0xFF09; + case SDLK_RETURN: return 0xFF0D; + case SDLK_ESCAPE: return 0xFF1B; + case SDLK_HOME: return 0xFF50; + case SDLK_LEFT: return 0xFF51; + case SDLK_UP: return 0xFF52; + case SDLK_RIGHT: return 0xFF53; + case SDLK_DOWN: return 0xFF54; + case SDLK_PAGEUP: return 0xFF55; + case SDLK_PAGEDOWN: return 0xFF56; + case SDLK_END: return 0xFF57; + case SDLK_INSERT: return 0xFF63; + case SDLK_DELETE: return 0xFFFF; + default: return 0; + + } + + } + + + static int GetModifierMask (int keyModifiers) { + + int mask = 0; + + if (keyModifiers & KMOD_SHIFT) mask |= (1 << 0); + if (keyModifiers & KMOD_CTRL) mask |= (1 << 2); + if (keyModifiers & KMOD_ALT) mask |= (1 << 3); + if (keyModifiers & KMOD_GUI) mask |= (1 << 26); + + return mask; + + } + + + static void OnItemActivate (void* widget, void* userData) { + + popupSelection = (int)(intptr_t)userData; + + } + + + static void OnMenuDeactivate (void* widget, void* userData) { + + gtk.gtk_main_quit (); + + } + + + static void PositionMenu (void* menu, int* x, int* y, int* pushIn, void* userData) { + + PopupPosition* position = (PopupPosition*)userData; + *x = position->x; + *y = position->y; + *pushIn = 1; + + } + + + static void AppendMenuItems (void* menu, const std::vector& items) { + + for (size_t i = 0; i < items.size (); i++) { + + const SDLMenuItem& item = items[i]; + bool hasSubmenu = (item.flags & MENU_ITEM_SUBMENU) != 0; + void* widget; + + if ((item.flags & MENU_ITEM_SEPARATOR) && !hasSubmenu) { + + widget = gtk.gtk_separator_menu_item_new (); + + } else { + + std::string label = SDLMenu::GetLabel (item.label, '_'); + + if ((item.flags & MENU_ITEM_CHECKED) && !hasSubmenu) { + + // Setting the active state emits "activate", so connect afterwards + widget = gtk.gtk_check_menu_item_new_with_mnemonic (label.c_str ()); + gtk.gtk_check_menu_item_set_active (widget, 1); + + } else { + + widget = gtk.gtk_menu_item_new_with_mnemonic (label.c_str ()); + + } + + gtk.gtk_widget_set_sensitive (widget, (item.flags & MENU_ITEM_ENABLED) ? 1 : 0); + + if (hasSubmenu) { + + void* submenu = gtk.gtk_menu_new (); + AppendMenuItems (submenu, item.submenu); + gtk.gtk_menu_item_set_submenu (widget, submenu); + + } else { + + unsigned int keyval = item.keyCode != 0 ? GetKeyval (item.keyCode) : 0; + void* accelLabel = keyval && gtk.gtk_accel_label_set_accel ? gtk.gtk_bin_get_child (widget) : NULL; + + if (accelLabel) { + + gtk.gtk_accel_label_set_accel (accelLabel, keyval, GetModifierMask (item.keyModifiers)); + + } + + gtk.g_signal_connect_data (widget, "activate", (GCallbackFunc)OnItemActivate, (void*)(intptr_t)item.id, NULL, 0); + + } + + } + + gtk.gtk_menu_shell_append (menu, widget); + + } + + } + + + bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { + + return false; + + } + + + int SDLMenu::GetSupport () { + + const char* driver = SDL_GetCurrentVideoDriver (); + + if (driver && strcmp (driver, "x11") != 0) return 0; + + return LoadGTK () ? MENU_SUPPORT_POPUP : 0; + + } + + + int SDLMenu::Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor) { + + SDL_SysWMinfo info; + SDL_VERSION (&info.version); + + if (!window || !SDL_GetWindowWMInfo (window, &info) || info.subsystem != SDL_SYSWM_X11) return 0; + + std::vector items; + + if (!Parse (data, length, &items) || !LoadGTK ()) return 0; + + // A pressed mouse button holds an implicit pointer grab on SDL's window, which would stop the menu from taking its own + if (gtk.XUngrabPointer) { + + gtk.XUngrabPointer (info.info.x11.display, 0); + if (gtk.XFlush) gtk.XFlush (info.info.x11.display); + + } + + void* menu = gtk.gtk_menu_new (); + gtk.g_object_ref_sink (menu); + + AppendMenuItems (menu, items); + gtk.gtk_widget_show_all (menu); + gtk.g_signal_connect_data (menu, "deactivate", (GCallbackFunc)OnMenuDeactivate, NULL, NULL, 0); + + PopupPosition position; + SDL_GetWindowPosition (window, &position.x, &position.y); + position.x += x; + position.y += y; + + popupSelection = 0; + + gtk.gtk_menu_popup (menu, NULL, NULL, atCursor ? NULL : PositionMenu, atCursor ? NULL : &position, 0, 0); + + // GTK gives up without emitting "deactivate" if it cannot grab the pointer, so only wait for a menu that opened + if (gtk.gtk_widget_get_visible (gtk.gtk_widget_get_toplevel (menu))) { + + gtk.gtk_main (); + + } + + gtk.gtk_widget_destroy (menu); + gtk.g_object_unref (menu); + + while (gtk.gtk_events_pending ()) { + + gtk.gtk_main_iteration (); + + } + + return popupSelection; + + } + + + void SDLMenu::Remove (SDL_Window* window) {} + + + bool SDLMenu::SetApplicationMenu (const unsigned char* data, int length) { + + return false; + + } + + + bool SDLMenu::SetWindowMenu (SDL_Window* window, const unsigned char* data, int length) { + + return false; + + } + + +} + + +#endif diff --git a/project/src/backend/sdl/SDLMenuMac.mm b/project/src/backend/sdl/SDLMenuMac.mm new file mode 100644 index 0000000000..8f9864757d --- /dev/null +++ b/project/src/backend/sdl/SDLMenuMac.mm @@ -0,0 +1,324 @@ +#include "SDLMenu.h" + +#ifdef LIME_SDL_MENU_COCOA + +#import +#include + +#if __has_feature(objc_arc) +#define LIME_AUTORELEASE(object) (object) +#define LIME_RETAIN(object) (object) +#else +#define LIME_AUTORELEASE(object) [(object) autorelease] +#define LIME_RETAIN(object) [(object) retain] +#endif + + +@interface LimeMenuTarget : NSObject { + + @public + NSInteger highlightedTag; + NSInteger popupSelection; + +} + +- (void)selectApplicationMenuItem:(NSMenuItem*)sender; +- (void)selectPopupMenuItem:(NSMenuItem*)sender; + +@end + + +@implementation LimeMenuTarget + +- (void)selectApplicationMenuItem:(NSMenuItem*)sender { + + // Called while SDL pumps Cocoa events, so queue the selection for SDLApplication + lime::SDLMenu::PushSelection (0, (int)[sender tag]); + +} + +- (void)selectPopupMenuItem:(NSMenuItem*)sender { + + popupSelection = [sender tag]; + +} + +- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item { + + highlightedTag = (item && [item action] == @selector(selectPopupMenuItem:)) ? [item tag] : 0; + +} + +@end + + +namespace lime { + + + // Cocoa has a single menu bar for the application, which SDL fills with a + // default application menu. The first item of a Lime menu becomes the + // application menu, as on other macOS applications. + + static NSMenu* defaultApplicationMenu = nil; + static bool defaultApplicationMenuSaved = false; + static LimeMenuTarget* menuTarget = nil; + + + static LimeMenuTarget* GetMenuTarget () { + + if (!menuTarget) menuTarget = [[LimeMenuTarget alloc] init]; + return menuTarget; + + } + + + static NSWindow* GetNSWindow (SDL_Window* window) { + + if (!window) return nil; + + SDL_SysWMinfo info; + SDL_VERSION (&info.version); + + if (!SDL_GetWindowWMInfo (window, &info) || info.subsystem != SDL_SYSWM_COCOA) return nil; + + return info.info.cocoa.window; + + } + + + static NSString* GetString (const std::string& text) { + + NSString* result = [[NSString alloc] initWithBytes:text.data () length:text.size () encoding:NSUTF8StringEncoding]; + return result ? LIME_AUTORELEASE (result) : @""; + + } + + + static NSString* GetKeyEquivalent (int keyCode) { + + unichar character = 0; + + // Use lowercase characters, since an uppercase key equivalent implies Shift + if (keyCode >= 0x20 && keyCode < 0x7F) { + + character = (unichar)keyCode; + + } else if (keyCode >= SDLK_F1 && keyCode <= SDLK_F12) { + + character = (unichar)(NSF1FunctionKey + (keyCode - SDLK_F1)); + + } else if (keyCode >= SDLK_F13 && keyCode <= SDLK_F24) { + + character = (unichar)(NSF13FunctionKey + (keyCode - SDLK_F13)); + + } else { + + switch (keyCode) { + + case SDLK_BACKSPACE: character = NSBackspaceCharacter; break; + case SDLK_TAB: character = NSTabCharacter; break; + case SDLK_RETURN: character = NSCarriageReturnCharacter; break; + case SDLK_ESCAPE: character = 0x1B; break; + case SDLK_DELETE: character = NSDeleteFunctionKey; break; + case SDLK_HOME: character = NSHomeFunctionKey; break; + case SDLK_END: character = NSEndFunctionKey; break; + case SDLK_PAGEUP: character = NSPageUpFunctionKey; break; + case SDLK_PAGEDOWN: character = NSPageDownFunctionKey; break; + case SDLK_INSERT: character = NSInsertFunctionKey; break; + case SDLK_LEFT: character = NSLeftArrowFunctionKey; break; + case SDLK_RIGHT: character = NSRightArrowFunctionKey; break; + case SDLK_UP: character = NSUpArrowFunctionKey; break; + case SDLK_DOWN: character = NSDownArrowFunctionKey; break; + default: break; + + } + + } + + return character ? [NSString stringWithCharacters:&character length:1] : @""; + + } + + + static NSUInteger GetModifierMask (int keyModifiers) { + + NSUInteger mask = 0; + + if (keyModifiers & KMOD_GUI) mask |= NSEventModifierFlagCommand; + if (keyModifiers & KMOD_SHIFT) mask |= NSEventModifierFlagShift; + if (keyModifiers & KMOD_ALT) mask |= NSEventModifierFlagOption; + if (keyModifiers & KMOD_CTRL) mask |= NSEventModifierFlagControl; + + return mask; + + } + + + static NSMenu* CreateMenu (NSString* title) { + + NSMenu* menu = LIME_AUTORELEASE ([[NSMenu alloc] initWithTitle:title]); + + // Use the enabled state from Lime instead of validating against the responder chain + [menu setAutoenablesItems:NO]; + [menu setDelegate:GetMenuTarget ()]; + + return menu; + + } + + + static void AppendMenuItems (NSMenu* menu, const std::vector& items, SEL action) { + + for (size_t i = 0; i < items.size (); i++) { + + const SDLMenuItem& item = items[i]; + bool hasSubmenu = (item.flags & MENU_ITEM_SUBMENU) != 0; + + if ((item.flags & MENU_ITEM_SEPARATOR) && !hasSubmenu) { + + [menu addItem:[NSMenuItem separatorItem]]; + continue; + + } + + // macOS menus do not use mnemonics + NSString* title = GetString (SDLMenu::GetLabel (item.label, 0)); + NSString* keyEquivalent = (!hasSubmenu && item.keyCode != 0) ? GetKeyEquivalent (item.keyCode) : @""; + + NSMenuItem* menuItem = LIME_AUTORELEASE ([[NSMenuItem alloc] initWithTitle:title action:(hasSubmenu ? NULL : action) keyEquivalent:keyEquivalent]); + + if ([keyEquivalent length] > 0) { + + [menuItem setKeyEquivalentModifierMask:GetModifierMask (item.keyModifiers)]; + + } + + [menuItem setTag:item.id]; + [menuItem setTarget:GetMenuTarget ()]; + [menuItem setEnabled:(item.flags & MENU_ITEM_ENABLED) != 0]; + [menuItem setState:(item.flags & MENU_ITEM_CHECKED) ? NSControlStateValueOn : NSControlStateValueOff]; + + if (hasSubmenu) { + + NSMenu* submenu = CreateMenu (title); + AppendMenuItems (submenu, item.submenu, action); + [menuItem setSubmenu:submenu]; + + } + + [menu addItem:menuItem]; + + } + + } + + + bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { + + return false; + + } + + + int SDLMenu::GetSupport () { + + return MENU_SUPPORT_POPUP | MENU_SUPPORT_APPLICATION; + + } + + + int SDLMenu::Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor) { + + @autoreleasepool { + + NSWindow* nsWindow = GetNSWindow (window); + std::vector items; + + if (!nsWindow || !Parse (data, length, &items)) return 0; + + LimeMenuTarget* target = GetMenuTarget (); + NSMenu* menu = CreateMenu (@""); + AppendMenuItems (menu, items, @selector(selectPopupMenuItem:)); + + NSView* view = [nsWindow contentView]; + NSPoint location; + + if (atCursor || !view) { + + // Screen coordinates, used when no view is given + location = [NSEvent mouseLocation]; + view = nil; + + } else { + + // SDL window coordinates start at the top-left of the content view + location = NSMakePoint (x, [view isFlipped] ? y : NSHeight ([view bounds]) - y); + + } + + target->popupSelection = 0; + target->highlightedTag = 0; + + BOOL selected = [menu popUpMenuPositioningItem:nil atLocation:location inView:view]; + + // The action is normally sent before tracking ends, the highlighted item is a fallback + int result = (int)target->popupSelection; + if (result == 0 && selected) result = (int)target->highlightedTag; + + return result; + + } + + } + + + void SDLMenu::Remove (SDL_Window* window) {} + + + bool SDLMenu::SetApplicationMenu (const unsigned char* data, int length) { + + @autoreleasepool { + + if (!NSApp) return false; + + if (!defaultApplicationMenuSaved) { + + defaultApplicationMenu = LIME_RETAIN ([NSApp mainMenu]); + defaultApplicationMenuSaved = true; + + } + + if (!data || length <= 0) { + + [NSApp setMainMenu:defaultApplicationMenu]; + return true; + + } + + std::vector items; + + if (!Parse (data, length, &items)) return false; + + NSMenu* menu = CreateMenu (@"MainMenu"); + AppendMenuItems (menu, items, @selector(selectApplicationMenuItem:)); + + [NSApp setMainMenu:menu]; + return true; + + } + + } + + + bool SDLMenu::SetWindowMenu (SDL_Window* window, const unsigned char* data, int length) { + + // macOS windows do not have menu bars, use the application menu instead + return false; + + } + + +} + + +#endif diff --git a/project/src/backend/sdl/SDLMenuWindows.cpp b/project/src/backend/sdl/SDLMenuWindows.cpp new file mode 100644 index 0000000000..43f1488871 --- /dev/null +++ b/project/src/backend/sdl/SDLMenuWindows.cpp @@ -0,0 +1,301 @@ +#include "SDLMenu.h" + +#ifdef LIME_SDL_MENU_WIN32 + +#include +#include +#include +#undef CreateWindow + + +namespace lime { + + + struct MenuBar { + + HMENU menu; + Uint32 windowID; + + }; + + + // Keep menu commands clear of the standard dialog command IDs (IDOK, IDCANCEL...) + static const int MENU_COMMAND_BASE = 0x1000; + static const int MENU_COMMAND_MAX = 0xFFFF; + + static std::map menuBars; + + + static HWND GetWindowHandle (SDL_Window* window) { + + if (!window) return NULL; + + SDL_SysWMinfo info; + SDL_VERSION (&info.version); + + if (!SDL_GetWindowWMInfo (window, &info) || info.subsystem != SDL_SYSWM_WINDOWS) return NULL; + + return info.info.win.window; + + } + + + static std::wstring ToWide (const std::string& text) { + + if (text.empty ()) return std::wstring (); + + int size = MultiByteToWideChar (CP_UTF8, 0, text.c_str (), (int)text.size (), NULL, 0); + if (size <= 0) return std::wstring (); + + std::wstring result (size, L'\0'); + MultiByteToWideChar (CP_UTF8, 0, text.c_str (), (int)text.size (), &result[0], size); + return result; + + } + + + static std::string GetKeyEquivalentText (int keyCode, int keyModifiers) { + + const char* keyName = SDL_GetKeyName ((SDL_Keycode)keyCode); + + if (!keyName || !keyName[0]) return std::string (); + + std::string text; + + if (keyModifiers & KMOD_CTRL) text += "Ctrl+"; + if (keyModifiers & KMOD_SHIFT) text += "Shift+"; + if (keyModifiers & KMOD_ALT) text += "Alt+"; + if (keyModifiers & KMOD_GUI) text += "Win+"; + + return text + keyName; + + } + + + static bool AppendMenuItems (HMENU menu, const std::vector& items) { + + for (size_t i = 0; i < items.size (); i++) { + + const SDLMenuItem& item = items[i]; + + UINT itemFlags = MF_STRING; + if (!(item.flags & MENU_ITEM_ENABLED)) itemFlags |= MF_GRAYED; + + if (item.flags & MENU_ITEM_SUBMENU) { + + HMENU submenu = CreatePopupMenu (); + + if (!submenu) return false; + + if (!AppendMenuItems (submenu, item.submenu) || !AppendMenuW (menu, itemFlags | MF_POPUP, (UINT_PTR)submenu, ToWide (item.label).c_str ())) { + + DestroyMenu (submenu); + return false; + + } + + } else if (item.flags & MENU_ITEM_SEPARATOR) { + + AppendMenuW (menu, MF_SEPARATOR, 0, NULL); + + } else { + + std::string label = item.label; + + if (item.keyCode != 0) { + + std::string keyText = GetKeyEquivalentText (item.keyCode, item.keyModifiers); + if (!keyText.empty ()) label += "\t" + keyText; + + } + + if (item.flags & MENU_ITEM_CHECKED) itemFlags |= MF_CHECKED; + + // WM_COMMAND only carries the low word of a menu item identifier + int command = MENU_COMMAND_BASE + item.id; + + if (command > MENU_COMMAND_MAX) { + + command = 0; + itemFlags |= MF_GRAYED; + + } + + AppendMenuW (menu, itemFlags, (UINT_PTR)command, ToWide (label).c_str ()); + + } + + } + + return true; + + } + + + static HMENU CreateMenuFromData (const unsigned char* data, int length, bool popup) { + + std::vector items; + + if (!SDLMenu::Parse (data, length, &items)) return NULL; + + HMENU menu = popup ? CreatePopupMenu () : CreateMenu (); + + if (menu && !AppendMenuItems (menu, items)) { + + DestroyMenu (menu); + return NULL; + + } + + return menu; + + } + + + bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { + + if (event->type != SDL_SYSWMEVENT || !event->syswm.msg || event->syswm.msg->subsystem != SDL_SYSWM_WINDOWS) return false; + + const SDL_SysWMmsg* msg = event->syswm.msg; + + // Menu commands have a zero notification code and no control handle (accelerators use 1) + if (msg->msg.win.msg != WM_COMMAND || HIWORD (msg->msg.win.wParam) != 0 || msg->msg.win.lParam != 0) return false; + + int command = LOWORD (msg->msg.win.wParam); + std::map::iterator it = menuBars.find (msg->msg.win.hwnd); + + if (command <= MENU_COMMAND_BASE || it == menuBars.end ()) return false; + + *windowID = it->second.windowID; + *id = command - MENU_COMMAND_BASE; + return true; + + } + + + int SDLMenu::GetSupport () { + + return MENU_SUPPORT_POPUP | MENU_SUPPORT_WINDOW; + + } + + + int SDLMenu::Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor) { + + HWND hwnd = GetWindowHandle (window); + + if (!hwnd) return 0; + + HMENU menu = CreateMenuFromData (data, length, true); + + if (!menu) return 0; + + POINT point; + + if (atCursor) { + + GetCursorPos (&point); + + } else { + + point.x = x; + point.y = y; + ClientToScreen (hwnd, &point); + + } + + UINT flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON; + flags |= GetSystemMetrics (SM_MENUDROPALIGNMENT) ? TPM_RIGHTALIGN : TPM_LEFTALIGN; + + int command = (int)TrackPopupMenuEx (menu, flags, point.x, point.y, hwnd, NULL); + + DestroyMenu (menu); + return command > MENU_COMMAND_BASE ? command - MENU_COMMAND_BASE : 0; + + } + + + void SDLMenu::Remove (SDL_Window* window) { + + // The attached menu is destroyed along with the window + HWND hwnd = GetWindowHandle (window); + if (hwnd) menuBars.erase (hwnd); + + } + + + bool SDLMenu::SetApplicationMenu (const unsigned char* data, int length) { + + return false; + + } + + + bool SDLMenu::SetWindowMenu (SDL_Window* window, const unsigned char* data, int length) { + + HWND hwnd = GetWindowHandle (window); + + if (!hwnd) return false; + + HMENU menu = NULL; + + if (data && length > 0) { + + menu = CreateMenuFromData (data, length, false); + if (!menu) return false; + + } + + std::map::iterator it = menuBars.find (hwnd); + HMENU previous = (it != menuBars.end ()) ? it->second.menu : NULL; + + Uint32 windowFlags = SDL_GetWindowFlags (window); + bool preserveSize = ((previous != NULL) != (menu != NULL)) && !(windowFlags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED)); + + int width = 0; + int height = 0; + SDL_GetWindowSize (window, &width, &height); + + if (!::SetMenu (hwnd, menu)) { + + if (menu) DestroyMenu (menu); + return false; + + } + + if (previous) DestroyMenu (previous); + + if (menu) { + + MenuBar menuBar; + menuBar.menu = menu; + menuBar.windowID = SDL_GetWindowID (window); + menuBars[hwnd] = menuBar; + + // Menu commands arrive as WM_COMMAND, which SDL only forwards as SDL_SYSWMEVENT + SDL_EventState (SDL_SYSWMEVENT, SDL_ENABLE); + + } else { + + menuBars.erase (hwnd); + + } + + DrawMenuBar (hwnd); + + // Adding or removing the menu bar changes the client area, so restore the previous content size + if (preserveSize && width > 0 && height > 0) { + + SDL_SetWindowSize (window, width, height); + + } + + return true; + + } + + +} + + +#endif diff --git a/project/src/backend/sdl/SDLWindow.cpp b/project/src/backend/sdl/SDLWindow.cpp index ac89fa42cd..d3d27bde5a 100644 --- a/project/src/backend/sdl/SDLWindow.cpp +++ b/project/src/backend/sdl/SDLWindow.cpp @@ -1,6 +1,7 @@ #include "SDLWindow.h" #include "SDLCursor.h" #include "SDLApplication.h" +#include "SDLMenu.h" #include "../../graphics/opengl/OpenGL.h" #include "../../graphics/opengl/OpenGLBindings.h" @@ -565,6 +566,7 @@ namespace lime { RestoreResizeEventHook (sdlWindow); #endif + SDLMenu::Remove (sdlWindow); SDL_DestroyWindow (sdlWindow); sdlWindow = 0; @@ -636,6 +638,7 @@ namespace lime { } + SDLMenu::Remove (sdlWindow); SDL_DestroyWindow (sdlWindow); sdlWindow = 0; @@ -1123,6 +1126,13 @@ namespace lime { } + int SDLWindow::PopupMenu (const unsigned char* data, int length, int x, int y, bool atCursor) { + + return SDLMenu::Popup (sdlWindow, data, length, x, y, atCursor); + + } + + void SDLWindow::ReadPixels (ImageBuffer *buffer, Rectangle *rect) { if (sdlRenderer) { @@ -1434,6 +1444,13 @@ namespace lime { } + bool SDLWindow::SetMenu (const unsigned char* data, int length) { + + return SDLMenu::SetWindowMenu (sdlWindow, data, length); + + } + + bool SDLWindow::SetMinimized (bool minimized) { if (minimized) { diff --git a/project/src/backend/sdl/SDLWindow.h b/project/src/backend/sdl/SDLWindow.h index 9c3c20fddd..db5299fe70 100644 --- a/project/src/backend/sdl/SDLWindow.h +++ b/project/src/backend/sdl/SDLWindow.h @@ -41,6 +41,7 @@ namespace lime { virtual int GetX (); virtual int GetY (); virtual void Move (int x, int y); + virtual int PopupMenu (const unsigned char* data, int length, int x, int y, bool atCursor); virtual void ReadPixels (ImageBuffer *buffer, Rectangle *rect); virtual void Resize (int width, int height); virtual void SetMinimumSize (int width, int height); @@ -51,6 +52,7 @@ namespace lime { virtual bool SetFullscreen (bool fullscreen); virtual void SetIcon (ImageBuffer *imageBuffer); virtual bool SetMaximized (bool maximized); + virtual bool SetMenu (const unsigned char* data, int length); virtual bool SetMinimized (bool minimized); virtual void SetMouseLock (bool mouseLock); virtual void SetOpacity (float opacity); diff --git a/project/src/ui/MenuEvent.cpp b/project/src/ui/MenuEvent.cpp new file mode 100644 index 0000000000..9c00ad83df --- /dev/null +++ b/project/src/ui/MenuEvent.cpp @@ -0,0 +1,64 @@ +#include +#include + + +namespace lime { + + + ValuePointer* MenuEvent::callback = 0; + ValuePointer* MenuEvent::eventObject = 0; + + static int id_id; + static int id_type; + static int id_windowID; + static bool init = false; + + + MenuEvent::MenuEvent () { + + id = 0; + type = MENU_SELECT; + windowID = 0; + + } + + + void MenuEvent::Dispatch (MenuEvent* event) { + + if (MenuEvent::callback) { + + if (MenuEvent::eventObject->IsCFFIValue ()) { + + if (!init) { + + id_id = val_id ("id"); + id_type = val_id ("type"); + id_windowID = val_id ("windowID"); + init = true; + + } + + value object = (value)MenuEvent::eventObject->Get (); + + alloc_field (object, id_id, alloc_int (event->id)); + alloc_field (object, id_type, alloc_int (event->type)); + alloc_field (object, id_windowID, alloc_int (event->windowID)); + + } else { + + MenuEvent* eventObject = (MenuEvent*)MenuEvent::eventObject->Get (); + + eventObject->id = event->id; + eventObject->type = event->type; + eventObject->windowID = event->windowID; + + } + + MenuEvent::callback->Call (); + + } + + } + + +} diff --git a/src/lime/_internal/backend/flash/FlashApplication.hx b/src/lime/_internal/backend/flash/FlashApplication.hx index bc1d5b90d6..b63a23ed48 100644 --- a/src/lime/_internal/backend/flash/FlashApplication.hx +++ b/src/lime/_internal/backend/flash/FlashApplication.hx @@ -8,6 +8,7 @@ import lime.app.FrameProfile; import lime.app.VSyncMode; import lime.media.AudioManager; import lime.system.Orientation; +import lime.ui.Menu; import lime.ui.Window; @:access(lime.app.Application) @@ -46,5 +47,7 @@ class FlashApplication return UNKNOWN; } + public function setMenu(menu:Menu):Void {} + public function setVSyncMode(mode:VSyncMode):Void {} } diff --git a/src/lime/_internal/backend/flash/FlashWindow.hx b/src/lime/_internal/backend/flash/FlashWindow.hx index ad9df272bd..0f079a7e1d 100644 --- a/src/lime/_internal/backend/flash/FlashWindow.hx +++ b/src/lime/_internal/backend/flash/FlashWindow.hx @@ -21,6 +21,7 @@ import lime.graphics.RenderContextAttributes; import lime.math.Rectangle; import lime.ui.KeyCode; import lime.ui.KeyModifier; +import lime.ui.Menu; import lime.ui.MouseButton; import lime.ui.MouseCursor; import lime.ui.MouseWheelMode; @@ -583,6 +584,8 @@ class FlashWindow public function move(x:Int, y:Int):Void {} + public function popupMenu(menu:Menu, x:Null, y:Null):Void {} + public function resize(width:Int, height:Int):Void {} public function setMinSize(width:Int, height:Int):Void {} @@ -614,6 +617,8 @@ class FlashWindow return false; } + public function setMenu(menu:Menu):Void {} + public function setMinimized(value:Bool):Bool { return false; diff --git a/src/lime/_internal/backend/html5/HTML5Application.hx b/src/lime/_internal/backend/html5/HTML5Application.hx index 1ee545a916..59ba437d6c 100644 --- a/src/lime/_internal/backend/html5/HTML5Application.hx +++ b/src/lime/_internal/backend/html5/HTML5Application.hx @@ -18,6 +18,7 @@ import lime.ui.KeyModifier; import lime.ui.Gamepad; import lime.ui.GamepadButton; import lime.ui.Joystick; +import lime.ui.Menu; import lime.ui.Window; @:access(lime._internal.backend.html5.HTML5Window) @@ -470,6 +471,8 @@ class HTML5Application Browser.window.requestAnimationFrame(cast handleApplicationEvent); } + public function setMenu(menu:Menu):Void {} + public function setVSyncMode(mode:VSyncMode):Void {} private function handleKeyEvent(event:KeyboardEvent):Void diff --git a/src/lime/_internal/backend/html5/HTML5Window.hx b/src/lime/_internal/backend/html5/HTML5Window.hx index 6a35b2f796..aa72c41aa3 100644 --- a/src/lime/_internal/backend/html5/HTML5Window.hx +++ b/src/lime/_internal/backend/html5/HTML5Window.hx @@ -30,6 +30,7 @@ import lime.system.System; import lime.system.Clipboard; import lime.ui.Gamepad; import lime.ui.Joystick; +import lime.ui.Menu; import lime.ui.MouseCursor; import lime.ui.MouseWheelMode; import lime.ui.Touch; @@ -1007,6 +1008,8 @@ class HTML5Window public function move(x:Int, y:Int):Void {} + public function popupMenu(menu:Menu, x:Null, y:Null):Void {} + public function readPixels(rect:Rectangle):Image { // TODO: Handle DIV, improve 3D canvas support @@ -1224,6 +1227,8 @@ class HTML5Window return false; } + public function setMenu(menu:Menu):Void {} + public function setMinimized(value:Bool):Bool { return false; diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index 10d3aa0bc6..f3e3c9e5b6 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -28,6 +28,8 @@ import lime.ui.Joystick; import lime.ui.JoystickHatPosition; import lime.ui.KeyCode; import lime.ui.KeyModifier; +import lime.ui.Menu; +import lime.ui.MenuItem; import lime.ui.Touch; import lime.ui.Window; @@ -47,6 +49,7 @@ import lime.ui.Window; @:access(lime.system.Sensor) @:access(lime.ui.Gamepad) @:access(lime.ui.Joystick) +@:access(lime.ui.MenuItem) @:access(lime.ui.Window) class NativeApplication { @@ -57,6 +60,7 @@ class NativeApplication private var gamepadEventInfo = new GamepadEventInfo(); private var joystickEventInfo = new JoystickEventInfo(); private var keyEventInfo = new KeyEventInfo(); + private var menuEventInfo = new MenuEventInfo(); private var orientationEventInfo = new OrientationEventInfo(); private var mouseEventInfo = new MouseEventInfo(); private var renderEventInfo = new RenderEventInfo(RENDER); @@ -75,6 +79,7 @@ class NativeApplication #if android private var deviceOrientationListener:OrientationChangeListener; #end + private var menuItems:Array; private var pauseTimer:Int; private var parent:Application; private var toggleFullscreen:Bool; @@ -132,6 +137,7 @@ class NativeApplication NativeCFFI.lime_gamepad_event_manager_register(handleGamepadEvent, gamepadEventInfo); NativeCFFI.lime_joystick_event_manager_register(handleJoystickEvent, joystickEventInfo); NativeCFFI.lime_key_event_manager_register(handleKeyEvent, keyEventInfo); + NativeCFFI.lime_menu_event_manager_register(handleMenuEvent, menuEventInfo); NativeCFFI.lime_mouse_event_manager_register(handleMouseEvent, mouseEventInfo); NativeCFFI.lime_render_event_manager_register(handleRenderEvent, renderEventInfo); @@ -208,6 +214,25 @@ class NativeApplication #end } + public function setMenu(menu:Menu):Void + { + #if (!macro && lime_cffi) + if (handle == null) return; + + if (menu != null) + { + var items = []; + var data = NativeMenu.encode(menu, items); + menuItems = NativeCFFI.lime_application_set_menu(handle, data) ? items : null; + } + else + { + NativeCFFI.lime_application_set_menu(handle, null); + menuItems = null; + } + #end + } + public function setVSyncMode(mode:VSyncMode):Void { #if (!macro && lime_cffi) @@ -384,6 +409,8 @@ class NativeApplication switch (type) { case KEY_DOWN: + // Key equivalents of the menu bar take priority, like native accelerators + if (window.__backend.handleMenuKeyEquivalent(keyCode, modifier)) return; @:privateAccess window.onKeyDown.__dispatchWithTimestamp(keyEventInfo.timestamp, keyCode, modifier); case KEY_UP: @:privateAccess window.onKeyUp.__dispatchWithTimestamp(keyEventInfo.timestamp, keyCode, modifier); @@ -445,6 +472,25 @@ class NativeApplication } } + private function handleMenuEvent():Void + { + switch (menuEventInfo.type) + { + case MENU_SELECT: + if (menuEventInfo.windowID == 0) + { + // Application menu + var item = NativeMenu.getItem(menuItems, menuEventInfo.id); + if (item != null) item.__select(); + } + else + { + var window = parent.__windowByID.get(menuEventInfo.windowID); + if (window != null) window.__backend.handleMenuSelect(menuEventInfo.id); + } + } + } + private function handleMouseEvent():Void { var window = parent.__windowByID.get(mouseEventInfo.windowID); @@ -921,6 +967,30 @@ class NativeApplication var KEY_UP = 1; } +@:keep /*private*/ class MenuEventInfo +{ + public var id:Int; + public var type:MenuEventType; + public var windowID:Int; + + public function new(type:MenuEventType = null, windowID:Int = 0, id:Int = 0) + { + this.type = type; + this.windowID = windowID; + this.id = id; + } + + public function clone():MenuEventInfo + { + return new MenuEventInfo(type, windowID, id); + } +} + +#if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract MenuEventType(Int) +{ + var MENU_SELECT = 0; +} + @:keep /*private*/ class MouseEventInfo { public var button:Int; diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index a7e2d3d76e..56a4cfb9d3 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -73,6 +73,8 @@ class NativeCFFI @:cffi private static function lime_application_set_frame_rate(handle:Dynamic, value:Float):Void; + @:cffi private static function lime_application_set_menu(handle:Dynamic, data:Dynamic):Bool; + @:cffi private static function lime_application_set_vsync_mode(handle:Dynamic, value:Int):Void; @:cffi private static function lime_application_update(handle:Dynamic):Bool; @@ -271,6 +273,10 @@ class NativeCFFI @:cffi private static function lime_lzma_decompress(data:Dynamic, bytes:Dynamic):Dynamic; + @:cffi private static function lime_menu_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; + + @:cffi private static function lime_menu_get_support():Int; + @:cffi private static function lime_mouse_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; @:cffi private static function lime_neko_execute(module:String):Void; @@ -675,6 +681,8 @@ class NativeCFFI @:cffi private static function lime_window_move(handle:Dynamic, x:Int, y:Int):Void; + @:cffi private static function lime_window_popup_menu(handle:Dynamic, data:Dynamic, x:Int, y:Int, atCursor:Bool):Int; + @:cffi private static function lime_window_read_pixels(handle:Dynamic, rect:Dynamic, imageBuffer:Dynamic):Dynamic; @:cffi private static function lime_window_resize(handle:Dynamic, width:Int, height:Int):Void; @@ -695,6 +703,8 @@ class NativeCFFI @:cffi private static function lime_window_set_maximized(handle:Dynamic, maximized:Bool):Bool; + @:cffi private static function lime_window_set_menu(handle:Dynamic, data:Dynamic):Bool; + @:cffi private static function lime_window_set_minimized(handle:Dynamic, minimized:Bool):Bool; @:cffi private static function lime_window_set_mouse_lock(handle:Dynamic, mouseLock:Bool):Void; @@ -734,6 +744,8 @@ class NativeCFFI private static var lime_application_set_frame_rate = new cpp.CallableFloat->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_set_frame_rate", "odv", false)); + private static var lime_application_set_menu = new cpp.Callablecpp.Object->Bool>(cpp.Prime._loadPrime("lime", "lime_application_set_menu", + "oob", false)); private static var lime_application_set_vsync_mode = new cpp.CallableInt->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_application_set_vsync_mode", "oiv", false)); private static var lime_application_update = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_application_update", "ob", false)); @@ -903,6 +915,9 @@ class NativeCFFI false)); private static var lime_lzma_decompress = new cpp.Callablecpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_lzma_decompress", "ooo", false)); + private static var lime_menu_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_menu_event_manager_register", "oov", false)); + private static var lime_menu_get_support = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_menu_get_support", "i", false)); private static var lime_mouse_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_mouse_event_manager_register", "oov", false)); private static var lime_neko_execute = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_neko_execute", "sv", false)); @@ -1193,6 +1208,8 @@ class NativeCFFI 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)); private static var lime_window_move = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_move", "oiiv", false)); + private static var lime_window_popup_menu = new cpp.Callablecpp.Object->Int->Int->Bool->Int>(cpp.Prime._loadPrime("lime", + "lime_window_popup_menu", "ooiibi", false)); private static var lime_window_read_pixels = new cpp.Callablecpp.Object->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_window_read_pixels", "oooo", false)); private static var lime_window_resize = new cpp.CallableInt->Int->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_resize", "oiiv", false)); @@ -1212,6 +1229,8 @@ class NativeCFFI false)); private static var lime_window_set_maximized = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_maximized", "obb", false)); + private static var lime_window_set_menu = new cpp.Callablecpp.Object->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_menu", "oob", + false)); private static var lime_window_set_minimized = new cpp.CallableBool->Bool>(cpp.Prime._loadPrime("lime", "lime_window_set_minimized", "obb", false)); private static var lime_window_set_mouse_lock = new cpp.CallableBool->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_set_mouse_lock", @@ -1250,6 +1269,7 @@ class NativeCFFI private static var lime_application_set_frame_rate = CFFI.load("lime", "lime_application_set_frame_rate", 2); private static var lime_application_set_modal_callbacks = CFFI.load("lime", "lime_application_set_modal_callbacks", 5); private static var lime_application_defer_modal_exception = CFFI.load("lime", "lime_application_defer_modal_exception", 1); + private static var lime_application_set_menu = CFFI.load("lime", "lime_application_set_menu", 2); private static var lime_application_set_vsync_mode = CFFI.load("lime", "lime_application_set_vsync_mode", 2); private static var lime_application_update = CFFI.load("lime", "lime_application_update", 1); private static var lime_audio_load = CFFI.load("lime", "lime_audio_load", 2); @@ -1347,6 +1367,8 @@ class NativeCFFI private static var lime_key_event_manager_register = CFFI.load("lime", "lime_key_event_manager_register", 2); private static var lime_lzma_compress = CFFI.load("lime", "lime_lzma_compress", 2); private static var lime_lzma_decompress = CFFI.load("lime", "lime_lzma_decompress", 2); + private static var lime_menu_event_manager_register = CFFI.load("lime", "lime_menu_event_manager_register", 2); + private static var lime_menu_get_support = CFFI.load("lime", "lime_menu_get_support", 0); private static var lime_mouse_event_manager_register = CFFI.load("lime", "lime_mouse_event_manager_register", 2); private static var lime_neko_execute = CFFI.load("lime", "lime_neko_execute", 1); private static var lime_orientation_event_manager_register = CFFI.load("lime", "lime_orientation_event_manager_register", 2); @@ -1504,6 +1526,7 @@ class NativeCFFI 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); private static var lime_window_move = CFFI.load("lime", "lime_window_move", 3); + private static var lime_window_popup_menu = CFFI.load("lime", "lime_window_popup_menu", 5); private static var lime_window_read_pixels = CFFI.load("lime", "lime_window_read_pixels", 3); private static var lime_window_resize = CFFI.load("lime", "lime_window_resize", 3); private static var lime_window_set_minimum_size = CFFI.load("lime", "lime_window_set_minimum_size", 3); @@ -1514,6 +1537,7 @@ class NativeCFFI private static var lime_window_set_fullscreen = CFFI.load("lime", "lime_window_set_fullscreen", 2); private static var lime_window_set_icon = CFFI.load("lime", "lime_window_set_icon", 2); private static var lime_window_set_maximized = CFFI.load("lime", "lime_window_set_maximized", 2); + private static var lime_window_set_menu = CFFI.load("lime", "lime_window_set_menu", 2); private static var lime_window_set_minimized = CFFI.load("lime", "lime_window_set_minimized", 2); private static var lime_window_set_mouse_lock = CFFI.load("lime", "lime_window_set_mouse_lock", 2); private static var lime_window_set_opacity = CFFI.load("lime", "lime_window_set_opacity", 2); @@ -1558,6 +1582,11 @@ class NativeCFFI @:hlNative("lime", "hl_application_set_frame_rate") private static function lime_application_set_frame_rate(handle:CFFIPointer, value:Float):Void {} + @:hlNative("lime", "hl_application_set_menu") private static function lime_application_set_menu(handle:CFFIPointer, data:Bytes):Bool + { + return false; + } + @:hlNative("lime", "hl_application_set_vsync_mode") private static function lime_application_set_vsync_mode(handle:CFFIPointer, value:Int):Void {} @:hlNative("lime", "hl_application_update") private static function lime_application_update(handle:CFFIPointer):Bool @@ -1975,6 +2004,14 @@ class NativeCFFI return null; } + @:hlNative("lime", "hl_menu_event_manager_register") private static function lime_menu_event_manager_register(callback:Void->Void, + eventObject:MenuEventInfo):Void {} + + @:hlNative("lime", "hl_menu_get_support") private static function lime_menu_get_support():Int + { + return 0; + } + @:hlNative("lime", "hl_mouse_event_manager_register") private static function lime_mouse_event_manager_register(callback:Void->Void, eventObject:MouseEventInfo):Void {} @@ -2761,6 +2798,11 @@ class NativeCFFI @:hlNative("lime", "hl_window_move") private static function lime_window_move(handle:CFFIPointer, x:Int, y:Int):Void {} + @:hlNative("lime", "hl_window_popup_menu") private static function lime_window_popup_menu(handle:CFFIPointer, data:Bytes, x:Int, y:Int, atCursor:Bool):Int + { + return 0; + } + @:hlNative("lime", "hl_window_read_pixels") private static function lime_window_read_pixels(handle:CFFIPointer, rect:Rectangle, imageBuffer:ImageBuffer):Dynamic { @@ -2795,6 +2837,11 @@ class NativeCFFI return false; } + @:hlNative("lime", "hl_window_set_menu") private static function lime_window_set_menu(handle:CFFIPointer, data:Bytes):Bool + { + return false; + } + @:hlNative("lime", "hl_window_set_minimized") private static function lime_window_set_minimized(handle:CFFIPointer, minimized:Bool):Bool { return false; diff --git a/src/lime/_internal/backend/native/NativeMenu.hx b/src/lime/_internal/backend/native/NativeMenu.hx new file mode 100644 index 0000000000..29b67aa44a --- /dev/null +++ b/src/lime/_internal/backend/native/NativeMenu.hx @@ -0,0 +1,165 @@ +package lime._internal.backend.native; + +import haxe.io.Bytes; +import haxe.io.BytesOutput; +import lime.ui.KeyCode; +import lime.ui.KeyModifier; +import lime.ui.Menu; +import lime.ui.MenuItem; + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime._internal.backend.native.NativeCFFI) +@:access(lime.ui.Menu) +@:access(lime.ui.MenuItem) +class NativeMenu +{ + public static inline var SUPPORT_POPUP:Int = 0x01; + public static inline var SUPPORT_WINDOW:Int = 0x02; + public static inline var SUPPORT_APPLICATION:Int = 0x04; + + /** + Writes the menu as little-endian Int32 values, read by SDLMenu.cpp: + + ``` + menu := itemCount, item[itemCount] + item := id, flags, keyCode, keyModifiers, labelLength, label, [menu if flags & MENU_ITEM_SUBMENU] + ``` + + Labels are UTF-8, with "&" marking the mnemonic and "&&" for a literal + ampersand. Each item is pushed to `items`, so that `id` is its index + 1. + **/ + public static function encode(menu:Menu, items:Array):Bytes + { + var output = new BytesOutput(); + writeMenu(output, menu, items); + return output.getBytes(); + } + + public static function getItem(items:Array, id:Int):MenuItem + { + return (items != null && id > 0 && id <= items.length) ? items[id - 1] : null; + } + + public static function getKeyEquivalentItem(items:Array, keyCode:KeyCode, modifier:KeyModifier):MenuItem + { + if (items == null || keyCode == UNKNOWN) return null; + + var modifiers = getModifierMask(modifier); + + for (item in items) + { + if (item.keyEquivalent == keyCode + && item.submenu == null + && !item.isSeparator + && getModifierMask(item.keyEquivalentModifiers) == modifiers + && isEnabled(item)) + { + return item; + } + } + + return null; + } + + public static function getSupport():Int + { + #if (!macro && lime_cffi) + return NativeCFFI.lime_menu_get_support(); + #else + return 0; + #end + } + + private static function getLabel(item:MenuItem):String + { + var label = item.label; + + if (item.mnemonicIndex < 0 && label.indexOf("&") == -1) + { + return label; + } + + var buffer = new StringBuf(); + + for (i in 0...label.length) + { + if (i == item.mnemonicIndex) buffer.add("&"); + + var char = label.charAt(i); + buffer.add(char == "&" ? "&&" : char); + } + + return buffer.toString(); + } + + private static function getModifierMask(modifier:KeyModifier):Int + { + var mask = 0; + + if (modifier.ctrlKey) mask |= KeyModifier.CTRL; + if (modifier.shiftKey) mask |= KeyModifier.SHIFT; + if (modifier.altKey) mask |= KeyModifier.ALT; + if (modifier.metaKey) mask |= KeyModifier.META; + + return mask; + } + + private static function isEnabled(item:MenuItem):Bool + { + while (item != null) + { + if (!item.enabled) return false; + item = item.menu != null ? item.menu.parent : null; + } + + return true; + } + + private static function writeMenu(output:BytesOutput, menu:Menu, items:Array):Void + { + output.writeInt32(menu.__items.length); + + for (item in menu.__items) + { + items.push(item); + + var flags = 0; + if (item.enabled) flags |= MENU_ITEM_ENABLED; + if (item.checked) flags |= MENU_ITEM_CHECKED; + + if (item.isSeparator) + { + flags |= MENU_ITEM_SEPARATOR; + } + else if (item.submenu != null) + { + flags |= MENU_ITEM_SUBMENU; + } + + var label = Bytes.ofString(getLabel(item)); + + output.writeInt32(items.length); + output.writeInt32(flags); + output.writeInt32(item.keyEquivalent); + output.writeInt32(item.keyEquivalentModifiers); + output.writeInt32(label.length); + output.write(label); + + if (flags & MENU_ITEM_SUBMENU != 0) + { + writeMenu(output, item.submenu, items); + } + } + } +} + +#if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract MenuItemFlags(Int) from Int to Int +{ + var MENU_ITEM_ENABLED = 0x01; + var MENU_ITEM_CHECKED = 0x02; + var MENU_ITEM_SEPARATOR = 0x04; + var MENU_ITEM_SUBMENU = 0x08; +} diff --git a/src/lime/_internal/backend/native/NativeWindow.hx b/src/lime/_internal/backend/native/NativeWindow.hx index 6fc4344a59..0eba1b7865 100644 --- a/src/lime/_internal/backend/native/NativeWindow.hx +++ b/src/lime/_internal/backend/native/NativeWindow.hx @@ -22,6 +22,10 @@ import lime.system.Display; import lime.system.DisplayMode; import lime.system.JNI; import lime.system.System; +import lime.ui.KeyCode; +import lime.ui.KeyModifier; +import lime.ui.Menu; +import lime.ui.MenuItem; import lime.ui.MouseCursor; import lime.ui.Window; import lime.utils.UInt8Array; @@ -38,6 +42,7 @@ import lime.utils.UInt8Array; @:access(lime.graphics.OpenGLRenderContext) @:access(lime.graphics.RenderContext) @:access(lime.system.DisplayMode) +@:access(lime.ui.MenuItem) @:access(lime.ui.Window) class NativeWindow { @@ -47,6 +52,7 @@ class NativeWindow private var cursor:MouseCursor; private var displayMode:DisplayMode; private var frameRate:Float; + private var menuItems:Array; private var mouseLock:Bool; private var parent:Window; private var useHardware:Bool; @@ -343,6 +349,21 @@ class NativeWindow return false; } + public function handleMenuKeyEquivalent(keyCode:KeyCode, modifier:KeyModifier):Bool + { + var item = NativeMenu.getKeyEquivalentItem(menuItems, keyCode, modifier); + if (item == null) return false; + + item.__select(); + return true; + } + + public function handleMenuSelect(id:Int):Void + { + var item = NativeMenu.getItem(menuItems, id); + if (item != null) item.__select(); + } + public function move(x:Int, y:Int):Void { if (handle != null) @@ -353,6 +374,22 @@ class NativeWindow } } + public function popupMenu(menu:Menu, x:Null, y:Null):Void + { + if (handle != null && menu != null) + { + #if (!macro && lime_cffi) + var items = []; + var data = NativeMenu.encode(menu, items); + var atCursor = (x == null || y == null); + var id = NativeCFFI.lime_window_popup_menu(handle, data, atCursor ? 0 : Std.int(x), atCursor ? 0 : Std.int(y), atCursor); + + var item = NativeMenu.getItem(items, id); + if (item != null) item.__select(); + #end + } + } + public function readPixels(rect:Rectangle):Image { var imageBuffer:ImageBuffer = null; @@ -647,6 +684,26 @@ class NativeWindow return value; } + public function setMenu(menu:Menu):Void + { + if (handle != null) + { + #if (!macro && lime_cffi) + if (menu != null) + { + var items = []; + var data = NativeMenu.encode(menu, items); + menuItems = NativeCFFI.lime_window_set_menu(handle, data) ? items : null; + } + else + { + NativeCFFI.lime_window_set_menu(handle, null); + menuItems = null; + } + #end + } + } + public function setMinimized(value:Bool):Bool { if (handle != null) diff --git a/src/lime/app/Application.hx b/src/lime/app/Application.hx index 7c617d01d1..1ded319175 100644 --- a/src/lime/app/Application.hx +++ b/src/lime/app/Application.hx @@ -10,6 +10,7 @@ import lime.ui.Joystick; import lime.ui.JoystickHatPosition; import lime.ui.KeyCode; import lime.ui.KeyModifier; +import lime.ui.Menu; import lime.ui.MouseButton; import lime.ui.MouseWheelMode; import lime.ui.Touch; @@ -27,6 +28,7 @@ import lime.utils.Preloader; @:fileXml('tags="haxe,release"') @:noDebug #end +@:access(lime.ui.Menu) @:access(lime.ui.Window) class Application extends Module { @@ -35,6 +37,15 @@ class Application extends Module **/ public static var current(default, null):Application; + /** + Whether the application has its own menu bar, set using `menu`. + + This is `true` on macOS, where the menu bar belongs to the application + rather than to its windows. Elsewhere, use `Window.menu` when + `Window.supportsMenu` is `true`. + **/ + public static var supportsMenu(get, never):Bool; + /** The device's orientation. **/ @@ -45,6 +56,17 @@ class Application extends Module **/ public var meta:Map; + /** + The menu bar of the application, or `null` for the default menu bar. + + On macOS, the submenu of the first item becomes the application menu, + which is titled with the application name. Other top-level items should + have submenus. Changes to the menu are applied immediately. + + Has no visible effect where `Application.supportsMenu` is `false`. + **/ + public var menu(get, set):Menu; + /** A list of currently attached Module instances **/ @@ -115,6 +137,7 @@ class Application extends Module @:noCompletion private var __frameConfigured:Bool; @:noCompletion private var __frameOptions:FrameOptions; @:noCompletion private var __frameProfile:FrameProfile; + @:noCompletion private var __menu:Menu; @:noCompletion private var __preloader:Preloader; @:noCompletion private var __vsyncMode:VSyncMode; @:noCompletion private var __window:Window; @@ -130,6 +153,7 @@ class Application extends Module { "frameOptions": {get: p.get_frameOptions, set: p.set_frameOptions}, "frameProfile": {get: p.get_frameProfile, set: p.set_frameProfile}, + "menu": {get: p.get_menu, set: p.set_menu}, "preloader": {get: p.get_preloader}, "vsyncMode": {get: p.get_vsyncMode, set: p.set_vsyncMode}, "window": {get: p.get_window}, @@ -610,6 +634,11 @@ class Application extends Module __windowByID.remove(window.id); window.close(); + if (window.__menu != null) + { + @:privateAccess window.__menu.__windows.remove(window); + } + __checkForAllWindowsClosed(); } } @@ -703,6 +732,20 @@ class Application extends Module return __frameProfile; } + @:noCompletion private inline function get_menu():Menu + { + return __menu; + } + + @:noCompletion private static function get_supportsMenu():Bool + { + #if (lime_cffi && !macro) + return (lime._internal.backend.native.NativeMenu.getSupport() & lime._internal.backend.native.NativeMenu.SUPPORT_APPLICATION) != 0; + #else + return false; + #end + } + @:noCompletion private inline function get_window():Window { return __window; @@ -730,6 +773,20 @@ class Application extends Module return __frameProfile; } + @:noCompletion private function set_menu(value:Menu):Menu + { + if (value != __menu) + { + if (__menu != null) __menu.__application = null; + __menu = value; + if (value != null) value.__application = this; + + __backend.setMenu(value); + } + + return value; + } + @:noCompletion private function set_vsyncMode(value:VSyncMode):VSyncMode { __applyFrameConfiguration(__frameProfile, __frameOptions, value, true); diff --git a/src/lime/ui/Menu.hx b/src/lime/ui/Menu.hx new file mode 100644 index 0000000000..eb967ccfb4 --- /dev/null +++ b/src/lime/ui/Menu.hx @@ -0,0 +1,293 @@ +package lime.ui; + +import lime.app.Application; +import lime.app.Event; + +/** + A native menu, displayed as a menu bar or as a context menu using + `popup()`. + + Menus contain `MenuItem` objects, which may in turn hold submenus. Changes + to a menu that is currently displayed are applied to the native menu + immediately. + + Where the menu bar is shown depends on the platform: on Windows each window + has its own menu bar (`Window.menu`), while on macOS the menu bar belongs to + the application (`Application.menu`). + + Example usage: + ```haxe + var fileMenu = new Menu(); + + var openItem = fileMenu.addItem(new MenuItem("Open...")); + openItem.keyEquivalent = KeyCode.O; + openItem.onSelect.add(() -> trace("Open")); + + fileMenu.addSeparator(); + fileMenu.addItem(new MenuItem("Exit")).onSelect.add(() -> window.close()); + + var menuBar = new Menu(); + menuBar.addSubmenu(fileMenu, "File").mnemonicIndex = 0; + + if (Window.supportsMenu) + { + window.menu = menuBar; + } + else if (Application.supportsMenu) + { + application.menu = menuBar; + } + ``` + + Availability note: native menus are implemented on Windows and macOS. On + Linux, context menus are available when GTK 3 is installed and SDL uses X11. + Elsewhere, menus can be created and assigned, but are not displayed. +**/ +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime.app.Application) +@:access(lime.ui.MenuItem) +@:access(lime.ui.Window) +class Menu +{ + /** + Whether any form of native menu is supported on the current platform. + See `Window.supportsMenu` and `Application.supportsMenu` for menu bars. + **/ + public static var isSupported(get, never):Bool; + + /** + A copy of the items in this menu. + **/ + public var items(get, never):Array; + + /** + The number of items in this menu. + **/ + public var numItems(get, never):Int; + + /** + Dispatched when an item in this menu, or in one of its submenus, is + selected. The innermost menu is notified first. Canceling this event + prevents it from reaching the outer menus. + **/ + public var onSelect(default, null) = new EventVoid>(); + + /** + The item that this menu is the submenu of, or `null`. + **/ + public var parent(default, null):MenuItem; + + @:noCompletion private var __application:Application; + @:noCompletion private var __items:Array; + @:noCompletion private var __windows:Array; + + public function new() + { + __items = []; + __windows = []; + } + + /** + Adds an item to the end of the menu. If the item already belongs to a + menu, it is removed from that menu first. + **/ + public function addItem(item:MenuItem):MenuItem + { + return addItemAt(item, __items.length); + } + + /** + Adds an item at the specified index. If the item already belongs to a + menu, it is removed from that menu first. + **/ + public function addItemAt(item:MenuItem, index:Int):MenuItem + { + if (item == null) return null; + + if (item.__submenu != null && __isDescendantOf(item.__submenu)) + { + throw "A menu cannot be a submenu of itself"; + } + + if (item.menu != null) + { + item.menu.removeItem(item); + } + + if (index < 0) index = 0; + if (index > __items.length) index = __items.length; + + __items.insert(index, item); + item.menu = this; + + __update(); + return item; + } + + /** + Adds a separator to the end of the menu. + **/ + public function addSeparator():MenuItem + { + return addItem(new MenuItem("", true)); + } + + /** + Adds an item that displays `submenu` to the end of the menu. + **/ + public function addSubmenu(submenu:Menu, label:String):MenuItem + { + return addSubmenuAt(submenu, __items.length, label); + } + + /** + Adds an item that displays `submenu` at the specified index. + **/ + public function addSubmenuAt(submenu:Menu, index:Int, label:String):MenuItem + { + var item = new MenuItem(label); + item.submenu = submenu; + return addItemAt(item, index); + } + + /** + Whether the item belongs to this menu. + **/ + public function containsItem(item:MenuItem):Bool + { + return item != null && item.menu == this; + } + + /** + Returns the item at the specified index, or `null`. + **/ + public function getItemAt(index:Int):MenuItem + { + return (index >= 0 && index < __items.length) ? __items[index] : null; + } + + /** + Returns the index of the item, or `-1` if it is not in this menu. + **/ + public function getItemIndex(item:MenuItem):Int + { + return __items.indexOf(item); + } + + /** + Displays the menu as a context menu for `window`. + + `x` and `y` are in window coordinates. If either is omitted, the menu + is displayed at the mouse cursor. + + This call blocks until the menu is dismissed, and the `onSelect` events + of the chosen item are dispatched before it returns. To avoid the mouse + button staying pressed, open context menus on mouse up. + **/ + public function popup(window:Window, ?x:Float, ?y:Float):Void + { + if (window != null) + { + window.__backend.popupMenu(this, x, y); + } + } + + /** + Removes all items from the menu. + **/ + public function removeAllItems():Void + { + for (item in __items) + { + item.menu = null; + } + + __items = []; + __update(); + } + + /** + Removes the item from the menu. + **/ + public function removeItem(item:MenuItem):MenuItem + { + var index = __items.indexOf(item); + return index > -1 ? removeItemAt(index) : null; + } + + /** + Removes and returns the item at the specified index, or `null`. + **/ + public function removeItemAt(index:Int):MenuItem + { + if (index < 0 || index >= __items.length) return null; + + var item = __items.splice(index, 1)[0]; + item.menu = null; + + __update(); + return item; + } + + /** + Moves the item to the specified index, adding it to the menu if needed. + **/ + public function setItemIndex(item:MenuItem, index:Int):Void + { + addItemAt(item, index); + } + + @:noCompletion private function __isDescendantOf(menu:Menu):Bool + { + var current = this; + + while (current != null) + { + if (current == menu) return true; + current = current.parent != null ? current.parent.menu : null; + } + + return false; + } + + @:noCompletion private function __update():Void + { + if (__application != null) + { + __application.__backend.setMenu(this); + } + + for (window in __windows) + { + window.__backend.setMenu(this); + } + + if (parent != null) + { + parent.__update(); + } + } + + // Get & Set Methods + @:noCompletion private static function get_isSupported():Bool + { + #if (lime_cffi && !macro) + return lime._internal.backend.native.NativeMenu.getSupport() != 0; + #else + return false; + #end + } + + @:noCompletion private function get_items():Array + { + return __items.copy(); + } + + @:noCompletion private function get_numItems():Int + { + return __items.length; + } +} diff --git a/src/lime/ui/MenuItem.hx b/src/lime/ui/MenuItem.hx new file mode 100644 index 0000000000..99ff788a77 --- /dev/null +++ b/src/lime/ui/MenuItem.hx @@ -0,0 +1,257 @@ +package lime.ui; + +import lime.app.Event; + +/** + An item in a `Menu`. An item may be a command, a separator, or a label for + a nested submenu. + + Changes to an item that is currently displayed are applied to the native + menu immediately. +**/ +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime.ui.Menu) +class MenuItem +{ + /** + Whether a check mark is displayed next to the item. + **/ + public var checked(get, set):Bool; + + /** + Whether the item can be selected. Disabled items are displayed grayed + out, and their key equivalent is ignored. + **/ + public var enabled(get, set):Bool; + + /** + Whether the item is a separator line. Separators cannot be selected. + **/ + public var isSeparator(default, null):Bool; + + /** + A keyboard shortcut that selects the item while its menu is displayed as + a menu bar, or `KeyCode.UNKNOWN` for none. The shortcut is also shown + next to the label, including in context menus. + **/ + public var keyEquivalent(get, set):KeyCode; + + /** + The modifier keys that must be held with `keyEquivalent`. Defaults to + `KeyModifier.CTRL` (`KeyModifier.META` on macOS). Left and right + modifier keys are treated the same. + **/ + public var keyEquivalentModifiers(get, set):KeyModifier; + + /** + The text displayed for the item. + **/ + public var label(get, set):String; + + /** + The menu that contains this item, or `null`. + **/ + public var menu(default, null):Menu; + + /** + The index of the character in `label` that is used for keyboard + navigation (underlined on Windows), or `-1` for none. + **/ + public var mnemonicIndex(get, set):Int; + + /** + Dispatched when the item is selected, before the `onSelect` event of + each menu that contains it. Canceling this event prevents it from + reaching the containing menus. + **/ + public var onSelect(default, null) = new EventVoid>(); + + /** + A menu that is displayed when this item is highlighted, or `null`. + + A menu can only be the submenu of one item at a time. Assigning a menu + that is already a submenu removes it from its previous item. + **/ + public var submenu(get, set):Menu; + + @:noCompletion private var __checked:Bool; + @:noCompletion private var __enabled:Bool; + @:noCompletion private var __keyEquivalent:KeyCode; + @:noCompletion private var __keyEquivalentModifiers:KeyModifier; + @:noCompletion private var __label:String; + @:noCompletion private var __mnemonicIndex:Int; + @:noCompletion private var __submenu:Menu; + + public function new(label:String = "", isSeparator:Bool = false) + { + __label = label != null ? label : ""; + this.isSeparator = isSeparator; + + __checked = false; + __enabled = true; + __keyEquivalent = UNKNOWN; + __keyEquivalentModifiers = #if mac KeyModifier.META #else KeyModifier.CTRL #end; + __mnemonicIndex = -1; + } + + @:noCompletion private function __select():Void + { + onSelect.dispatch(); + if (onSelect.canceled) return; + + var current = menu; + + while (current != null) + { + current.onSelect.dispatch(this); + if (current.onSelect.canceled) break; + + current = current.parent != null ? current.parent.menu : null; + } + } + + @:noCompletion private function __update():Void + { + if (menu != null) menu.__update(); + } + + // Get & Set Methods + @:noCompletion private function get_checked():Bool + { + return __checked; + } + + @:noCompletion private function set_checked(value:Bool):Bool + { + if (value != __checked) + { + __checked = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_enabled():Bool + { + return __enabled; + } + + @:noCompletion private function set_enabled(value:Bool):Bool + { + if (value != __enabled) + { + __enabled = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_keyEquivalent():KeyCode + { + return __keyEquivalent; + } + + @:noCompletion private function set_keyEquivalent(value:KeyCode):KeyCode + { + if (value != __keyEquivalent) + { + __keyEquivalent = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_keyEquivalentModifiers():KeyModifier + { + return __keyEquivalentModifiers; + } + + @:noCompletion private function set_keyEquivalentModifiers(value:KeyModifier):KeyModifier + { + if (value != __keyEquivalentModifiers) + { + __keyEquivalentModifiers = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_label():String + { + return __label; + } + + @:noCompletion private function set_label(value:String):String + { + if (value == null) value = ""; + + if (value != __label) + { + __label = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_mnemonicIndex():Int + { + return __mnemonicIndex; + } + + @:noCompletion private function set_mnemonicIndex(value:Int):Int + { + if (value != __mnemonicIndex) + { + __mnemonicIndex = value; + __update(); + } + + return value; + } + + @:noCompletion private function get_submenu():Menu + { + return __submenu; + } + + @:noCompletion private function set_submenu(value:Menu):Menu + { + if (value == __submenu) return value; + + if (value != null) + { + if (menu != null && menu.__isDescendantOf(value)) + { + throw "A menu cannot be a submenu of itself"; + } + + if (value.parent != null) + { + value.parent.submenu = null; + } + } + + if (__submenu != null) + { + __submenu.parent = null; + } + + __submenu = value; + + if (value != null) + { + value.parent = this; + } + + __update(); + return value; + } +} diff --git a/src/lime/ui/Window.hx b/src/lime/ui/Window.hx index ffae6b7b40..87a2154fb0 100644 --- a/src/lime/ui/Window.hx +++ b/src/lime/ui/Window.hx @@ -27,8 +27,17 @@ typedef Stage = Dynamic; @:fileXml('tags="haxe,release"') @:noDebug #end +@:access(lime.ui.Menu) class Window { + /** + * Whether windows have their own menu bar, set using `menu`. + * + * This is `true` on Windows. On macOS, the menu bar belongs to the + * application instead (see `Application.supportsMenu`). + **/ + public static var supportsMenu(get, never):Bool; + public var application(default, null):Application; public var borderless(get, set):Bool; public var context(default, null):RenderContext; @@ -64,6 +73,19 @@ class Window public var maxHeight(get, set):Int; public var maximized(get, set):Bool; public var maxWidth(get, set):Int; + + /** + * The menu displayed as this window's menu bar, or `null` for none. + * + * Changes to the menu are applied to the menu bar immediately. Adding or + * removing the menu bar keeps the size of the window content the same. + * Menu bar key equivalents are handled before `onKeyDown`, which is not + * dispatched for them. + * + * Has no visible effect where `Window.supportsMenu` is `false`. + **/ + public var menu(get, set):Menu; + public var minHeight(get, set):Int; public var minimized(get, set):Bool; public var minWidth(get, set):Int; @@ -169,6 +191,7 @@ class Window @:noCompletion private var __height:Int; @:noCompletion private var __hidden:Bool; @:noCompletion private var __maximized:Bool; + @:noCompletion private var __menu:Menu; @:noCompletion private var __minimized:Bool; @:noCompletion private var __resizable:Bool; @:noCompletion private var __scale:Float; @@ -199,6 +222,7 @@ class Window "maximized": {get: p.get_maximized, set: p.set_maximized}, "maxWidth": {get: p.get_maxWidth, set: p.set_maxWidth}, + "menu": {get: p.get_menu, set: p.set_menu}, "minHeight": {get: p.get_minHeight, set: p.set_minHeight}, "minimized": {get: p.get_minimized, set: p.set_minimized}, "minWidth": {get: p.get_minWidth, set: p.set_minWidth}, @@ -2712,6 +2736,34 @@ class Window return __maxWidth; } + @:noCompletion private inline function get_menu():Menu + { + return __menu; + } + + @:noCompletion private static function get_supportsMenu():Bool + { + #if (lime_cffi && !macro) + return (lime._internal.backend.native.NativeMenu.getSupport() & lime._internal.backend.native.NativeMenu.SUPPORT_WINDOW) != 0; + #else + return false; + #end + } + + @:noCompletion private function set_menu(value:Menu):Menu + { + if (value != __menu) + { + if (__menu != null) __menu.__windows.remove(this); + __menu = value; + if (value != null) value.__windows.push(this); + + __backend.setMenu(value); + } + + return value; + } + @:noCompletion private inline function get_minHeight():Int { return __minHeight; From 6c0f15cbca252796f8015a4e6c4fff8925333856 Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:39:07 -0400 Subject: [PATCH 110/251] TrayIcon: Add system tray icons Adds lime.ui.TrayIcon with an icon, tooltip, menu and click events, so that OpenFL's SystemTrayIcon can be built on top of it. - Windows uses Shell_NotifyIcon. Right-clicking dispatches onRightClick and then shows the menu, unless the event is canceled. - macOS uses NSStatusItem. When an icon has a menu, clicking it shows the menu, otherwise onClick and onRightClick are dispatched. - Linux uses AppIndicator, loaded at runtime when libayatana-appindicator3 or libappindicator3 is available, and the desktop shows the menu. Menu selections and tray icon events now share one registered SDL event type, and menus update the tray icons that display them. --- project/Build.xml | 1 + project/include/ui/TrayIcon.h | 37 ++ project/include/ui/TrayIconEvent.h | 41 ++ project/src/ExternalInterface.cpp | 190 ++++++++++ project/src/backend/sdl/SDLApplication.cpp | 24 +- project/src/backend/sdl/SDLApplication.h | 3 + project/src/backend/sdl/SDLMenu.cpp | 118 +++++- project/src/backend/sdl/SDLMenu.h | 3 + project/src/backend/sdl/SDLMenuLinux.cpp | 290 ++++++++++++++- project/src/backend/sdl/SDLMenuMac.mm | 244 +++++++++++- project/src/backend/sdl/SDLMenuWindows.cpp | 349 ++++++++++++++++++ project/src/backend/sdl/SDLTrayIcon.h | 37 ++ project/src/ui/TrayIconEvent.cpp | 64 ++++ .../backend/native/NativeApplication.hx | 48 +++ .../_internal/backend/native/NativeCFFI.hx | 77 ++++ .../backend/native/NativeTrayIcon.hx | 172 +++++++++ src/lime/ui/Menu.hx | 8 + src/lime/ui/TrayIcon.hx | 189 ++++++++++ 18 files changed, 1871 insertions(+), 24 deletions(-) create mode 100644 project/include/ui/TrayIcon.h create mode 100644 project/include/ui/TrayIconEvent.h create mode 100644 project/src/backend/sdl/SDLTrayIcon.h create mode 100644 project/src/ui/TrayIconEvent.cpp create mode 100644 src/lime/_internal/backend/native/NativeTrayIcon.hx create mode 100644 src/lime/ui/TrayIcon.hx diff --git a/project/Build.xml b/project/Build.xml index d900bb5d8c..3acca44b92 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -364,6 +364,7 @@ + diff --git a/project/include/ui/TrayIcon.h b/project/include/ui/TrayIcon.h new file mode 100644 index 0000000000..94751e16f6 --- /dev/null +++ b/project/include/ui/TrayIcon.h @@ -0,0 +1,37 @@ +#ifndef LIME_UI_TRAY_ICON_H +#define LIME_UI_TRAY_ICON_H + + +#include + + +namespace lime { + + + class TrayIcon { + + + public: + + virtual ~TrayIcon () {}; + + virtual void Close () = 0; + virtual int GetID () = 0; + virtual int PopupMenu (const unsigned char* data, int length) = 0; + virtual void SetIcon (ImageBuffer* imageBuffer) = 0; + virtual bool SetMenu (const unsigned char* data, int length) = 0; + virtual void SetTooltip (const char* tooltip) = 0; + + static bool IsSupported (); + + + }; + + + TrayIcon* CreateTrayIcon (); + + +} + + +#endif diff --git a/project/include/ui/TrayIconEvent.h b/project/include/ui/TrayIconEvent.h new file mode 100644 index 0000000000..adcbf481c0 --- /dev/null +++ b/project/include/ui/TrayIconEvent.h @@ -0,0 +1,41 @@ +#ifndef LIME_UI_TRAY_ICON_EVENT_H +#define LIME_UI_TRAY_ICON_EVENT_H + + +#include +#include + + +namespace lime { + + + enum TrayIconEventType { + + TRAY_ICON_CLICK, + TRAY_ICON_MENU_SELECT, + TRAY_ICON_RIGHT_CLICK + + }; + + + struct TrayIconEvent { + + hl_type* t; + int id; + int itemID; + TrayIconEventType type; + + static ValuePointer* callback; + static ValuePointer* eventObject; + + TrayIconEvent (); + + static void Dispatch (TrayIconEvent* event); + + }; + + +} + + +#endif diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index f3a171eec1..80e61972a0 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #include #include @@ -1299,6 +1301,22 @@ namespace lime { } + void gc_tray_icon (value handle) { + + TrayIcon* trayIcon = (TrayIcon*)val_data (handle); + delete trayIcon; + + } + + + void hl_gc_tray_icon (HL_CFFIPointer* handle) { + + TrayIcon* trayIcon = (TrayIcon*)handle->ptr; + delete trayIcon; + + } + + void gc_window (value handle) { Window* window = (Window*)val_data (handle); @@ -4603,6 +4621,159 @@ namespace lime { } + void lime_tray_icon_close (value trayIcon) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + targetTrayIcon->Close (); + + } + + + HL_PRIM void HL_NAME(hl_tray_icon_close) (HL_CFFIPointer* trayIcon) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + targetTrayIcon->Close (); + + } + + + value lime_tray_icon_create () { + + TrayIcon* trayIcon = CreateTrayIcon (); + return CFFIPointer (trayIcon, gc_tray_icon); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_tray_icon_create) () { + + TrayIcon* trayIcon = CreateTrayIcon (); + return HLCFFIPointer (trayIcon, (hl_finalizer)hl_gc_tray_icon); + + } + + + void lime_tray_icon_event_manager_register (value callback, value eventObject) { + + TrayIconEvent::callback = new ValuePointer (callback); + TrayIconEvent::eventObject = new ValuePointer (eventObject); + + } + + + HL_PRIM void HL_NAME(hl_tray_icon_event_manager_register) (vclosure* callback, TrayIconEvent* eventObject) { + + TrayIconEvent::callback = new ValuePointer (callback); + TrayIconEvent::eventObject = new ValuePointer ((vobj*)eventObject); + + } + + + int lime_tray_icon_get_id (value trayIcon) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + return targetTrayIcon->GetID (); + + } + + + HL_PRIM int HL_NAME(hl_tray_icon_get_id) (HL_CFFIPointer* trayIcon) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + return targetTrayIcon->GetID (); + + } + + + bool lime_tray_icon_is_supported () { + + return TrayIcon::IsSupported (); + + } + + + HL_PRIM bool HL_NAME(hl_tray_icon_is_supported) () { + + return TrayIcon::IsSupported (); + + } + + + int lime_tray_icon_popup_menu (value trayIcon, value data) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + Bytes bytes (data); + return targetTrayIcon->PopupMenu (bytes.b, bytes.length); + + } + + + HL_PRIM int HL_NAME(hl_tray_icon_popup_menu) (HL_CFFIPointer* trayIcon, Bytes* data) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + return targetTrayIcon->PopupMenu (data ? data->b : 0, data ? data->length : 0); + + } + + + void lime_tray_icon_set_icon (value trayIcon, value buffer) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + + if (val_is_null (buffer)) { + + targetTrayIcon->SetIcon (NULL); + return; + + } + + ImageBuffer imageBuffer = ImageBuffer (buffer); + targetTrayIcon->SetIcon (&imageBuffer); + + } + + + HL_PRIM void HL_NAME(hl_tray_icon_set_icon) (HL_CFFIPointer* trayIcon, ImageBuffer* buffer) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + targetTrayIcon->SetIcon (buffer); + + } + + + bool lime_tray_icon_set_menu (value trayIcon, value data) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + Bytes bytes (data); + return targetTrayIcon->SetMenu (bytes.b, bytes.length); + + } + + + HL_PRIM bool HL_NAME(hl_tray_icon_set_menu) (HL_CFFIPointer* trayIcon, Bytes* data) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + return targetTrayIcon->SetMenu (data ? data->b : 0, data ? data->length : 0); + + } + + + void lime_tray_icon_set_tooltip (value trayIcon, HxString tooltip) { + + TrayIcon* targetTrayIcon = (TrayIcon*)val_data (trayIcon); + targetTrayIcon->SetTooltip (tooltip.c_str ()); + + } + + + HL_PRIM void HL_NAME(hl_tray_icon_set_tooltip) (HL_CFFIPointer* trayIcon, hl_vstring* tooltip) { + + TrayIcon* targetTrayIcon = (TrayIcon*)trayIcon->ptr; + targetTrayIcon->SetTooltip (tooltip ? (const char*)hl_to_utf8 ((const uchar*)tooltip->bytes) : NULL); + + } + + void lime_window_alert (value window, HxString message, HxString title) { Window* targetWindow = (Window*)val_data (window); @@ -13676,6 +13847,15 @@ namespace lime { DEFINE_PRIME2 (lime_system_set_windows_console_mode); DEFINE_PRIME2v (lime_text_event_manager_register); DEFINE_PRIME2v (lime_touch_event_manager_register); + DEFINE_PRIME1v (lime_tray_icon_close); + DEFINE_PRIME0 (lime_tray_icon_create); + DEFINE_PRIME2v (lime_tray_icon_event_manager_register); + DEFINE_PRIME1 (lime_tray_icon_get_id); + DEFINE_PRIME0 (lime_tray_icon_is_supported); + DEFINE_PRIME2 (lime_tray_icon_popup_menu); + DEFINE_PRIME2v (lime_tray_icon_set_icon); + DEFINE_PRIME2 (lime_tray_icon_set_menu); + DEFINE_PRIME2v (lime_tray_icon_set_tooltip); DEFINE_PRIME3v (lime_window_alert); DEFINE_PRIME1v (lime_window_close); DEFINE_PRIME1v (lime_window_context_flip); @@ -13853,6 +14033,7 @@ namespace lime { #define _TSENSOR_EVENT _OBJ (_I32 _F64 _F64 _F64 _I32) #define _TTEXT_EVENT _OBJ (_I32 _I32 _I32 _BYTES _I32 _I32) #define _TTOUCH_EVENT _OBJ (_I32 _F64 _F64 _I32 _F64 _I32 _F64 _F64) + #define _TTRAY_ICON_EVENT _OBJ (_I32 _I32 _I32) #define _TVECTOR2 _OBJ (_F64 _F64) #define _TVORBISFILE _OBJ (_I32 _DYN) #define _TWINDOW_EVENT _OBJ (_I32 _I32 _I32 _I32 _I32 _I32) @@ -13996,6 +14177,15 @@ namespace lime { DEFINE_HL_PRIM (_BOOL, hl_system_set_windows_console_mode, _I32 _I32); DEFINE_HL_PRIM (_VOID, hl_text_event_manager_register, _FUN (_VOID, _NO_ARG) _TTEXT_EVENT); DEFINE_HL_PRIM (_VOID, hl_touch_event_manager_register, _FUN (_VOID, _NO_ARG) _TTOUCH_EVENT); + DEFINE_HL_PRIM (_VOID, hl_tray_icon_close, _TCFFIPOINTER); + DEFINE_HL_PRIM (_TCFFIPOINTER, hl_tray_icon_create, _NO_ARG); + DEFINE_HL_PRIM (_VOID, hl_tray_icon_event_manager_register, _FUN (_VOID, _NO_ARG) _TTRAY_ICON_EVENT); + DEFINE_HL_PRIM (_I32, hl_tray_icon_get_id, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_tray_icon_is_supported, _NO_ARG); + DEFINE_HL_PRIM (_I32, hl_tray_icon_popup_menu, _TCFFIPOINTER _TBYTES); + DEFINE_HL_PRIM (_VOID, hl_tray_icon_set_icon, _TCFFIPOINTER _TIMAGEBUFFER); + DEFINE_HL_PRIM (_BOOL, hl_tray_icon_set_menu, _TCFFIPOINTER _TBYTES); + DEFINE_HL_PRIM (_VOID, hl_tray_icon_set_tooltip, _TCFFIPOINTER _STRING); DEFINE_HL_PRIM (_VOID, hl_window_alert, _TCFFIPOINTER _STRING _STRING); DEFINE_HL_PRIM (_VOID, hl_window_close, _TCFFIPOINTER); DEFINE_HL_PRIM (_VOID, hl_window_context_flip, _TCFFIPOINTER); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index a68ce3d953..a998dc2480 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -2,6 +2,7 @@ #include "SDLGamepad.h" #include "SDLJoystick.h" #include "SDLMenu.h" +#include "SDLTrayIcon.h" #include #include #include @@ -811,8 +812,9 @@ namespace lime default: - // Menu selections queued by SDLMenu use a registered event type + // Menu and tray icon events queued by SDLMenu use a registered event type ProcessMenuEvent(event); + ProcessTrayIconEvent(event); break; } } @@ -1319,6 +1321,24 @@ namespace lime } #endif + void SDLApplication::ProcessTrayIconEvent(SDL_Event *event) + { + + int id; + int type; + int itemID; + + if (TrayIconEvent::callback && SDLMenu::GetTrayIconEvent(event, &id, &type, &itemID)) + { + + trayIconEvent.type = (TrayIconEventType)type; + trayIconEvent.id = id; + trayIconEvent.itemID = itemID; + + TrayIconEvent::Dispatch(&trayIconEvent); + } + } + void SDLApplication::ProcessWindowEvent(SDL_Event *event, bool currentSize) { @@ -1493,6 +1513,8 @@ namespace lime bool SDLApplication::Update() { + SDLTrayIcon::Update(); + #if defined(HX_WINDOWS) && !defined(HX_WINRT) CheckModalException(); #endif diff --git a/project/src/backend/sdl/SDLApplication.h b/project/src/backend/sdl/SDLApplication.h index ca878ef268..3e59f6fd34 100644 --- a/project/src/backend/sdl/SDLApplication.h +++ b/project/src/backend/sdl/SDLApplication.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ namespace lime { void ProcessSensorEvent (SDL_Event* event); void ProcessTextEvent (SDL_Event* event); void ProcessTouchEvent (SDL_Event* event); + void ProcessTrayIconEvent (SDL_Event* event); void ProcessWindowEvent (SDL_Event* event, bool currentSize = false); #if defined(HX_WINDOWS) && !defined(HX_WINRT) bool PrepareResizeEvent (SDL_Event* event, bool currentSize); @@ -176,6 +178,7 @@ namespace lime { double sleepGuardMs; TextEvent textEvent; TouchEvent touchEvent; + TrayIconEvent trayIconEvent; bool useDisplayDrivenFallback; bool useHighResolutionTimer; WindowEvent windowEvent; diff --git a/project/src/backend/sdl/SDLMenu.cpp b/project/src/backend/sdl/SDLMenu.cpp index 29f5ec0906..ed16d4e0ea 100644 --- a/project/src/backend/sdl/SDLMenu.cpp +++ b/project/src/backend/sdl/SDLMenu.cpp @@ -1,4 +1,6 @@ #include "SDLMenu.h" +#include "SDLTrayIcon.h" +#include namespace lime { @@ -11,8 +13,16 @@ namespace lime { // // Labels are UTF-8, with "&" marking the mnemonic and "&&" for a literal ampersand. + enum MenuEventKind { + + MENU_EVENT_SELECTION = 1, + MENU_EVENT_TRAY_ICON = 2 + + }; + + static const int MAX_MENU_DEPTH = 32; - static Uint32 selectionEventType = 0; + static Uint32 menuEventType = 0; static bool ReadInt (const unsigned char* data, int length, int* position, int* result) { @@ -64,6 +74,13 @@ namespace lime { } + TrayIcon* CreateTrayIcon () { + + return new SDLTrayIcon (); + + } + + int Menu::GetSupport () { return SDLMenu::GetSupport (); @@ -115,7 +132,7 @@ namespace lime { bool SDLMenu::GetSelection (SDL_Event* event, Uint32* windowID, int* id) { - if (selectionEventType != 0 && event->type == selectionEventType) { + if (menuEventType != 0 && event->type == menuEventType && (intptr_t)event->user.data1 == MENU_EVENT_SELECTION) { *windowID = event->user.windowID; *id = event->user.code; @@ -128,6 +145,18 @@ namespace lime { } + bool SDLMenu::GetTrayIconEvent (SDL_Event* event, int* trayIconID, int* type, int* itemID) { + + if (menuEventType == 0 || event->type != menuEventType || (intptr_t)event->user.data1 != MENU_EVENT_TRAY_ICON) return false; + + *trayIconID = (int)event->user.windowID; + *type = event->user.code; + *itemID = (int)(intptr_t)event->user.data2; + return true; + + } + + bool SDLMenu::Parse (const unsigned char* data, int length, std::vector* items) { int position = 0; @@ -136,18 +165,18 @@ namespace lime { } - void SDLMenu::PushSelection (Uint32 windowID, int id) { + void SDLMenu::PushEvent (int kind, Uint32 target, int code, int value) { - if (selectionEventType == 0) { + if (menuEventType == 0) { - selectionEventType = SDL_RegisterEvents (1); + menuEventType = SDL_RegisterEvents (1); // SDLApplication treats SDL_USEREVENT as a frame request, so never share it - if (selectionEventType == SDL_USEREVENT) selectionEventType = SDL_RegisterEvents (1); + if (menuEventType == SDL_USEREVENT) menuEventType = SDL_RegisterEvents (1); - if (selectionEventType == (Uint32)-1) { + if (menuEventType == (Uint32)-1) { - selectionEventType = 0; + menuEventType = 0; return; } @@ -156,14 +185,37 @@ namespace lime { SDL_Event event; SDL_zero (event); - event.type = selectionEventType; - event.user.windowID = windowID; - event.user.code = id; + event.type = menuEventType; + event.user.windowID = target; + event.user.code = code; + event.user.data1 = (void*)(intptr_t)kind; + event.user.data2 = (void*)(intptr_t)value; SDL_PushEvent (&event); } + void SDLMenu::PushSelection (Uint32 windowID, int id) { + + PushEvent (MENU_EVENT_SELECTION, windowID, id, 0); + + } + + + void SDLMenu::PushTrayIconEvent (int trayIconID, int type, int itemID) { + + PushEvent (MENU_EVENT_TRAY_ICON, (Uint32)trayIconID, type, itemID); + + } + + + int SDLTrayIcon::GetID () { + + return id; + + } + + #if !defined (LIME_SDL_MENU_WIN32) && !defined (LIME_SDL_MENU_COCOA) && !defined (LIME_SDL_MENU_GTK) bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { @@ -203,6 +255,50 @@ namespace lime { } + + bool TrayIcon::IsSupported () { + + return false; + + } + + + SDLTrayIcon::SDLTrayIcon () { + + id = 0; + platform = 0; + + } + + + SDLTrayIcon::~SDLTrayIcon () {} + + + void SDLTrayIcon::Close () {} + + + int SDLTrayIcon::PopupMenu (const unsigned char* data, int length) { + + return 0; + + } + + + void SDLTrayIcon::SetIcon (ImageBuffer* imageBuffer) {} + + + bool SDLTrayIcon::SetMenu (const unsigned char* data, int length) { + + return false; + + } + + + void SDLTrayIcon::SetTooltip (const char* tooltip) {} + + + void SDLTrayIcon::Update () {} + #endif diff --git a/project/src/backend/sdl/SDLMenu.h b/project/src/backend/sdl/SDLMenu.h index 4fdc4f7e5e..a240f28968 100644 --- a/project/src/backend/sdl/SDLMenu.h +++ b/project/src/backend/sdl/SDLMenu.h @@ -47,6 +47,7 @@ namespace lime { static bool GetSelection (SDL_Event* event, Uint32* windowID, int* id); static int GetSupport (); + static bool GetTrayIconEvent (SDL_Event* event, int* trayIconID, int* type, int* itemID); static int Popup (SDL_Window* window, const unsigned char* data, int length, int x, int y, bool atCursor); static void Remove (SDL_Window* window); static bool SetApplicationMenu (const unsigned char* data, int length); @@ -55,10 +56,12 @@ namespace lime { static std::string GetLabel (const std::string& label, char mnemonicPrefix); static bool Parse (const unsigned char* data, int length, std::vector* items); static void PushSelection (Uint32 windowID, int id); + static void PushTrayIconEvent (int trayIconID, int type, int itemID); private: static bool GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id); + static void PushEvent (int kind, Uint32 target, int code, int value); }; diff --git a/project/src/backend/sdl/SDLMenuLinux.cpp b/project/src/backend/sdl/SDLMenuLinux.cpp index bd9f31185b..8cef23086c 100644 --- a/project/src/backend/sdl/SDLMenuLinux.cpp +++ b/project/src/backend/sdl/SDLMenuLinux.cpp @@ -2,22 +2,34 @@ #ifdef LIME_SDL_MENU_GTK +// Native menus and tray icons for Linux + // Lime's SDL backend uses the minimal SDL configuration, so enable the X11 window info explicitly #ifndef SDL_VIDEO_DRIVER_X11 #define SDL_VIDEO_DRIVER_X11 1 #endif +#include "SDLTrayIcon.h" +#include #include #include #include +#include +#include #include +#include + +#ifdef LIME_PNG +#include +#include +#endif namespace lime { - // GTK 3 is loaded at runtime, so Lime has no build or link dependency on it. - // Only popup menus are supported: an SDL window cannot host a GTK menu bar. + // GTK 3 and AppIndicator are loaded at runtime, so Lime has no build or link dependency on them. + // Popup menus and tray icons are supported: an SDL window cannot host a GTK menu bar. typedef void (*GCallbackFunc) (void); typedef void (*GtkMenuPositionFunc) (void* menu, int* x, int* y, int* pushIn, void* userData); @@ -29,6 +41,7 @@ namespace lime { bool available; void (*gdk_set_allowed_backends) (const char*); + int (*g_main_context_iteration) (void*, int); void* (*g_object_ref_sink) (void*); void (*g_object_unref) (void*); unsigned long (*g_signal_connect_data) (void*, const char*, GCallbackFunc, void*, void*, int); @@ -84,6 +97,7 @@ namespace lime { #define LIME_GTK_REQUIRE(name) gtk.name = (decltype (gtk.name))dlsym (library, #name); if (!gtk.name) return false; #define LIME_GTK_OPTIONAL(name) gtk.name = (decltype (gtk.name))dlsym (library, #name); + LIME_GTK_REQUIRE (g_main_context_iteration); LIME_GTK_REQUIRE (g_object_ref_sink); LIME_GTK_REQUIRE (g_object_unref); LIME_GTK_REQUIRE (g_signal_connect_data); @@ -172,9 +186,19 @@ namespace lime { } + // Menu item callbacks receive the tray icon ID (or zero) in the high bits and the item ID in the low 16 bits + static void OnItemActivate (void* widget, void* userData) { - popupSelection = (int)(intptr_t)userData; + popupSelection = (int)((intptr_t)userData & 0xFFFF); + + } + + + static void OnTrayIconItemActivate (void* widget, void* userData) { + + intptr_t value = (intptr_t)userData; + SDLMenu::PushTrayIconEvent ((int)(value >> 16), TRAY_ICON_MENU_SELECT, (int)(value & 0xFFFF)); } @@ -196,7 +220,7 @@ namespace lime { } - static void AppendMenuItems (void* menu, const std::vector& items) { + static void AppendMenuItems (void* menu, const std::vector& items, GCallbackFunc onActivate, int tag) { for (size_t i = 0; i < items.size (); i++) { @@ -229,7 +253,7 @@ namespace lime { if (hasSubmenu) { void* submenu = gtk.gtk_menu_new (); - AppendMenuItems (submenu, item.submenu); + AppendMenuItems (submenu, item.submenu, onActivate, tag); gtk.gtk_menu_item_set_submenu (widget, submenu); } else { @@ -243,7 +267,8 @@ namespace lime { } - gtk.g_signal_connect_data (widget, "activate", (GCallbackFunc)OnItemActivate, (void*)(intptr_t)item.id, NULL, 0); + intptr_t userData = ((intptr_t)tag << 16) | (item.id & 0xFFFF); + gtk.g_signal_connect_data (widget, "activate", onActivate, (void*)userData, NULL, 0); } @@ -296,7 +321,7 @@ namespace lime { void* menu = gtk.gtk_menu_new (); gtk.g_object_ref_sink (menu); - AppendMenuItems (menu, items); + AppendMenuItems (menu, items, (GCallbackFunc)OnItemActivate, 0); gtk.gtk_widget_show_all (menu); gtk.g_signal_connect_data (menu, "deactivate", (GCallbackFunc)OnMenuDeactivate, NULL, NULL, 0); @@ -347,6 +372,257 @@ namespace lime { } + // Tray icons use AppIndicator, which publishes them to the desktop as StatusNotifierItems over + // D-Bus, with the menu exported by dbusmenu. The desktop shows the menu, and AppIndicator does + // not report clicks on the icon itself. + + struct AppIndicatorLibrary { + + bool initialized; + bool available; + + void* (*app_indicator_new) (const char*, const char*, int); + void (*app_indicator_set_icon_full) (void*, const char*, const char*); + void (*app_indicator_set_menu) (void*, void*); + void (*app_indicator_set_status) (void*, int); + void (*app_indicator_set_title) (void*, const char*); + + }; + + + struct GTKTrayIcon { + + void* indicator; + void* menu; + std::string iconPath; + + }; + + + static const int APP_INDICATOR_CATEGORY_APPLICATION_STATUS = 0; + static const int APP_INDICATOR_STATUS_PASSIVE = 0; + static const int APP_INDICATOR_STATUS_ACTIVE = 1; + + static AppIndicatorLibrary appIndicator; + static int nextTrayIconID = 0; + static int trayIconCount = 0; + + + static bool LoadAppIndicator () { + + if (appIndicator.initialized) return appIndicator.available; + + appIndicator.initialized = true; + + if (!LoadGTK ()) return false; + + void* library = dlopen ("libayatana-appindicator3.so.1", RTLD_NOW | RTLD_LOCAL); + if (!library) library = dlopen ("libappindicator3.so.1", RTLD_NOW | RTLD_LOCAL); + if (!library) return false; + + #define LIME_APP_INDICATOR_REQUIRE(name) appIndicator.name = (decltype (appIndicator.name))dlsym (library, #name); if (!appIndicator.name) return false; + + LIME_APP_INDICATOR_REQUIRE (app_indicator_new); + LIME_APP_INDICATOR_REQUIRE (app_indicator_set_icon_full); + LIME_APP_INDICATOR_REQUIRE (app_indicator_set_menu); + LIME_APP_INDICATOR_REQUIRE (app_indicator_set_status); + LIME_APP_INDICATOR_REQUIRE (app_indicator_set_title); + + #undef LIME_APP_INDICATOR_REQUIRE + + appIndicator.available = true; + return true; + + } + + + static void IterateMainContext () { + + for (int i = 0; i < 64 && gtk.g_main_context_iteration (NULL, 0); i++) {} + + } + + + static std::string WriteIconFile (int id, ImageBuffer* imageBuffer) { + + #ifdef LIME_PNG + + Bytes bytes; + + if (!imageBuffer || !PNG::Encode (imageBuffer, &bytes) || bytes.length <= 0) return std::string (); + + static int counter = 0; + const char* directory = getenv ("XDG_RUNTIME_DIR"); + if (!directory || !directory[0]) directory = "/tmp"; + + // Use a new name for each icon, since the desktop may cache icons by name + char path[1024]; + snprintf (path, sizeof (path), "%s/lime-tray-%d-%d-%d.png", directory, (int)getpid (), id, ++counter); + + FILE* file = fopen (path, "wb"); + if (!file) return std::string (); + + size_t written = fwrite (bytes.b, 1, bytes.length, file); + fclose (file); + + if (written != (size_t)bytes.length) { + + unlink (path); + return std::string (); + + } + + return std::string (path); + + #else + + return std::string (); + + #endif + + } + + + bool TrayIcon::IsSupported () { + + return LoadAppIndicator (); + + } + + + SDLTrayIcon::SDLTrayIcon () { + + id = ++nextTrayIconID; + platform = NULL; + + if (!LoadAppIndicator ()) return; + + char name[64]; + snprintf (name, sizeof (name), "lime-%d-%d", (int)getpid (), id); + + GTKTrayIcon* data = new GTKTrayIcon (); + data->indicator = appIndicator.app_indicator_new (name, "application-x-executable", APP_INDICATOR_CATEGORY_APPLICATION_STATUS); + data->menu = NULL; + platform = data; + trayIconCount++; + + // AppIndicator only shows icons that have a menu + SetMenu (NULL, 0); + appIndicator.app_indicator_set_status (data->indicator, APP_INDICATOR_STATUS_ACTIVE); + IterateMainContext (); + + } + + + SDLTrayIcon::~SDLTrayIcon () { + + Close (); + + } + + + void SDLTrayIcon::Close () { + + GTKTrayIcon* data = (GTKTrayIcon*)platform; + + if (!data) return; + + appIndicator.app_indicator_set_status (data->indicator, APP_INDICATOR_STATUS_PASSIVE); + gtk.g_object_unref (data->indicator); + + if (data->menu) { + + gtk.gtk_widget_destroy (data->menu); + gtk.g_object_unref (data->menu); + + } + + if (!data->iconPath.empty ()) unlink (data->iconPath.c_str ()); + + delete data; + platform = NULL; + trayIconCount--; + + IterateMainContext (); + + } + + + int SDLTrayIcon::PopupMenu (const unsigned char* data, int length) { + + // The desktop shows the menu exported by AppIndicator + return 0; + + } + + + void SDLTrayIcon::SetIcon (ImageBuffer* imageBuffer) { + + GTKTrayIcon* data = (GTKTrayIcon*)platform; + + if (!data) return; + + std::string path = WriteIconFile (id, imageBuffer); + + if (path.empty ()) return; + + appIndicator.app_indicator_set_icon_full (data->indicator, path.c_str (), ""); + + if (!data->iconPath.empty ()) unlink (data->iconPath.c_str ()); + data->iconPath = path; + + } + + + bool SDLTrayIcon::SetMenu (const unsigned char* data, int length) { + + GTKTrayIcon* trayData = (GTKTrayIcon*)platform; + + if (!trayData) return false; + + std::vector items; + + if (data && length > 0 && !SDLMenu::Parse (data, length, &items)) return false; + + void* menu = gtk.gtk_menu_new (); + gtk.g_object_ref_sink (menu); + + AppendMenuItems (menu, items, (GCallbackFunc)OnTrayIconItemActivate, id); + gtk.gtk_widget_show_all (menu); + appIndicator.app_indicator_set_menu (trayData->indicator, menu); + + if (trayData->menu) { + + gtk.gtk_widget_destroy (trayData->menu); + gtk.g_object_unref (trayData->menu); + + } + + trayData->menu = menu; + return true; + + } + + + void SDLTrayIcon::SetTooltip (const char* tooltip) { + + GTKTrayIcon* data = (GTKTrayIcon*)platform; + + if (!data) return; + + appIndicator.app_indicator_set_title (data->indicator, tooltip ? tooltip : ""); + + } + + + void SDLTrayIcon::Update () { + + // AppIndicator communicates over D-Bus, which needs the GLib main context to run + if (trayIconCount > 0) IterateMainContext (); + + } + + } diff --git a/project/src/backend/sdl/SDLMenuMac.mm b/project/src/backend/sdl/SDLMenuMac.mm index 8f9864757d..19bf10ccd0 100644 --- a/project/src/backend/sdl/SDLMenuMac.mm +++ b/project/src/backend/sdl/SDLMenuMac.mm @@ -2,15 +2,26 @@ #ifdef LIME_SDL_MENU_COCOA +// Native menus and tray icons for macOS + #import +#include "SDLTrayIcon.h" +#include #include +#include #if __has_feature(objc_arc) #define LIME_AUTORELEASE(object) (object) #define LIME_RETAIN(object) (object) +#define LIME_BRIDGE(type, pointer) ((__bridge type)(pointer)) +#define LIME_BRIDGE_RETAIN(object) ((void*)CFBridgingRetain (object)) +#define LIME_BRIDGE_RELEASE(pointer) CFRelease ((CFTypeRef)(pointer)) #else #define LIME_AUTORELEASE(object) [(object) autorelease] #define LIME_RETAIN(object) [(object) retain] +#define LIME_BRIDGE(type, pointer) ((type)(pointer)) +#define LIME_BRIDGE_RETAIN(object) ((void*)[(object) retain]) +#define LIME_BRIDGE_RELEASE(pointer) [(NSObject*)(pointer) release] #endif @@ -22,14 +33,25 @@ @interface LimeMenuTarget : NSObject { } +- (void)clickTrayIcon:(id)sender; - (void)selectApplicationMenuItem:(NSMenuItem*)sender; - (void)selectPopupMenuItem:(NSMenuItem*)sender; +- (void)selectTrayIconMenuItem:(NSMenuItem*)sender; @end @implementation LimeMenuTarget +- (void)clickTrayIcon:(id)sender { + + NSEvent* event = [NSApp currentEvent]; + bool rightClick = event && ([event type] == NSEventTypeRightMouseUp || ([event modifierFlags] & NSEventModifierFlagControl)); + + lime::SDLMenu::PushTrayIconEvent ((int)[sender tag], rightClick ? lime::TRAY_ICON_RIGHT_CLICK : lime::TRAY_ICON_CLICK, 0); + +} + - (void)selectApplicationMenuItem:(NSMenuItem*)sender { // Called while SDL pumps Cocoa events, so queue the selection for SDLApplication @@ -43,6 +65,14 @@ - (void)selectPopupMenuItem:(NSMenuItem*)sender { } +- (void)selectTrayIconMenuItem:(NSMenuItem*)sender { + + // Tray icon menu items carry the tray icon ID in the high 32 bits of their tag + NSInteger tag = [sender tag]; + lime::SDLMenu::PushTrayIconEvent ((int)(tag >> 32), lime::TRAY_ICON_MENU_SELECT, (int)(tag & 0xFFFFFFFF)); + +} + - (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item { highlightedTag = (item && [item action] == @selector(selectPopupMenuItem:)) ? [item tag] : 0; @@ -167,7 +197,7 @@ static NSUInteger GetModifierMask (int keyModifiers) { } - static void AppendMenuItems (NSMenu* menu, const std::vector& items, SEL action) { + static void AppendMenuItems (NSMenu* menu, const std::vector& items, SEL action, NSInteger tagBase) { for (size_t i = 0; i < items.size (); i++) { @@ -193,7 +223,7 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items } - [menuItem setTag:item.id]; + [menuItem setTag:(tagBase | item.id)]; [menuItem setTarget:GetMenuTarget ()]; [menuItem setEnabled:(item.flags & MENU_ITEM_ENABLED) != 0]; [menuItem setState:(item.flags & MENU_ITEM_CHECKED) ? NSControlStateValueOn : NSControlStateValueOff]; @@ -201,7 +231,7 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items if (hasSubmenu) { NSMenu* submenu = CreateMenu (title); - AppendMenuItems (submenu, item.submenu, action); + AppendMenuItems (submenu, item.submenu, action, tagBase); [menuItem setSubmenu:submenu]; } @@ -238,7 +268,7 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items LimeMenuTarget* target = GetMenuTarget (); NSMenu* menu = CreateMenu (@""); - AppendMenuItems (menu, items, @selector(selectPopupMenuItem:)); + AppendMenuItems (menu, items, @selector(selectPopupMenuItem:), 0); NSView* view = [nsWindow contentView]; NSPoint location; @@ -300,7 +330,7 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items if (!Parse (data, length, &items)) return false; NSMenu* menu = CreateMenu (@"MainMenu"); - AppendMenuItems (menu, items, @selector(selectApplicationMenuItem:)); + AppendMenuItems (menu, items, @selector(selectApplicationMenuItem:), 0); [NSApp setMainMenu:menu]; return true; @@ -318,6 +348,210 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items } + // Tray icons use NSStatusItem. When an icon has a menu, macOS shows it when the icon is + // clicked, otherwise clicks are reported through the button action. + + static int nextTrayIconID = 0; + + + static NSStatusItem* GetStatusItem (SDLTrayIcon* trayIcon) { + + return trayIcon->platform ? LIME_BRIDGE (NSStatusItem*, trayIcon->platform) : nil; + + } + + + static NSImage* GetTrayImage (NSImage* image) { + + if (!image) return nil; + + CGFloat size = [[NSStatusBar systemStatusBar] thickness] - 4.0; + if (size < 16.0) size = 16.0; + + NSImage* copy = LIME_AUTORELEASE ([image copy]); + NSSize imageSize = [copy size]; + + if (imageSize.width > 0 && imageSize.height > 0) { + + [copy setSize:NSMakeSize (size * imageSize.width / imageSize.height, size)]; + + } + + return copy; + + } + + + bool TrayIcon::IsSupported () { + + return NSApp != nil; + + } + + + SDLTrayIcon::SDLTrayIcon () { + + id = ++nextTrayIconID; + platform = NULL; + + @autoreleasepool { + + NSStatusItem* statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + + if (!statusItem) return; + + NSStatusBarButton* button = [statusItem button]; + [button setImage:GetTrayImage ([NSApp applicationIconImage])]; + [button setTarget:GetMenuTarget ()]; + [button setAction:@selector(clickTrayIcon:)]; + [button setTag:id]; + [button sendActionOn:(NSEventMaskLeftMouseUp | NSEventMaskRightMouseUp)]; + + // The status bar does not keep the item alive + platform = LIME_BRIDGE_RETAIN (statusItem); + + } + + } + + + SDLTrayIcon::~SDLTrayIcon () { + + Close (); + + } + + + void SDLTrayIcon::Close () { + + if (!platform) return; + + @autoreleasepool { + + [[NSStatusBar systemStatusBar] removeStatusItem:GetStatusItem (this)]; + + } + + LIME_BRIDGE_RELEASE (platform); + platform = NULL; + + } + + + int SDLTrayIcon::PopupMenu (const unsigned char* data, int length) { + + if (!platform) return 0; + + @autoreleasepool { + + std::vector items; + + if (!SDLMenu::Parse (data, length, &items)) return 0; + + LimeMenuTarget* target = GetMenuTarget (); + NSMenu* menu = CreateMenu (@""); + AppendMenuItems (menu, items, @selector(selectPopupMenuItem:), 0); + + NSStatusBarButton* button = [GetStatusItem (this) button]; + NSPoint location = NSMakePoint (0, [button isFlipped] ? NSHeight ([button bounds]) + 4.0 : -4.0); + + target->popupSelection = 0; + target->highlightedTag = 0; + + BOOL selected = [menu popUpMenuPositioningItem:nil atLocation:location inView:button]; + + int result = (int)target->popupSelection; + if (result == 0 && selected) result = (int)target->highlightedTag; + + return result; + + } + + } + + + void SDLTrayIcon::SetIcon (ImageBuffer* imageBuffer) { + + if (!platform || !imageBuffer || !imageBuffer->data || !imageBuffer->data->buffer || imageBuffer->width <= 0 || imageBuffer->height <= 0 || imageBuffer->bitsPerPixel != 32) { + + return; + + } + + @autoreleasepool { + + int width = imageBuffer->width; + int height = imageBuffer->height; + + if (imageBuffer->data->buffer->length < imageBuffer->Stride () * height) return; + + NSBitmapImageRep* bitmap = LIME_AUTORELEASE ([[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:NSBitmapFormatAlphaNonpremultiplied bytesPerRow:width * 4 bitsPerPixel:32]); + + if (!bitmap) return; + + const unsigned char* source = imageBuffer->data->buffer->b; + unsigned char* dest = [bitmap bitmapData]; + int stride = imageBuffer->Stride (); + + for (int y = 0; y < height; y++) { + + memcpy (dest + y * width * 4, source + y * stride, width * 4); + + } + + NSImage* image = LIME_AUTORELEASE ([[NSImage alloc] initWithSize:NSMakeSize (width, height)]); + [image addRepresentation:bitmap]; + + [[GetStatusItem (this) button] setImage:GetTrayImage (image)]; + + } + + } + + + bool SDLTrayIcon::SetMenu (const unsigned char* data, int length) { + + if (!platform) return false; + + @autoreleasepool { + + NSStatusItem* statusItem = GetStatusItem (this); + std::vector items; + + if (!data || length <= 0 || !SDLMenu::Parse (data, length, &items)) { + + [statusItem setMenu:nil]; + return false; + + } + + NSMenu* menu = CreateMenu (@""); + AppendMenuItems (menu, items, @selector(selectTrayIconMenuItem:), (NSInteger)id << 32); + + [statusItem setMenu:menu]; + return true; + + } + + } + + + void SDLTrayIcon::SetTooltip (const char* tooltip) { + + if (!platform) return; + + @autoreleasepool { + + [[GetStatusItem (this) button] setToolTip:GetString (tooltip ? std::string (tooltip) : std::string ())]; + + } + + } + + + void SDLTrayIcon::Update () {} + + } diff --git a/project/src/backend/sdl/SDLMenuWindows.cpp b/project/src/backend/sdl/SDLMenuWindows.cpp index 43f1488871..25b5134f3a 100644 --- a/project/src/backend/sdl/SDLMenuWindows.cpp +++ b/project/src/backend/sdl/SDLMenuWindows.cpp @@ -2,9 +2,16 @@ #ifdef LIME_SDL_MENU_WIN32 +// Native menus and tray icons for Windows + +#include "SDLTrayIcon.h" +#include #include #include +#include +#include #include +#include #undef CreateWindow @@ -295,6 +302,348 @@ namespace lime { } + bool TrayIcon::IsSupported () { + + return true; + + } + + + // Tray icons use Shell_NotifyIcon, with a hidden window that receives their notifications + // and owns their context menus. It is a top-level window (not message-only) so that it can + // take the foreground, which a tray context menu needs to close when clicking elsewhere. + + struct Win32TrayIcon { + + HICON icon; + POINT anchor; + bool hasAnchor; + std::wstring tooltip; + + }; + + + static const UINT TRAY_ICON_MESSAGE = WM_APP + 1; + static const wchar_t* TRAY_ICON_WINDOW_CLASS = L"LimeTrayIconWindow"; + + static int nextTrayIconID = 0; + static UINT taskbarCreatedMessage = 0; + static HWND trayIconWindow = NULL; + static std::map trayIcons; + + + static bool UpdateNotifyIcon (SDLTrayIcon* trayIcon, DWORD action); + + + static LRESULT CALLBACK TrayIconWindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + + if (message == TRAY_ICON_MESSAGE) { + + // With NOTIFYICON_VERSION_4, the event is in the low word and the icon ID in the high word + int id = HIWORD (lParam); + std::map::iterator it = trayIcons.find (id); + + if (it != trayIcons.end () && it->second->platform) { + + Win32TrayIcon* data = (Win32TrayIcon*)it->second->platform; + + switch (LOWORD (lParam)) { + + case NIN_SELECT: + case NIN_KEYSELECT: + + SDLMenu::PushTrayIconEvent (id, TRAY_ICON_CLICK, 0); + break; + + case WM_CONTEXTMENU: + + data->anchor.x = GET_X_LPARAM (wParam); + data->anchor.y = GET_Y_LPARAM (wParam); + data->hasAnchor = true; + SDLMenu::PushTrayIconEvent (id, TRAY_ICON_RIGHT_CLICK, 0); + break; + + default: break; + + } + + } + + return 0; + + } + + if (taskbarCreatedMessage != 0 && message == taskbarCreatedMessage) { + + // Explorer restarted, so the icons have to be added again + for (std::map::iterator it = trayIcons.begin (); it != trayIcons.end (); ++it) { + + UpdateNotifyIcon (it->second, NIM_ADD); + + } + + return 0; + + } + + return DefWindowProcW (hwnd, message, wParam, lParam); + + } + + + static HWND GetTrayIconWindow () { + + if (trayIconWindow) return trayIconWindow; + + HINSTANCE instance = NULL; + GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)&TrayIconWindowProc, &instance); + + WNDCLASSEXW windowClass; + ZeroMemory (&windowClass, sizeof (windowClass)); + windowClass.cbSize = sizeof (windowClass); + windowClass.lpfnWndProc = TrayIconWindowProc; + windowClass.hInstance = instance; + windowClass.lpszClassName = TRAY_ICON_WINDOW_CLASS; + RegisterClassExW (&windowClass); + + trayIconWindow = CreateWindowExW (WS_EX_TOOLWINDOW, TRAY_ICON_WINDOW_CLASS, L"", WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance, NULL); + taskbarCreatedMessage = RegisterWindowMessageW (L"TaskbarCreated"); + + return trayIconWindow; + + } + + + static HICON GetDefaultIcon () { + + int size = GetSystemMetrics (SM_CXSMICON); + + // Lime executables embed the application icon as resource 1 + HICON icon = (HICON)LoadImageW (GetModuleHandleW (NULL), MAKEINTRESOURCEW (1), IMAGE_ICON, size, size, LR_SHARED); + return icon ? icon : LoadIcon (NULL, IDI_APPLICATION); + + } + + + static HICON CreateIconFromImage (ImageBuffer* imageBuffer) { + + if (!imageBuffer || !imageBuffer->data || !imageBuffer->data->buffer || imageBuffer->width <= 0 || imageBuffer->height <= 0 || imageBuffer->bitsPerPixel != 32) { + + return NULL; + + } + + int width = imageBuffer->width; + int height = imageBuffer->height; + + if (imageBuffer->data->buffer->length < imageBuffer->Stride () * height) return NULL; + + BITMAPV5HEADER header; + ZeroMemory (&header, sizeof (header)); + header.bV5Size = sizeof (header); + header.bV5Width = width; + header.bV5Height = -height; + header.bV5Planes = 1; + header.bV5BitCount = 32; + header.bV5Compression = BI_BITFIELDS; + header.bV5RedMask = 0x00FF0000; + header.bV5GreenMask = 0x0000FF00; + header.bV5BlueMask = 0x000000FF; + header.bV5AlphaMask = 0xFF000000; + + void* bits = NULL; + HDC dc = GetDC (NULL); + HBITMAP color = CreateDIBSection (dc, (BITMAPINFO*)&header, DIB_RGB_COLORS, &bits, NULL, 0); + ReleaseDC (NULL, dc); + + if (!color) return NULL; + + // Lime images are RGBA, Windows bitmaps are BGRA + const unsigned char* source = imageBuffer->data->buffer->b; + unsigned char* dest = (unsigned char*)bits; + int stride = imageBuffer->Stride (); + + for (int y = 0; y < height; y++) { + + const unsigned char* sourceRow = source + y * stride; + unsigned char* destRow = dest + y * width * 4; + + for (int x = 0; x < width; x++) { + + destRow[x * 4 + 0] = sourceRow[x * 4 + 2]; + destRow[x * 4 + 1] = sourceRow[x * 4 + 1]; + destRow[x * 4 + 2] = sourceRow[x * 4 + 0]; + destRow[x * 4 + 3] = sourceRow[x * 4 + 3]; + + } + + } + + // The alpha channel is used for transparency, so the mask only needs to exist + std::vector maskBits (((width + 15) / 16) * 2 * height, 0); + HBITMAP mask = CreateBitmap (width, height, 1, 1, &maskBits[0]); + + ICONINFO info; + info.fIcon = TRUE; + info.xHotspot = 0; + info.yHotspot = 0; + info.hbmMask = mask; + info.hbmColor = color; + + HICON icon = CreateIconIndirect (&info); + + DeleteObject (mask); + DeleteObject (color); + return icon; + + } + + + static bool UpdateNotifyIcon (SDLTrayIcon* trayIcon, DWORD action) { + + Win32TrayIcon* data = (Win32TrayIcon*)trayIcon->platform; + + if (!data) return false; + + NOTIFYICONDATAW notifyIcon; + ZeroMemory (¬ifyIcon, sizeof (notifyIcon)); + notifyIcon.cbSize = sizeof (notifyIcon); + notifyIcon.hWnd = GetTrayIconWindow (); + notifyIcon.uID = trayIcon->id; + notifyIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_SHOWTIP; + notifyIcon.uCallbackMessage = TRAY_ICON_MESSAGE; + notifyIcon.hIcon = data->icon ? data->icon : GetDefaultIcon (); + wcsncpy_s (notifyIcon.szTip, data->tooltip.c_str (), _TRUNCATE); + + if (!Shell_NotifyIconW (action, ¬ifyIcon)) return false; + + if (action == NIM_ADD) { + + notifyIcon.uVersion = NOTIFYICON_VERSION_4; + Shell_NotifyIconW (NIM_SETVERSION, ¬ifyIcon); + + } + + return true; + + } + + + SDLTrayIcon::SDLTrayIcon () { + + id = ++nextTrayIconID; + + Win32TrayIcon* data = new Win32TrayIcon (); + data->icon = NULL; + data->hasAnchor = false; + platform = data; + + trayIcons[id] = this; + UpdateNotifyIcon (this, NIM_ADD); + + } + + + SDLTrayIcon::~SDLTrayIcon () { + + Close (); + + } + + + void SDLTrayIcon::Close () { + + Win32TrayIcon* data = (Win32TrayIcon*)platform; + + if (!data) return; + + NOTIFYICONDATAW notifyIcon; + ZeroMemory (¬ifyIcon, sizeof (notifyIcon)); + notifyIcon.cbSize = sizeof (notifyIcon); + notifyIcon.hWnd = GetTrayIconWindow (); + notifyIcon.uID = id; + Shell_NotifyIconW (NIM_DELETE, ¬ifyIcon); + + if (data->icon) DestroyIcon (data->icon); + + delete data; + platform = NULL; + trayIcons.erase (id); + + } + + + int SDLTrayIcon::PopupMenu (const unsigned char* data, int length) { + + Win32TrayIcon* trayData = (Win32TrayIcon*)platform; + + if (!trayData) return 0; + + HMENU menu = CreateMenuFromData (data, length, true); + + if (!menu) return 0; + + HWND hwnd = GetTrayIconWindow (); + POINT point = trayData->anchor; + + if (!trayData->hasAnchor) GetCursorPos (&point); + trayData->hasAnchor = false; + + // Without the foreground, the menu would stay open when clicking elsewhere + SetForegroundWindow (hwnd); + + UINT flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_BOTTOMALIGN; + flags |= GetSystemMetrics (SM_MENUDROPALIGNMENT) ? TPM_RIGHTALIGN : TPM_LEFTALIGN; + + int command = (int)TrackPopupMenuEx (menu, flags, point.x, point.y, hwnd, NULL); + + // Lets the menu close properly after it is dismissed (see TrackPopupMenu) + PostMessageW (hwnd, WM_NULL, 0, 0); + + DestroyMenu (menu); + return command > MENU_COMMAND_BASE ? command - MENU_COMMAND_BASE : 0; + + } + + + void SDLTrayIcon::SetIcon (ImageBuffer* imageBuffer) { + + Win32TrayIcon* data = (Win32TrayIcon*)platform; + + if (!data) return; + + HICON previous = data->icon; + data->icon = CreateIconFromImage (imageBuffer); + UpdateNotifyIcon (this, NIM_MODIFY); + + if (previous) DestroyIcon (previous); + + } + + + bool SDLTrayIcon::SetMenu (const unsigned char* data, int length) { + + // The menu is shown by PopupMenu when the icon is right-clicked + return false; + + } + + + void SDLTrayIcon::SetTooltip (const char* tooltip) { + + Win32TrayIcon* data = (Win32TrayIcon*)platform; + + if (!data) return; + + data->tooltip = ToWide (tooltip ? std::string (tooltip) : std::string ()); + UpdateNotifyIcon (this, NIM_MODIFY); + + } + + + void SDLTrayIcon::Update () {} + + } diff --git a/project/src/backend/sdl/SDLTrayIcon.h b/project/src/backend/sdl/SDLTrayIcon.h new file mode 100644 index 0000000000..0f39932566 --- /dev/null +++ b/project/src/backend/sdl/SDLTrayIcon.h @@ -0,0 +1,37 @@ +#ifndef LIME_SDL_TRAY_ICON_H +#define LIME_SDL_TRAY_ICON_H + + +#include +#include + + +namespace lime { + + + class SDLTrayIcon : public TrayIcon { + + public: + + SDLTrayIcon (); + ~SDLTrayIcon (); + + virtual void Close (); + virtual int GetID (); + virtual int PopupMenu (const unsigned char* data, int length); + virtual void SetIcon (ImageBuffer* imageBuffer); + virtual bool SetMenu (const unsigned char* data, int length); + virtual void SetTooltip (const char* tooltip); + + static void Update (); + + int id; + void* platform; + + }; + + +} + + +#endif diff --git a/project/src/ui/TrayIconEvent.cpp b/project/src/ui/TrayIconEvent.cpp new file mode 100644 index 0000000000..5c8e2b3e77 --- /dev/null +++ b/project/src/ui/TrayIconEvent.cpp @@ -0,0 +1,64 @@ +#include +#include + + +namespace lime { + + + ValuePointer* TrayIconEvent::callback = 0; + ValuePointer* TrayIconEvent::eventObject = 0; + + static int id_id; + static int id_itemID; + static int id_type; + static bool init = false; + + + TrayIconEvent::TrayIconEvent () { + + id = 0; + itemID = 0; + type = TRAY_ICON_CLICK; + + } + + + void TrayIconEvent::Dispatch (TrayIconEvent* event) { + + if (TrayIconEvent::callback) { + + if (TrayIconEvent::eventObject->IsCFFIValue ()) { + + if (!init) { + + id_id = val_id ("id"); + id_itemID = val_id ("itemID"); + id_type = val_id ("type"); + init = true; + + } + + value object = (value)TrayIconEvent::eventObject->Get (); + + alloc_field (object, id_id, alloc_int (event->id)); + alloc_field (object, id_itemID, alloc_int (event->itemID)); + alloc_field (object, id_type, alloc_int (event->type)); + + } else { + + TrayIconEvent* eventObject = (TrayIconEvent*)TrayIconEvent::eventObject->Get (); + + eventObject->id = event->id; + eventObject->itemID = event->itemID; + eventObject->type = event->type; + + } + + TrayIconEvent::callback->Call (); + + } + + } + + +} diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index f3e3c9e5b6..f28f94cdc3 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -67,6 +67,7 @@ class NativeApplication private var sensorEventInfo = new SensorEventInfo(); private var textEventInfo = new TextEventInfo(); private var touchEventInfo = new TouchEventInfo(); + private var trayIconEventInfo = new TrayIconEventInfo(); private var unusedTouchesPool = new List(); private var windowEventInfo = new WindowEventInfo(); #if (windows && !winrt) @@ -143,6 +144,7 @@ class NativeApplication NativeCFFI.lime_text_event_manager_register(handleTextEvent, textEventInfo); NativeCFFI.lime_touch_event_manager_register(handleTouchEvent, touchEventInfo); + NativeCFFI.lime_tray_icon_event_manager_register(handleTrayIconEvent, trayIconEventInfo); NativeCFFI.lime_window_event_manager_register(handleWindowEvent, windowEventInfo); #if (windows && !winrt) NativeCFFI.lime_application_set_modal_callbacks(handle, @@ -191,6 +193,8 @@ class NativeApplication public function exit():Void { + // Tray icons would otherwise remain in the notification area on some platforms + NativeTrayIcon.closeAll(); AudioManager.shutdown(); #if (!macro && lime_cffi) NativeCFFI.lime_application_quit(handle); @@ -680,6 +684,24 @@ class NativeApplication } } + private function handleTrayIconEvent():Void + { + var trayIcon = NativeTrayIcon.getTrayIcon(trayIconEventInfo.id); + + if (trayIcon != null) + { + switch (trayIconEventInfo.type) + { + case TRAY_ICON_CLICK: + trayIcon.handleClick(); + case TRAY_ICON_MENU_SELECT: + trayIcon.handleMenuSelect(trayIconEventInfo.itemID); + case TRAY_ICON_RIGHT_CLICK: + trayIcon.handleRightClick(); + } + } + } + private function handleWindowEvent():Void { var window = parent.__windowByID.get(windowEventInfo.windowID); @@ -1148,6 +1170,32 @@ class NativeApplication var TOUCH_MOVE = 2; } +@:keep /*private*/ class TrayIconEventInfo +{ + public var id:Int; + public var itemID:Int; + public var type:TrayIconEventType; + + public function new(type:TrayIconEventType = null, id:Int = 0, itemID:Int = 0) + { + this.type = type; + this.id = id; + this.itemID = itemID; + } + + public function clone():TrayIconEventInfo + { + return new TrayIconEventInfo(type, id, itemID); + } +} + +#if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract TrayIconEventType(Int) +{ + var TRAY_ICON_CLICK = 0; + var TRAY_ICON_MENU_SELECT = 1; + var TRAY_ICON_RIGHT_CLICK = 2; +} + @:keep /*private*/ class WindowEventInfo { public var height:Int; diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 56a4cfb9d3..a5c9c806ed 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -69,6 +69,7 @@ class NativeCFFI uncapMode:Int):Void; @:cffi private static function lime_application_set_modal_callbacks(handle:Dynamic, update:Dynamic, render:Dynamic, window:Dynamic, rethrow:Dynamic):Void; + @:cffi private static function lime_application_defer_modal_exception(handle:Dynamic):Void; @:cffi private static function lime_application_set_frame_rate(handle:Dynamic, value:Float):Void; @@ -325,6 +326,24 @@ class NativeCFFI @:cffi private static function lime_touch_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; + @:cffi private static function lime_tray_icon_close(handle:Dynamic):Void; + + @:cffi private static function lime_tray_icon_create():Dynamic; + + @:cffi private static function lime_tray_icon_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; + + @:cffi private static function lime_tray_icon_get_id(handle:Dynamic):Int; + + @:cffi private static function lime_tray_icon_is_supported():Bool; + + @:cffi private static function lime_tray_icon_popup_menu(handle:Dynamic, data:Dynamic):Int; + + @:cffi private static function lime_tray_icon_set_icon(handle:Dynamic, buffer:Dynamic):Void; + + @:cffi private static function lime_tray_icon_set_menu(handle:Dynamic, data:Dynamic):Bool; + + @:cffi private static function lime_tray_icon_set_tooltip(handle:Dynamic, tooltip:String):Void; + @:cffi private static function lime_window_alert(handle:Dynamic, message:String, title:String):Void; @:cffi private static function lime_window_close(handle:Dynamic):Void; @@ -959,6 +978,20 @@ class NativeCFFI "lime_text_event_manager_register", "oov", false)); private static var lime_touch_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_touch_event_manager_register", "oov", false)); + private static var lime_tray_icon_close = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_tray_icon_close", "ov", false)); + private static var lime_tray_icon_create = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_tray_icon_create", "o", false)); + private static var lime_tray_icon_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", + "lime_tray_icon_event_manager_register", "oov", false)); + private static var lime_tray_icon_get_id = new cpp.CallableInt>(cpp.Prime._loadPrime("lime", "lime_tray_icon_get_id", "oi", false)); + private static var lime_tray_icon_is_supported = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_tray_icon_is_supported", "b", false)); + private static var lime_tray_icon_popup_menu = new cpp.Callablecpp.Object->Int>(cpp.Prime._loadPrime("lime", "lime_tray_icon_popup_menu", + "ooi", false)); + private static var lime_tray_icon_set_icon = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_tray_icon_set_icon", + "oov", false)); + private static var lime_tray_icon_set_menu = new cpp.Callablecpp.Object->Bool>(cpp.Prime._loadPrime("lime", "lime_tray_icon_set_menu", "oob", + false)); + private static var lime_tray_icon_set_tooltip = new cpp.CallableString->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_tray_icon_set_tooltip", + "osv", false)); private static var lime_window_alert = new cpp.CallableString->String->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_alert", "ossv", false)); private static var lime_window_close = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_close", "ov", false)); @@ -1393,6 +1426,15 @@ class NativeCFFI private static var lime_system_open_url = CFFI.load("lime", "lime_system_open_url", 2); private static var lime_text_event_manager_register = CFFI.load("lime", "lime_text_event_manager_register", 2); private static var lime_touch_event_manager_register = CFFI.load("lime", "lime_touch_event_manager_register", 2); + private static var lime_tray_icon_close = CFFI.load("lime", "lime_tray_icon_close", 1); + private static var lime_tray_icon_create = CFFI.load("lime", "lime_tray_icon_create", 0); + private static var lime_tray_icon_event_manager_register = CFFI.load("lime", "lime_tray_icon_event_manager_register", 2); + private static var lime_tray_icon_get_id = CFFI.load("lime", "lime_tray_icon_get_id", 1); + private static var lime_tray_icon_is_supported = CFFI.load("lime", "lime_tray_icon_is_supported", 0); + private static var lime_tray_icon_popup_menu = CFFI.load("lime", "lime_tray_icon_popup_menu", 2); + private static var lime_tray_icon_set_icon = CFFI.load("lime", "lime_tray_icon_set_icon", 2); + private static var lime_tray_icon_set_menu = CFFI.load("lime", "lime_tray_icon_set_menu", 2); + private static var lime_tray_icon_set_tooltip = CFFI.load("lime", "lime_tray_icon_set_tooltip", 2); private static var lime_window_alert = CFFI.load("lime", "lime_window_alert", 3); private static var lime_window_close = CFFI.load("lime", "lime_window_close", 1); private static var lime_window_context_flip = CFFI.load("lime", "lime_window_context_flip", 1); @@ -1578,6 +1620,7 @@ class NativeCFFI frameRate:Float, timePrecision:Int, busyWait:Int, uncapMode:Int):Void {} @:hlNative("lime", "hl_application_set_modal_callbacks") private static function lime_application_set_modal_callbacks(handle:CFFIPointer, update:Void->Void, render:Void->Void, window:Void->Void, rethrow:Void->Void):Void {} + @:hlNative("lime", "hl_application_defer_modal_exception") private static function lime_application_defer_modal_exception(handle:CFFIPointer):Void {} @:hlNative("lime", "hl_application_set_frame_rate") private static function lime_application_set_frame_rate(handle:CFFIPointer, value:Float):Void {} @@ -2111,6 +2154,40 @@ class NativeCFFI @:hlNative("lime", "hl_touch_event_manager_register") private static function lime_touch_event_manager_register(callback:Void->Void, eventObject:TouchEventInfo):Void {} + @:hlNative("lime", "hl_tray_icon_close") private static function lime_tray_icon_close(handle:CFFIPointer):Void {} + + @:hlNative("lime", "hl_tray_icon_create") private static function lime_tray_icon_create():CFFIPointer + { + return null; + } + + @:hlNative("lime", "hl_tray_icon_event_manager_register") private static function lime_tray_icon_event_manager_register(callback:Void->Void, + eventObject:TrayIconEventInfo):Void {} + + @:hlNative("lime", "hl_tray_icon_get_id") private static function lime_tray_icon_get_id(handle:CFFIPointer):Int + { + return 0; + } + + @:hlNative("lime", "hl_tray_icon_is_supported") private static function lime_tray_icon_is_supported():Bool + { + return false; + } + + @:hlNative("lime", "hl_tray_icon_popup_menu") private static function lime_tray_icon_popup_menu(handle:CFFIPointer, data:Bytes):Int + { + return 0; + } + + @:hlNative("lime", "hl_tray_icon_set_icon") private static function lime_tray_icon_set_icon(handle:CFFIPointer, buffer:ImageBuffer):Void {} + + @:hlNative("lime", "hl_tray_icon_set_menu") private static function lime_tray_icon_set_menu(handle:CFFIPointer, data:Bytes):Bool + { + return false; + } + + @:hlNative("lime", "hl_tray_icon_set_tooltip") private static function lime_tray_icon_set_tooltip(handle:CFFIPointer, tooltip:String):Void {} + @:hlNative("lime", "hl_window_alert") private static function lime_window_alert(handle:CFFIPointer, message:String, title:String):Void {} @:hlNative("lime", "hl_window_close") private static function lime_window_close(handle:CFFIPointer):Void {} diff --git a/src/lime/_internal/backend/native/NativeTrayIcon.hx b/src/lime/_internal/backend/native/NativeTrayIcon.hx new file mode 100644 index 0000000000..80388a0a91 --- /dev/null +++ b/src/lime/_internal/backend/native/NativeTrayIcon.hx @@ -0,0 +1,172 @@ +package lime._internal.backend.native; + +import lime.graphics.Image; +import lime.graphics.ImageBuffer; +import lime.math.Vector2; +import lime.ui.Menu; +import lime.ui.MenuItem; +import lime.ui.TrayIcon; + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime._internal.backend.native.NativeCFFI) +@:access(lime.ui.Menu) +@:access(lime.ui.MenuItem) +@:access(lime.ui.TrayIcon) +class NativeTrayIcon +{ + private static var trayIconsByID = new Map(); + + public var handle:Dynamic; + + private var id:Int; + private var menuItems:Array; + private var menuShownByPlatform:Bool; + private var parent:TrayIcon; + + public function new(parent:TrayIcon) + { + this.parent = parent; + id = -1; + + #if (!macro && lime_cffi) + handle = NativeCFFI.lime_tray_icon_create(); + + if (handle != null) + { + id = NativeCFFI.lime_tray_icon_get_id(handle); + trayIconsByID.set(id, this); + } + #end + } + + public static function closeAll():Void + { + TrayIcon.__closeAll(); + } + + public static function getTrayIcon(id:Int):NativeTrayIcon + { + return trayIconsByID.get(id); + } + + public static function isSupported():Bool + { + #if (!macro && lime_cffi) + return NativeCFFI.lime_tray_icon_is_supported(); + #else + return false; + #end + } + + public function close():Void + { + if (handle != null) + { + #if (!macro && lime_cffi) + NativeCFFI.lime_tray_icon_close(handle); + #end + + trayIconsByID.remove(id); + handle = null; + menuItems = null; + } + } + + public function handleClick():Void + { + parent.onClick.dispatch(); + } + + public function handleMenuSelect(itemID:Int):Void + { + var item = NativeMenu.getItem(menuItems, itemID); + if (item != null) item.__select(); + } + + public function handleRightClick():Void + { + parent.onRightClick.dispatch(); + + if (!parent.onRightClick.canceled && !menuShownByPlatform && parent.__menu != null) + { + popupMenu(parent.__menu); + } + } + + public function popupMenu(menu:Menu):Void + { + if (handle != null && menu != null) + { + #if (!macro && lime_cffi) + var items = []; + var data = NativeMenu.encode(menu, items); + var item = NativeMenu.getItem(items, NativeCFFI.lime_tray_icon_popup_menu(handle, data)); + if (item != null) item.__select(); + #end + } + } + + public function setIcon(image:Image):Void + { + if (handle != null) + { + #if (!macro && lime_cffi) + NativeCFFI.lime_tray_icon_set_icon(handle, getIconBuffer(image)); + #end + } + } + + public function setMenu(menu:Menu):Void + { + if (handle != null) + { + #if (!macro && lime_cffi) + if (menu != null) + { + var items = []; + var data = NativeMenu.encode(menu, items); + menuItems = items; + menuShownByPlatform = NativeCFFI.lime_tray_icon_set_menu(handle, data); + } + else + { + menuItems = null; + menuShownByPlatform = NativeCFFI.lime_tray_icon_set_menu(handle, null); + } + #end + } + } + + public function setTooltip(value:String):Void + { + if (handle != null) + { + #if (!macro && lime_cffi) + NativeCFFI.lime_tray_icon_set_tooltip(handle, value != null ? value : ""); + #end + } + } + + private static function getIconBuffer(image:Image):ImageBuffer + { + if (image == null || image.buffer == null) return null; + + var buffer = image.buffer; + + // Native icons are created from straight (non-premultiplied) RGBA pixels covering the whole buffer + if (image.format == RGBA32 && !image.premultiplied && image.offsetX == 0 && image.offsetY == 0 && image.width == buffer.width + && image.height == buffer.height) + { + return buffer; + } + + var copy = new Image(null, 0, 0, image.width, image.height, 0x00000000); + copy.copyPixels(image, image.rect, new Vector2(0, 0)); + copy.format = RGBA32; + copy.premultiplied = false; + return copy.buffer; + } +} diff --git a/src/lime/ui/Menu.hx b/src/lime/ui/Menu.hx index eb967ccfb4..645419132c 100644 --- a/src/lime/ui/Menu.hx +++ b/src/lime/ui/Menu.hx @@ -49,6 +49,7 @@ import lime.app.Event; #end @:access(lime.app.Application) @:access(lime.ui.MenuItem) +@:access(lime.ui.TrayIcon) @:access(lime.ui.Window) class Menu { @@ -82,11 +83,13 @@ class Menu @:noCompletion private var __application:Application; @:noCompletion private var __items:Array; + @:noCompletion private var __trayIcons:Array; @:noCompletion private var __windows:Array; public function new() { __items = []; + __trayIcons = []; __windows = []; } @@ -260,6 +263,11 @@ class Menu __application.__backend.setMenu(this); } + for (trayIcon in __trayIcons) + { + trayIcon.__backend.setMenu(this); + } + for (window in __windows) { window.__backend.setMenu(this); diff --git a/src/lime/ui/TrayIcon.hx b/src/lime/ui/TrayIcon.hx new file mode 100644 index 0000000000..e61a346ea3 --- /dev/null +++ b/src/lime/ui/TrayIcon.hx @@ -0,0 +1,189 @@ +package lime.ui; + +import lime.app.Event; +import lime.graphics.Image; + +/** + An icon in the system tray, with an optional menu. Tray icons are shown in + the notification area on Windows, in the menu bar on macOS, and as status + notifier items on Linux. + + Example usage: + ```haxe + if (TrayIcon.isSupported) + { + var trayIcon = new TrayIcon(Assets.getImage("icon.png"), "My App"); + trayIcon.onClick.add(() -> window.focus()); + + var menu = new Menu(); + menu.addItem(new MenuItem("Show")).onSelect.add(() -> window.focus()); + menu.addSeparator(); + menu.addItem(new MenuItem("Quit")).onSelect.add(() -> System.exit(0)); + trayIcon.menu = menu; + } + ``` + + Platform notes: + + - Windows: `onClick` is dispatched when the icon is clicked. When it is + right-clicked, `onRightClick` is dispatched, and then the menu is shown + unless the event was canceled. + - macOS: when the icon has a menu, clicking it shows the menu. Otherwise, + `onClick` and `onRightClick` are dispatched. + - Linux: requires AppIndicator (libayatana-appindicator3) and a desktop that + shows status notifier items. Clicking the icon shows its menu, and + `onClick` and `onRightClick` are not dispatched. + + A tray icon stays visible until `close()` is called or the application + exits. +**/ +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime.ui.Menu) +class TrayIcon +{ + /** + Whether tray icons are supported on the current platform. + **/ + public static var isSupported(get, never):Bool; + + /** + The image displayed for the icon, or `null` for the application icon. + **/ + public var icon(get, set):Image; + + /** + The menu for the icon, or `null` for none. + **/ + public var menu(get, set):Menu; + + /** + Dispatched when the icon is clicked. See the platform notes above. + **/ + public var onClick(default, null) = new EventVoid>(); + + /** + Dispatched when the icon is right-clicked. On Windows, canceling this + event prevents the menu from being shown. + **/ + public var onRightClick(default, null) = new EventVoid>(); + + /** + The text shown when hovering over the icon (or its title on Linux). + **/ + public var tooltip(get, set):String; + + @:noCompletion private static var __trayIcons:Array = []; + + @:noCompletion private var __backend:TrayIconBackend; + @:noCompletion private var __icon:Image; + @:noCompletion private var __menu:Menu; + @:noCompletion private var __tooltip:String; + + public function new(icon:Image = null, tooltip:String = null) + { + __backend = new TrayIconBackend(this); + + // Keep open tray icons alive, since the platform shows them until they are closed + __trayIcons.push(this); + + if (icon != null) this.icon = icon; + if (tooltip != null) this.tooltip = tooltip; + } + + /** + Removes the icon from the system tray. + **/ + public function close():Void + { + if (__menu != null) + { + __menu.__trayIcons.remove(this); + __menu = null; + } + + __trayIcons.remove(this); + __backend.close(); + } + + @:noCompletion private static function __closeAll():Void + { + for (trayIcon in __trayIcons.copy()) + { + trayIcon.close(); + } + } + + // Get & Set Methods + @:noCompletion private inline function get_icon():Image + { + return __icon; + } + + @:noCompletion private function set_icon(value:Image):Image + { + __icon = value; + __backend.setIcon(value); + return value; + } + + @:noCompletion private static function get_isSupported():Bool + { + return TrayIconBackend.isSupported(); + } + + @:noCompletion private inline function get_menu():Menu + { + return __menu; + } + + @:noCompletion private function set_menu(value:Menu):Menu + { + if (value != __menu) + { + if (__menu != null) __menu.__trayIcons.remove(this); + __menu = value; + if (value != null) value.__trayIcons.push(this); + + __backend.setMenu(value); + } + + return value; + } + + @:noCompletion private inline function get_tooltip():String + { + return __tooltip; + } + + @:noCompletion private function set_tooltip(value:String):String + { + __tooltip = value; + __backend.setTooltip(value); + return value; + } +} + +#if (lime_cffi && !macro) +@:noCompletion private typedef TrayIconBackend = lime._internal.backend.native.NativeTrayIcon; +#else +@:noCompletion private class TrayIconBackend +{ + public static function isSupported():Bool + { + return false; + } + + public function new(parent:TrayIcon) {} + + public function close():Void {} + + public function setIcon(image:Image):Void {} + + public function setMenu(menu:Menu):Void {} + + public function setTooltip(value:String):Void {} +} +#end From cb09ca80f8690810a8ada504068adb9c5850033b Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:56:25 -0400 Subject: [PATCH 111/251] DockIcon: Add the Dock menu, icon and bounce on macOS Adds lime.ui.DockIcon, matching AIR's DockIcon, so that OpenFL can support NativeApplication.icon on macOS: - DockIcon.menu adds items to the Dock icon's menu, through an applicationDockMenu: method added to SDL's application delegate - DockIcon.icon replaces the Dock icon image, and null restores the application bundle icon - DockIcon.bounce() requests the user's attention Dock menu selections are dispatched as a new MenuEvent type. On other platforms, DockIcon.isSupported is false and its members have no effect. --- project/include/ui/DockIcon.h | 28 +++ project/include/ui/MenuEvent.h | 3 +- project/src/ExternalInterface.cpp | 74 ++++++++ project/src/backend/sdl/SDLApplication.cpp | 14 +- project/src/backend/sdl/SDLMenu.cpp | 47 ++++- project/src/backend/sdl/SDLMenu.h | 2 + project/src/backend/sdl/SDLMenuMac.mm | 172 +++++++++++++++--- .../backend/native/NativeApplication.hx | 4 + .../_internal/backend/native/NativeCFFI.hx | 30 +++ .../backend/native/NativeDockIcon.hx | 62 +++++++ .../backend/native/NativeTrayIcon.hx | 2 +- src/lime/ui/DockIcon.hx | 121 ++++++++++++ src/lime/ui/Menu.hx | 8 + 13 files changed, 534 insertions(+), 33 deletions(-) create mode 100644 project/include/ui/DockIcon.h create mode 100644 src/lime/_internal/backend/native/NativeDockIcon.hx create mode 100644 src/lime/ui/DockIcon.hx diff --git a/project/include/ui/DockIcon.h b/project/include/ui/DockIcon.h new file mode 100644 index 0000000000..3d0de0dce6 --- /dev/null +++ b/project/include/ui/DockIcon.h @@ -0,0 +1,28 @@ +#ifndef LIME_UI_DOCK_ICON_H +#define LIME_UI_DOCK_ICON_H + + +#include + + +namespace lime { + + + class DockIcon { + + + public: + + static void Bounce (bool critical); + static bool IsSupported (); + static void SetIcon (ImageBuffer* imageBuffer); + static bool SetMenu (const unsigned char* data, int length); + + + }; + + +} + + +#endif diff --git a/project/include/ui/MenuEvent.h b/project/include/ui/MenuEvent.h index 5b8ba05abc..1dde1b3daf 100644 --- a/project/include/ui/MenuEvent.h +++ b/project/include/ui/MenuEvent.h @@ -11,7 +11,8 @@ namespace lime { enum MenuEventType { - MENU_SELECT + MENU_SELECT, + MENU_DOCK_SELECT }; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 80e61972a0..5d8c376d6c 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -2033,6 +2034,71 @@ namespace lime { } + void lime_dock_icon_bounce (bool critical) { + + DockIcon::Bounce (critical); + + } + + + HL_PRIM void HL_NAME(hl_dock_icon_bounce) (bool critical) { + + DockIcon::Bounce (critical); + + } + + + bool lime_dock_icon_is_supported () { + + return DockIcon::IsSupported (); + + } + + + HL_PRIM bool HL_NAME(hl_dock_icon_is_supported) () { + + return DockIcon::IsSupported (); + + } + + + void lime_dock_icon_set_icon (value buffer) { + + if (val_is_null (buffer)) { + + DockIcon::SetIcon (NULL); + return; + + } + + ImageBuffer imageBuffer = ImageBuffer (buffer); + DockIcon::SetIcon (&imageBuffer); + + } + + + HL_PRIM void HL_NAME(hl_dock_icon_set_icon) (ImageBuffer* buffer) { + + DockIcon::SetIcon (buffer); + + } + + + bool lime_dock_icon_set_menu (value data) { + + Bytes bytes (data); + return DockIcon::SetMenu (bytes.b, bytes.length); + + } + + + HL_PRIM bool HL_NAME(hl_dock_icon_set_menu) (Bytes* data) { + + return DockIcon::SetMenu (data ? data->b : 0, data ? data->length : 0); + + } + + void lime_drop_event_manager_register (value callback, value eventObject) { DropEvent::callback = new ValuePointer (callback); @@ -13744,6 +13810,10 @@ namespace lime { DEFINE_PRIME2 (lime_data_pointer_offset); DEFINE_PRIME2 (lime_deflate_compress); DEFINE_PRIME2 (lime_deflate_decompress); + DEFINE_PRIME1v (lime_dock_icon_bounce); + DEFINE_PRIME0 (lime_dock_icon_is_supported); + DEFINE_PRIME1v (lime_dock_icon_set_icon); + DEFINE_PRIME1 (lime_dock_icon_set_menu); DEFINE_PRIME2v (lime_drop_event_manager_register); DEFINE_PRIME3 (lime_file_dialog_open_directory); DEFINE_PRIME3 (lime_file_dialog_open_file); @@ -14074,6 +14144,10 @@ namespace lime { DEFINE_HL_PRIM (_F64, hl_data_pointer_offset, _F64 _I32); DEFINE_HL_PRIM (_TBYTES, hl_deflate_compress, _TBYTES _TBYTES); DEFINE_HL_PRIM (_TBYTES, hl_deflate_decompress, _TBYTES _TBYTES); + DEFINE_HL_PRIM (_VOID, hl_dock_icon_bounce, _BOOL); + DEFINE_HL_PRIM (_BOOL, hl_dock_icon_is_supported, _NO_ARG); + DEFINE_HL_PRIM (_VOID, hl_dock_icon_set_icon, _TIMAGEBUFFER); + DEFINE_HL_PRIM (_BOOL, hl_dock_icon_set_menu, _TBYTES); DEFINE_HL_PRIM (_VOID, hl_drop_event_manager_register, _FUN(_VOID, _NO_ARG) _TDROP_EVENT); DEFINE_HL_PRIM (_BYTES, hl_file_dialog_open_directory, _STRING _STRING _STRING); DEFINE_HL_PRIM (_BYTES, hl_file_dialog_open_file, _STRING _STRING _STRING); diff --git a/project/src/backend/sdl/SDLApplication.cpp b/project/src/backend/sdl/SDLApplication.cpp index a998dc2480..1bfda665e1 100644 --- a/project/src/backend/sdl/SDLApplication.cpp +++ b/project/src/backend/sdl/SDLApplication.cpp @@ -1106,13 +1106,25 @@ namespace lime Uint32 windowID; int id; - if (MenuEvent::callback && SDLMenu::GetSelection(event, &windowID, &id)) + if (!MenuEvent::callback) + return; + + if (SDLMenu::GetSelection(event, &windowID, &id)) { menuEvent.type = MENU_SELECT; menuEvent.id = id; menuEvent.windowID = windowID; + MenuEvent::Dispatch(&menuEvent); + } + else if (SDLMenu::GetDockMenuSelection(event, &id)) + { + + menuEvent.type = MENU_DOCK_SELECT; + menuEvent.id = id; + menuEvent.windowID = 0; + MenuEvent::Dispatch(&menuEvent); } } diff --git a/project/src/backend/sdl/SDLMenu.cpp b/project/src/backend/sdl/SDLMenu.cpp index ed16d4e0ea..fc53012ddf 100644 --- a/project/src/backend/sdl/SDLMenu.cpp +++ b/project/src/backend/sdl/SDLMenu.cpp @@ -1,5 +1,6 @@ #include "SDLMenu.h" #include "SDLTrayIcon.h" +#include #include @@ -16,7 +17,8 @@ namespace lime { enum MenuEventKind { MENU_EVENT_SELECTION = 1, - MENU_EVENT_TRAY_ICON = 2 + MENU_EVENT_TRAY_ICON = 2, + MENU_EVENT_DOCK_SELECTION = 3 }; @@ -130,6 +132,16 @@ namespace lime { } + bool SDLMenu::GetDockMenuSelection (SDL_Event* event, int* id) { + + if (menuEventType == 0 || event->type != menuEventType || (intptr_t)event->user.data1 != MENU_EVENT_DOCK_SELECTION) return false; + + *id = event->user.code; + return true; + + } + + bool SDLMenu::GetSelection (SDL_Event* event, Uint32* windowID, int* id) { if (menuEventType != 0 && event->type == menuEventType && (intptr_t)event->user.data1 == MENU_EVENT_SELECTION) { @@ -195,6 +207,13 @@ namespace lime { } + void SDLMenu::PushDockMenuSelection (int id) { + + PushEvent (MENU_EVENT_DOCK_SELECTION, 0, id, 0); + + } + + void SDLMenu::PushSelection (Uint32 windowID, int id) { PushEvent (MENU_EVENT_SELECTION, windowID, id, 0); @@ -216,6 +235,32 @@ namespace lime { } +#ifndef LIME_SDL_MENU_COCOA + + // The Dock only exists on macOS + + void DockIcon::Bounce (bool critical) {} + + + bool DockIcon::IsSupported () { + + return false; + + } + + + void DockIcon::SetIcon (ImageBuffer* imageBuffer) {} + + + bool DockIcon::SetMenu (const unsigned char* data, int length) { + + return false; + + } + +#endif + + #if !defined (LIME_SDL_MENU_WIN32) && !defined (LIME_SDL_MENU_COCOA) && !defined (LIME_SDL_MENU_GTK) bool SDLMenu::GetPlatformSelection (SDL_Event* event, Uint32* windowID, int* id) { diff --git a/project/src/backend/sdl/SDLMenu.h b/project/src/backend/sdl/SDLMenu.h index a240f28968..191f677c1d 100644 --- a/project/src/backend/sdl/SDLMenu.h +++ b/project/src/backend/sdl/SDLMenu.h @@ -45,6 +45,7 @@ namespace lime { public: + static bool GetDockMenuSelection (SDL_Event* event, int* id); static bool GetSelection (SDL_Event* event, Uint32* windowID, int* id); static int GetSupport (); static bool GetTrayIconEvent (SDL_Event* event, int* trayIconID, int* type, int* itemID); @@ -55,6 +56,7 @@ namespace lime { static std::string GetLabel (const std::string& label, char mnemonicPrefix); static bool Parse (const unsigned char* data, int length, std::vector* items); + static void PushDockMenuSelection (int id); static void PushSelection (Uint32 windowID, int id); static void PushTrayIconEvent (int trayIconID, int type, int itemID); diff --git a/project/src/backend/sdl/SDLMenuMac.mm b/project/src/backend/sdl/SDLMenuMac.mm index 19bf10ccd0..d8314e6d37 100644 --- a/project/src/backend/sdl/SDLMenuMac.mm +++ b/project/src/backend/sdl/SDLMenuMac.mm @@ -2,10 +2,12 @@ #ifdef LIME_SDL_MENU_COCOA -// Native menus and tray icons for macOS +// Native menus, tray icons and the Dock icon for macOS #import +#import #include "SDLTrayIcon.h" +#include #include #include #include @@ -13,12 +15,14 @@ #if __has_feature(objc_arc) #define LIME_AUTORELEASE(object) (object) #define LIME_RETAIN(object) (object) +#define LIME_RELEASE(object) #define LIME_BRIDGE(type, pointer) ((__bridge type)(pointer)) #define LIME_BRIDGE_RETAIN(object) ((void*)CFBridgingRetain (object)) #define LIME_BRIDGE_RELEASE(pointer) CFRelease ((CFTypeRef)(pointer)) #else #define LIME_AUTORELEASE(object) [(object) autorelease] #define LIME_RETAIN(object) [(object) retain] +#define LIME_RELEASE(object) [(object) release] #define LIME_BRIDGE(type, pointer) ((type)(pointer)) #define LIME_BRIDGE_RETAIN(object) ((void*)[(object) retain]) #define LIME_BRIDGE_RELEASE(pointer) [(NSObject*)(pointer) release] @@ -35,6 +39,7 @@ @interface LimeMenuTarget : NSObject { - (void)clickTrayIcon:(id)sender; - (void)selectApplicationMenuItem:(NSMenuItem*)sender; +- (void)selectDockMenuItem:(NSMenuItem*)sender; - (void)selectPopupMenuItem:(NSMenuItem*)sender; - (void)selectTrayIconMenuItem:(NSMenuItem*)sender; @@ -59,6 +64,12 @@ - (void)selectApplicationMenuItem:(NSMenuItem*)sender { } +- (void)selectDockMenuItem:(NSMenuItem*)sender { + + lime::SDLMenu::PushDockMenuSelection ((int)[sender tag]); + +} + - (void)selectPopupMenuItem:(NSMenuItem*)sender { popupSelection = [sender tag]; @@ -184,6 +195,40 @@ static NSUInteger GetModifierMask (int keyModifiers) { } + static NSImage* CreateImage (ImageBuffer* imageBuffer) { + + if (!imageBuffer || !imageBuffer->data || !imageBuffer->data->buffer || imageBuffer->width <= 0 || imageBuffer->height <= 0 || imageBuffer->bitsPerPixel != 32) { + + return nil; + + } + + int width = imageBuffer->width; + int height = imageBuffer->height; + int stride = imageBuffer->Stride (); + + if (imageBuffer->data->buffer->length < stride * height) return nil; + + NSBitmapImageRep* bitmap = LIME_AUTORELEASE ([[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:NSBitmapFormatAlphaNonpremultiplied bytesPerRow:width * 4 bitsPerPixel:32]); + + if (!bitmap) return nil; + + const unsigned char* source = imageBuffer->data->buffer->b; + unsigned char* dest = [bitmap bitmapData]; + + for (int y = 0; y < height; y++) { + + memcpy (dest + y * width * 4, source + y * stride, width * 4); + + } + + NSImage* image = LIME_AUTORELEASE ([[NSImage alloc] initWithSize:NSMakeSize (width, height)]); + [image addRepresentation:bitmap]; + return image; + + } + + static NSMenu* CreateMenu (NSString* title) { NSMenu* menu = LIME_AUTORELEASE ([[NSMenu alloc] initWithTitle:title]); @@ -472,37 +517,12 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items void SDLTrayIcon::SetIcon (ImageBuffer* imageBuffer) { - if (!platform || !imageBuffer || !imageBuffer->data || !imageBuffer->data->buffer || imageBuffer->width <= 0 || imageBuffer->height <= 0 || imageBuffer->bitsPerPixel != 32) { - - return; - - } + if (!platform) return; @autoreleasepool { - int width = imageBuffer->width; - int height = imageBuffer->height; - - if (imageBuffer->data->buffer->length < imageBuffer->Stride () * height) return; - - NSBitmapImageRep* bitmap = LIME_AUTORELEASE ([[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:NSBitmapFormatAlphaNonpremultiplied bytesPerRow:width * 4 bitsPerPixel:32]); - - if (!bitmap) return; - - const unsigned char* source = imageBuffer->data->buffer->b; - unsigned char* dest = [bitmap bitmapData]; - int stride = imageBuffer->Stride (); - - for (int y = 0; y < height; y++) { - - memcpy (dest + y * width * 4, source + y * stride, width * 4); - - } - - NSImage* image = LIME_AUTORELEASE ([[NSImage alloc] initWithSize:NSMakeSize (width, height)]); - [image addRepresentation:bitmap]; - - [[GetStatusItem (this) button] setImage:GetTrayImage (image)]; + NSImage* image = CreateImage (imageBuffer); + [[GetStatusItem (this) button] setImage:GetTrayImage (image ? image : [NSApp applicationIconImage])]; } @@ -552,6 +572,100 @@ static void AppendMenuItems (NSMenu* menu, const std::vector& items void SDLTrayIcon::Update () {} + // AppKit asks the application delegate for the Dock menu. SDL's delegate does not provide + // one, so the method is added to its class when a Dock menu is first set. + + static NSMenu* dockMenu = nil; + static bool dockMenuHandlerInstalled = false; + + + static NSMenu* GetApplicationDockMenu (id self, SEL command, NSApplication* sender) { + + return dockMenu; + + } + + + static bool InstallDockMenuHandler () { + + if (dockMenuHandlerInstalled) return true; + + id delegate = [NSApp delegate]; + SEL selector = @selector(applicationDockMenu:); + + // Another delegate that already provides a Dock menu is left alone + if (!delegate || [delegate respondsToSelector:selector]) return false; + + if (!class_addMethod ([delegate class], selector, (IMP)GetApplicationDockMenu, "@@:@")) return false; + + // NSApplication caches which methods its delegate implements, so set it again + [NSApp setDelegate:nil]; + [NSApp setDelegate:delegate]; + + dockMenuHandlerInstalled = true; + return true; + + } + + + void DockIcon::Bounce (bool critical) { + + if (NSApp) [NSApp requestUserAttention:(critical ? NSCriticalRequest : NSInformationalRequest)]; + + } + + + bool DockIcon::IsSupported () { + + return NSApp != nil; + + } + + + void DockIcon::SetIcon (ImageBuffer* imageBuffer) { + + if (!NSApp) return; + + @autoreleasepool { + + // A nil image restores the icon from the application bundle + [NSApp setApplicationIconImage:CreateImage (imageBuffer)]; + + } + + } + + + bool DockIcon::SetMenu (const unsigned char* data, int length) { + + if (!NSApp) return false; + + @autoreleasepool { + + NSMenu* menu = nil; + + if (data && length > 0) { + + std::vector items; + + if (!SDLMenu::Parse (data, length, &items) || !InstallDockMenuHandler ()) return false; + + menu = CreateMenu (@""); + AppendMenuItems (menu, items, @selector(selectDockMenuItem:), 0); + + } + + NSMenu* previous = dockMenu; + dockMenu = LIME_RETAIN (menu); + LIME_RELEASE (previous); + + return menu != nil; + + } + + } + + } diff --git a/src/lime/_internal/backend/native/NativeApplication.hx b/src/lime/_internal/backend/native/NativeApplication.hx index f28f94cdc3..5db858e197 100644 --- a/src/lime/_internal/backend/native/NativeApplication.hx +++ b/src/lime/_internal/backend/native/NativeApplication.hx @@ -480,6 +480,9 @@ class NativeApplication { switch (menuEventInfo.type) { + case MENU_DOCK_SELECT: + NativeDockIcon.handleMenuSelect(menuEventInfo.id); + case MENU_SELECT: if (menuEventInfo.windowID == 0) { @@ -1011,6 +1014,7 @@ class NativeApplication #if (haxe_ver >= 4.0) private enum #else @:enum private #end abstract MenuEventType(Int) { var MENU_SELECT = 0; + var MENU_DOCK_SELECT = 1; } @:keep /*private*/ class MouseEventInfo diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index a5c9c806ed..3f2a89c06e 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -124,6 +124,14 @@ class NativeCFFI @:cffi private static function lime_deflate_decompress(data:Dynamic, bytes:Dynamic):Dynamic; + @:cffi private static function lime_dock_icon_bounce(critical:Bool):Void; + + @:cffi private static function lime_dock_icon_is_supported():Bool; + + @:cffi private static function lime_dock_icon_set_icon(buffer:Dynamic):Void; + + @:cffi private static function lime_dock_icon_set_menu(data:Dynamic):Bool; + @:cffi private static function lime_drop_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void; @:cffi private static function lime_file_dialog_open_directory(title:String, filter:String, defaultPath:String):Dynamic; @@ -809,6 +817,10 @@ class NativeCFFI "ooo", false)); private static var lime_deflate_decompress = new cpp.Callablecpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_deflate_decompress", "ooo", false)); + private static var lime_dock_icon_bounce = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_dock_icon_bounce", "bv", false)); + private static var lime_dock_icon_is_supported = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_dock_icon_is_supported", "b", false)); + private static var lime_dock_icon_set_icon = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_dock_icon_set_icon", "ov", false)); + private static var lime_dock_icon_set_menu = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_dock_icon_set_menu", "ob", false)); private static var lime_drop_event_manager_register = new cpp.Callablecpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_drop_event_manager_register", "oov", false)); private static var lime_file_dialog_open_directory = new cpp.CallableString->String->cpp.Object>(cpp.Prime._loadPrime("lime", @@ -1327,6 +1339,10 @@ class NativeCFFI private static var lime_data_pointer_offset = CFFI.load("lime", "lime_data_pointer_offset", 2); private static var lime_deflate_compress = CFFI.load("lime", "lime_deflate_compress", 2); private static var lime_deflate_decompress = CFFI.load("lime", "lime_deflate_decompress", 2); + private static var lime_dock_icon_bounce = CFFI.load("lime", "lime_dock_icon_bounce", 1); + private static var lime_dock_icon_is_supported = CFFI.load("lime", "lime_dock_icon_is_supported", 0); + private static var lime_dock_icon_set_icon = CFFI.load("lime", "lime_dock_icon_set_icon", 1); + private static var lime_dock_icon_set_menu = CFFI.load("lime", "lime_dock_icon_set_menu", 1); private static var lime_drop_event_manager_register = CFFI.load("lime", "lime_drop_event_manager_register", 2); private static var lime_file_dialog_open_directory = CFFI.load("lime", "lime_file_dialog_open_directory", 3); private static var lime_file_dialog_open_file = CFFI.load("lime", "lime_file_dialog_open_file", 3); @@ -1735,6 +1751,20 @@ class NativeCFFI return null; } + @:hlNative("lime", "hl_dock_icon_bounce") private static function lime_dock_icon_bounce(critical:Bool):Void {} + + @:hlNative("lime", "hl_dock_icon_is_supported") private static function lime_dock_icon_is_supported():Bool + { + return false; + } + + @:hlNative("lime", "hl_dock_icon_set_icon") private static function lime_dock_icon_set_icon(buffer:ImageBuffer):Void {} + + @:hlNative("lime", "hl_dock_icon_set_menu") private static function lime_dock_icon_set_menu(data:Bytes):Bool + { + return false; + } + @:hlNative("lime", "hl_drop_event_manager_register") private static function lime_drop_event_manager_register(callback:Void->Void, eventObject:DropEventInfo):Void {} diff --git a/src/lime/_internal/backend/native/NativeDockIcon.hx b/src/lime/_internal/backend/native/NativeDockIcon.hx new file mode 100644 index 0000000000..6bc4c76211 --- /dev/null +++ b/src/lime/_internal/backend/native/NativeDockIcon.hx @@ -0,0 +1,62 @@ +package lime._internal.backend.native; + +import lime.graphics.Image; +import lime.ui.Menu; +import lime.ui.MenuItem; + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime._internal.backend.native.NativeCFFI) +@:access(lime.ui.MenuItem) +class NativeDockIcon +{ + private static var menuItems:Array; + + public static function bounce(critical:Bool):Void + { + #if (!macro && lime_cffi) + NativeCFFI.lime_dock_icon_bounce(critical); + #end + } + + public static function handleMenuSelect(id:Int):Void + { + var item = NativeMenu.getItem(menuItems, id); + if (item != null) item.__select(); + } + + public static function isSupported():Bool + { + #if (!macro && lime_cffi) + return NativeCFFI.lime_dock_icon_is_supported(); + #else + return false; + #end + } + + public static function setIcon(image:Image):Void + { + #if (!macro && lime_cffi) + NativeCFFI.lime_dock_icon_set_icon(NativeTrayIcon.getIconBuffer(image)); + #end + } + + public static function setMenu(menu:Menu):Void + { + #if (!macro && lime_cffi) + if (menu != null) + { + var items = []; + var data = NativeMenu.encode(menu, items); + menuItems = NativeCFFI.lime_dock_icon_set_menu(data) ? items : null; + } + else + { + NativeCFFI.lime_dock_icon_set_menu(null); + menuItems = null; + } + #end + } +} diff --git a/src/lime/_internal/backend/native/NativeTrayIcon.hx b/src/lime/_internal/backend/native/NativeTrayIcon.hx index 80388a0a91..ff13280624 100644 --- a/src/lime/_internal/backend/native/NativeTrayIcon.hx +++ b/src/lime/_internal/backend/native/NativeTrayIcon.hx @@ -150,7 +150,7 @@ class NativeTrayIcon } } - private static function getIconBuffer(image:Image):ImageBuffer + public static function getIconBuffer(image:Image):ImageBuffer { if (image == null || image.buffer == null) return null; diff --git a/src/lime/ui/DockIcon.hx b/src/lime/ui/DockIcon.hx new file mode 100644 index 0000000000..691458732a --- /dev/null +++ b/src/lime/ui/DockIcon.hx @@ -0,0 +1,121 @@ +package lime.ui; + +import lime.graphics.Image; + +/** + The application's icon in the macOS Dock. + + The Dock icon can show a custom image, add items to the menu shown when + the icon is right-clicked, and bounce to request the user's attention. + + Example usage: + ```haxe + if (DockIcon.isSupported) + { + var menu = new Menu(); + menu.addItem(new MenuItem("New Window")).onSelect.add(() -> createWindow()); + DockIcon.menu = menu; + + DockIcon.bounce(); + } + ``` + + Availability note: the Dock only exists on macOS. Elsewhere, the Dock icon + can be configured, but nothing is displayed. +**/ +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end +@:access(lime.ui.Menu) +class DockIcon +{ + /** + Whether the application has a Dock icon. + **/ + public static var isSupported(get, never):Bool; + + /** + The image shown in the Dock, or `null` for the application icon. + **/ + public static var icon(get, set):Image; + + /** + A menu whose items are added to the Dock icon's menu, above the items + provided by macOS, or `null` for none. + **/ + public static var menu(get, set):Menu; + + @:noCompletion private static var __icon:Image; + @:noCompletion private static var __menu:Menu; + + /** + Bounces the Dock icon to request the user's attention while the + application is not active. A critical request keeps bouncing until the + application is activated, otherwise the icon bounces once. + **/ + public static function bounce(critical:Bool = false):Void + { + DockIconBackend.bounce(critical); + } + + @:noCompletion private static function __update():Void + { + DockIconBackend.setMenu(__menu); + } + + // Get & Set Methods + @:noCompletion private static inline function get_icon():Image + { + return __icon; + } + + @:noCompletion private static function set_icon(value:Image):Image + { + __icon = value; + DockIconBackend.setIcon(value); + return value; + } + + @:noCompletion private static function get_isSupported():Bool + { + return DockIconBackend.isSupported(); + } + + @:noCompletion private static inline function get_menu():Menu + { + return __menu; + } + + @:noCompletion private static function set_menu(value:Menu):Menu + { + if (value != __menu) + { + if (__menu != null) __menu.__dockIcon = false; + __menu = value; + if (value != null) value.__dockIcon = true; + + DockIconBackend.setMenu(value); + } + + return value; + } +} + +#if (lime_cffi && !macro) +@:noCompletion private typedef DockIconBackend = lime._internal.backend.native.NativeDockIcon; +#else +@:noCompletion private class DockIconBackend +{ + public static function bounce(critical:Bool):Void {} + + public static function isSupported():Bool + { + return false; + } + + public static function setIcon(image:Image):Void {} + + public static function setMenu(menu:Menu):Void {} +} +#end diff --git a/src/lime/ui/Menu.hx b/src/lime/ui/Menu.hx index 645419132c..ef854235fc 100644 --- a/src/lime/ui/Menu.hx +++ b/src/lime/ui/Menu.hx @@ -48,6 +48,7 @@ import lime.app.Event; @:noDebug #end @:access(lime.app.Application) +@:access(lime.ui.DockIcon) @:access(lime.ui.MenuItem) @:access(lime.ui.TrayIcon) @:access(lime.ui.Window) @@ -82,12 +83,14 @@ class Menu public var parent(default, null):MenuItem; @:noCompletion private var __application:Application; + @:noCompletion private var __dockIcon:Bool; @:noCompletion private var __items:Array; @:noCompletion private var __trayIcons:Array; @:noCompletion private var __windows:Array; public function new() { + __dockIcon = false; __items = []; __trayIcons = []; __windows = []; @@ -263,6 +266,11 @@ class Menu __application.__backend.setMenu(this); } + if (__dockIcon) + { + DockIcon.__update(); + } + for (trayIcon in __trayIcons) { trayIcon.__backend.setMenu(this); From 096a7a2494d745d58c3294ca97958e14b7527fab Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 15:42:32 -0400 Subject: [PATCH 112/251] TrayIcon, DockIcon: Use per-target backends The backend was a typedef on native targets and a private stub class elsewhere, which dox can't merge across targets. Add Flash and HTML5 stub backends so the backend is a typedef everywhere, like the other backends. --- .../_internal/backend/flash/FlashDockIcon.hx | 18 ++++++++++++++ .../_internal/backend/flash/FlashTrayIcon.hx | 23 ++++++++++++++++++ .../_internal/backend/html5/HTML5DockIcon.hx | 18 ++++++++++++++ .../_internal/backend/html5/HTML5TrayIcon.hx | 23 ++++++++++++++++++ src/lime/ui/DockIcon.hx | 20 ++++------------ src/lime/ui/TrayIcon.hx | 24 ++++--------------- 6 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 src/lime/_internal/backend/flash/FlashDockIcon.hx create mode 100644 src/lime/_internal/backend/flash/FlashTrayIcon.hx create mode 100644 src/lime/_internal/backend/html5/HTML5DockIcon.hx create mode 100644 src/lime/_internal/backend/html5/HTML5TrayIcon.hx diff --git a/src/lime/_internal/backend/flash/FlashDockIcon.hx b/src/lime/_internal/backend/flash/FlashDockIcon.hx new file mode 100644 index 0000000000..d31b84fe7b --- /dev/null +++ b/src/lime/_internal/backend/flash/FlashDockIcon.hx @@ -0,0 +1,18 @@ +package lime._internal.backend.flash; + +import lime.graphics.Image; +import lime.ui.Menu; + +class FlashDockIcon +{ + public static function bounce(critical:Bool):Void {} + + public static function isSupported():Bool + { + return false; + } + + public static function setIcon(image:Image):Void {} + + public static function setMenu(menu:Menu):Void {} +} diff --git a/src/lime/_internal/backend/flash/FlashTrayIcon.hx b/src/lime/_internal/backend/flash/FlashTrayIcon.hx new file mode 100644 index 0000000000..c5071ef3ba --- /dev/null +++ b/src/lime/_internal/backend/flash/FlashTrayIcon.hx @@ -0,0 +1,23 @@ +package lime._internal.backend.flash; + +import lime.graphics.Image; +import lime.ui.Menu; +import lime.ui.TrayIcon; + +class FlashTrayIcon +{ + public function new(parent:TrayIcon) {} + + public function close():Void {} + + public static function isSupported():Bool + { + return false; + } + + public function setIcon(image:Image):Void {} + + public function setMenu(menu:Menu):Void {} + + public function setTooltip(value:String):Void {} +} diff --git a/src/lime/_internal/backend/html5/HTML5DockIcon.hx b/src/lime/_internal/backend/html5/HTML5DockIcon.hx new file mode 100644 index 0000000000..1ffb1f03c5 --- /dev/null +++ b/src/lime/_internal/backend/html5/HTML5DockIcon.hx @@ -0,0 +1,18 @@ +package lime._internal.backend.html5; + +import lime.graphics.Image; +import lime.ui.Menu; + +class HTML5DockIcon +{ + public static function bounce(critical:Bool):Void {} + + public static function isSupported():Bool + { + return false; + } + + public static function setIcon(image:Image):Void {} + + public static function setMenu(menu:Menu):Void {} +} diff --git a/src/lime/_internal/backend/html5/HTML5TrayIcon.hx b/src/lime/_internal/backend/html5/HTML5TrayIcon.hx new file mode 100644 index 0000000000..d9ad16f78f --- /dev/null +++ b/src/lime/_internal/backend/html5/HTML5TrayIcon.hx @@ -0,0 +1,23 @@ +package lime._internal.backend.html5; + +import lime.graphics.Image; +import lime.ui.Menu; +import lime.ui.TrayIcon; + +class HTML5TrayIcon +{ + public function new(parent:TrayIcon) {} + + public function close():Void {} + + public static function isSupported():Bool + { + return false; + } + + public function setIcon(image:Image):Void {} + + public function setMenu(menu:Menu):Void {} + + public function setTooltip(value:String):Void {} +} diff --git a/src/lime/ui/DockIcon.hx b/src/lime/ui/DockIcon.hx index 691458732a..c018bdfe9f 100644 --- a/src/lime/ui/DockIcon.hx +++ b/src/lime/ui/DockIcon.hx @@ -102,20 +102,10 @@ class DockIcon } } -#if (lime_cffi && !macro) -@:noCompletion private typedef DockIconBackend = lime._internal.backend.native.NativeDockIcon; +#if flash +@:noCompletion private typedef DockIconBackend = lime._internal.backend.flash.FlashDockIcon; +#elseif (js && html5) +@:noCompletion private typedef DockIconBackend = lime._internal.backend.html5.HTML5DockIcon; #else -@:noCompletion private class DockIconBackend -{ - public static function bounce(critical:Bool):Void {} - - public static function isSupported():Bool - { - return false; - } - - public static function setIcon(image:Image):Void {} - - public static function setMenu(menu:Menu):Void {} -} +@:noCompletion private typedef DockIconBackend = lime._internal.backend.native.NativeDockIcon; #end diff --git a/src/lime/ui/TrayIcon.hx b/src/lime/ui/TrayIcon.hx index e61a346ea3..b88b478506 100644 --- a/src/lime/ui/TrayIcon.hx +++ b/src/lime/ui/TrayIcon.hx @@ -166,24 +166,10 @@ class TrayIcon } } -#if (lime_cffi && !macro) -@:noCompletion private typedef TrayIconBackend = lime._internal.backend.native.NativeTrayIcon; +#if flash +@:noCompletion private typedef TrayIconBackend = lime._internal.backend.flash.FlashTrayIcon; +#elseif (js && html5) +@:noCompletion private typedef TrayIconBackend = lime._internal.backend.html5.HTML5TrayIcon; #else -@:noCompletion private class TrayIconBackend -{ - public static function isSupported():Bool - { - return false; - } - - public function new(parent:TrayIcon) {} - - public function close():Void {} - - public function setIcon(image:Image):Void {} - - public function setMenu(menu:Menu):Void {} - - public function setTooltip(value:String):Void {} -} +@:noCompletion private typedef TrayIconBackend = lime._internal.backend.native.NativeTrayIcon; #end From f67beb0544123ab88538c8ac6526c18a3bda6d29 Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 16:00:43 -0400 Subject: [PATCH 113/251] TrayIcon: Fix the MinGW build SDL_config_windows.h includes sdkddkver.h before _WIN32_WINNT is set, so MinGW targets Windows Server 2003 and does not declare NIF_SHOWTIP or NOTIFYICON_VERSION_4. Define them when they are missing, as SDLSystem.cpp does for CSIDL_MYDOCUMENTS. --- project/src/backend/sdl/SDLMenuWindows.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/project/src/backend/sdl/SDLMenuWindows.cpp b/project/src/backend/sdl/SDLMenuWindows.cpp index 25b5134f3a..5b5a8f7a3c 100644 --- a/project/src/backend/sdl/SDLMenuWindows.cpp +++ b/project/src/backend/sdl/SDLMenuWindows.cpp @@ -14,6 +14,15 @@ #include #undef CreateWindow +// SDL_config_windows.h includes sdkddkver.h before _WIN32_WINNT is set, which MinGW +// then defaults to Windows Server 2003, hiding the Vista notification icon values +#ifndef NIF_SHOWTIP +#define NIF_SHOWTIP 0x00000080 +#endif +#ifndef NOTIFYICON_VERSION_4 +#define NOTIFYICON_VERSION_4 4 +#endif + namespace lime { From 8aa354e70a28069d3011f040816c1a3a1bf7edad Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 9 Oct 2026 16:37:32 -0400 Subject: [PATCH 114/251] VideoDecoder: Add native video decoding lime.media.VideoDecoder decodes a video's pictures and sound on two native threads, one per stream, each queueing a few frames or a fraction of a second of audio ahead of the reader. readFrame and readAudio never block, so they can be called every frame from the main thread on hxcpp, HashLink and Neko alike. Frames come as NV12 (luma plus interleaved chroma, for a YUV shader) or RGBA, with the stream's color matrix and range so conversions agree. readFrame takes the playback time and skips frames that are already replaced without copying them. Seeks can land exactly on a time, dropping the frames and audio before it. Audio is 16-bit PCM with at most two channels, mixed down when the source has more. Platform decoders implement the small VideoBackend interface. This adds the Windows one, using Media Foundation loaded at runtime so Windows N editions still start. It decodes on the GPU through D3D11 by default, which takes far less CPU than software decoding, and falls back to software when the hardware cannot handle a stream. --- project/Build.xml | 3 + project/include/media/VideoDecoder.h | 234 ++++ project/src/ExternalInterface.cpp | 3 + project/src/media/video/MFVideoBackend.cpp | 1095 +++++++++++++++++ project/src/media/video/VideoDecoder.cpp | 650 ++++++++++ .../src/media/video/VideoDecoderBindings.cpp | 364 ++++++ .../_internal/backend/native/NativeCFFI.hx | 85 ++ src/lime/media/VideoColorMatrix.hx | 25 + src/lime/media/VideoDecoder.hx | 391 ++++++ src/lime/media/VideoFrame.hx | 111 ++ src/lime/media/VideoFrameFormat.hx | 25 + 11 files changed, 2986 insertions(+) create mode 100644 project/include/media/VideoDecoder.h create mode 100644 project/src/media/video/MFVideoBackend.cpp create mode 100644 project/src/media/video/VideoDecoder.cpp create mode 100644 project/src/media/video/VideoDecoderBindings.cpp create mode 100644 src/lime/media/VideoColorMatrix.hx create mode 100644 src/lime/media/VideoDecoder.hx create mode 100644 src/lime/media/VideoFrame.hx create mode 100644 src/lime/media/VideoFrameFormat.hx diff --git a/project/Build.xml b/project/Build.xml index 3acca44b92..d41135dd03 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -341,6 +341,9 @@ + + + diff --git a/project/include/media/VideoDecoder.h b/project/include/media/VideoDecoder.h new file mode 100644 index 0000000000..1a2e8662cd --- /dev/null +++ b/project/include/media/VideoDecoder.h @@ -0,0 +1,234 @@ +#ifndef LIME_MEDIA_VIDEO_DECODER_H +#define LIME_MEDIA_VIDEO_DECODER_H + + +#include +#include +#include +#include +#include + +#if defined (HX_WINDOWS) && !defined (HX_WINRT) +#define LIME_VIDEO_MEDIA_FOUNDATION +#elif defined (HX_MACOS) || (defined (IPHONE) && !defined (APPLETV)) +#define LIME_VIDEO_AVFOUNDATION +#elif defined (HX_ANDROID) +#define LIME_VIDEO_MEDIACODEC +#elif defined (HX_LINUX) && !defined (EMSCRIPTEN) +#define LIME_VIDEO_GSTREAMER +#endif + + +namespace lime { + + + enum VideoColorMatrix { + + VIDEO_COLOR_MATRIX_BT601 = 0, + VIDEO_COLOR_MATRIX_BT709 = 1, + VIDEO_COLOR_MATRIX_BT2020 = 2 + + }; + + + enum VideoDecodeResult { + + VIDEO_DECODE_OK = 1, + VIDEO_DECODE_END = 0, + VIDEO_DECODE_ERROR = -1 + + }; + + + enum VideoFrameFormat { + + VIDEO_FRAME_FORMAT_NV12 = 0, + VIDEO_FRAME_FORMAT_RGBA = 1 + + }; + + + enum VideoReadResult { + + VIDEO_READ_NOT_READY = 0, + VIDEO_READ_END = -1, + VIDEO_READ_ERROR = -2, + VIDEO_READ_BUFFER_TOO_SMALL = -3 + + }; + + + // A decoded picture in system memory. NV12 sets u to the interleaved UV + // plane, v to u + 1 and uvPixelStride to 2. I420 uses separate U and V + // planes with a uvPixelStride of 1. + struct VideoPlanes { + + VideoColorMatrix colorMatrix; + bool fullRange; + int height; + const unsigned char* u; + int uvPixelStride; + int uvStride; + const unsigned char* v; + int width; + const unsigned char* y; + int yStride; + + }; + + + struct VideoStreamInfo { + + int audioChannels; + int audioSampleRate; + double duration; + double frameRate; + bool hasAudio; + bool hasVideo; + int height; + int width; + + }; + + + // Platform decoding. VideoDecoder calls DecodeAudio and DecodeVideo from + // two threads at once, so the streams must not share decoder state. Open, + // Close and Seek are only called while neither stream is decoding. + class VideoBackend { + + + public: + + virtual ~VideoBackend () {}; + + virtual void Close () = 0; + + // Appends the next packet of interleaved signed 16-bit PCM with + // info->audioChannels channels to pcm, and sets time to the time of + // its first sample in seconds. + virtual VideoDecodeResult DecodeAudio (std::vector* pcm, double* time) = 0; + + // Decodes the next frame. The planes stay valid until the next call to + // DecodeVideo, Seek or Close. + virtual VideoDecodeResult DecodeVideo (VideoPlanes* planes, double* time, double* duration) = 0; + + virtual bool Open (const char* path, bool hardwareDecoding, VideoStreamInfo* info) = 0; + + // Seeks both streams to the keyframe at or before time. + virtual bool Seek (double time) = 0; + + static VideoBackend* Create (); + static bool IsSupported (); + + static void DownmixToStereo (const short* in, int frames, int channels, std::vector* pcm); + static VideoColorMatrix GetDefaultColorMatrix (int width, int height); + + + }; + + + // Decodes a video on two background threads, one per stream, and queues + // a few frames and a fraction of a second of audio ahead of the reader. + class VideoDecoder { + + + public: + + VideoDecoder (VideoBackend* backend); + ~VideoDecoder (); + + void Close (); + bool Open (const char* path, bool hardwareDecoding, VideoFrameFormat format); + + // Returns the number of bytes written, VIDEO_READ_NOT_READY when no + // audio is buffered yet, VIDEO_READ_END or VIDEO_READ_ERROR. Audio is + // interleaved signed 16-bit PCM. + int ReadAudio (unsigned char* data, int length); + + // Copies the next frame in the open format and returns the number of + // bytes written. When time is not negative, frames that ended by time + // are dropped and a frame is only returned once it starts by time. + // Returns VIDEO_READ_NOT_READY when no frame is due, VIDEO_READ_END, + // VIDEO_READ_ERROR, or VIDEO_READ_BUFFER_TOO_SMALL when the frame needs + // frameLength bytes. The frame then stays queued. + int ReadFrame (unsigned char* data, int length, double time); + + // Seeks both streams. An accurate seek drops the frames and audio + // before time, otherwise reading resumes from the preceding keyframe. + void Seek (double time, bool accurate); + + static int GetFrameLength (VideoFrameFormat format, int width, int height); + static int WriteFrame (const VideoPlanes* planes, VideoFrameFormat format, unsigned char* data, int length); + + double audioTime; + VideoFrameFormat format; + VideoColorMatrix frameColorMatrix; + double frameDuration; + bool frameFullRange; + int frameHeight; + int frameLength; + double frameTime; + int frameWidth; + VideoStreamInfo info; + + private: + + struct AudioChunk { + + std::vector data; + size_t offset; + double time; + + }; + + struct Frame { + + VideoColorMatrix colorMatrix; + std::vector data; + double duration; + bool fullRange; + int height; + int length; + double time; + int width; + + }; + + void AudioThread (); + void Flush (); + void StartThreads (); + void StopThreads (); + void VideoThread (); + + std::deque audioChunks; + std::condition_variable audioCondition; + std::mutex audioDecodeMutex; + bool audioEnded; + bool audioError; + size_t audioQueued; + double audioQueueEnd; + std::thread audioThread; + VideoBackend* backend; + std::vector freeChunks; + std::vector freeFrames; + std::deque frames; + std::mutex mutex; + bool open; + bool quit; + bool seekAccurate; + bool seekPending; + double seekTime; + std::condition_variable videoCondition; + std::mutex videoDecodeMutex; + bool videoEnded; + bool videoError; + std::thread videoThread; + + + }; + + +} + + +#endif diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 5d8c376d6c..0bc78042b1 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -14451,6 +14451,8 @@ extern "C" int lime_opengl_register_prims (); extern "C" int lime_opengl_register_prims () { return 0; } #endif +extern "C" int lime_video_register_prims (); + #ifdef LIME_VORBIS extern "C" int lime_vorbis_register_prims (); #else @@ -14465,6 +14467,7 @@ extern "C" int lime_register_prims () { lime_harfbuzz_register_prims (); lime_openal_register_prims (); lime_opengl_register_prims (); + lime_video_register_prims (); lime_vorbis_register_prims (); return 0; diff --git a/project/src/media/video/MFVideoBackend.cpp b/project/src/media/video/MFVideoBackend.cpp new file mode 100644 index 0000000000..c2ec689c35 --- /dev/null +++ b/project/src/media/video/MFVideoBackend.cpp @@ -0,0 +1,1095 @@ +#if defined (HX_WINDOWS) && !defined (HX_WINRT) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +// Declares the Windows 8 DXGI device manager, which is loaded at runtime +#if !defined (_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif +#if !defined (WINVER) || WINVER < 0x0602 +#undef WINVER +#define WINVER 0x0602 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include + + +#ifdef LIME_VIDEO_MEDIA_FOUNDATION + + +namespace lime { + + + // Media Foundation is missing from Windows N editions, so it is loaded at + // runtime instead of linked + typedef HRESULT (WINAPI *MFCreateAttributesFunc) (IMFAttributes**, UINT32); + typedef HRESULT (WINAPI *MFCreateDXGIDeviceManagerFunc) (UINT*, IMFDXGIDeviceManager**); + typedef HRESULT (WINAPI *MFCreateMediaTypeFunc) (IMFMediaType**); + typedef HRESULT (WINAPI *MFCreateSourceReaderFromURLFunc) (LPCWSTR, IMFAttributes*, IMFSourceReader**); + typedef HRESULT (WINAPI *MFShutdownFunc) (); + typedef HRESULT (WINAPI *MFStartupFunc) (ULONG, DWORD); + + // GUID_NULL, the 100-nanosecond time format for SetCurrentPosition + static const GUID TIME_FORMAT_100NS = {}; + + // Hardware frames are copied to staging textures and mapped STAGING_DELAY + // frames later, so reading them back does not wait for the GPU + static const int STAGING_DELAY = 2; + static const int STAGING_TEXTURES = 4; + + static PFN_D3D11_CREATE_DEVICE _D3D11CreateDevice = 0; + static MFCreateAttributesFunc _MFCreateAttributes = 0; + static MFCreateDXGIDeviceManagerFunc _MFCreateDXGIDeviceManager = 0; + static MFCreateMediaTypeFunc _MFCreateMediaType = 0; + static MFCreateSourceReaderFromURLFunc _MFCreateSourceReaderFromURL = 0; + static MFShutdownFunc _MFShutdown = 0; + static MFStartupFunc _MFStartup = 0; + + static std::once_flag loadFlag; + static bool loaded = false; + + + static bool LoadMediaFoundation () { + + std::call_once (loadFlag, [] { + + HMODULE mfplat = LoadLibraryW (L"mfplat.dll"); + HMODULE mfreadwrite = LoadLibraryW (L"mfreadwrite.dll"); + + if (!mfplat || !mfreadwrite) return; + + _MFCreateAttributes = (MFCreateAttributesFunc)GetProcAddress (mfplat, "MFCreateAttributes"); + _MFCreateDXGIDeviceManager = (MFCreateDXGIDeviceManagerFunc)GetProcAddress (mfplat, "MFCreateDXGIDeviceManager"); + _MFCreateMediaType = (MFCreateMediaTypeFunc)GetProcAddress (mfplat, "MFCreateMediaType"); + _MFShutdown = (MFShutdownFunc)GetProcAddress (mfplat, "MFShutdown"); + _MFStartup = (MFStartupFunc)GetProcAddress (mfplat, "MFStartup"); + _MFCreateSourceReaderFromURL = (MFCreateSourceReaderFromURLFunc)GetProcAddress (mfreadwrite, "MFCreateSourceReaderFromURL"); + + HMODULE d3d11 = LoadLibraryW (L"d3d11.dll"); + if (d3d11) _D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress (d3d11, "D3D11CreateDevice"); + + loaded = (_MFCreateAttributes && _MFCreateMediaType && _MFShutdown && _MFStartup && _MFCreateSourceReaderFromURL); + + }); + + return loaded; + + } + + + static void InitializeCOM () { + + // Media Foundation objects are free-threaded, so each decoding thread + // joins the multithreaded apartment. A thread that is already in an + // apartment keeps it. + static thread_local bool initialized = false; + + if (!initialized) { + + CoInitializeEx (NULL, COINIT_MULTITHREADED); + initialized = true; + + } + + } + + + static std::wstring GetURL (const char* path) { + + int length = MultiByteToWideChar (CP_UTF8, 0, path, -1, NULL, 0); + if (length <= 0) return std::wstring (); + + std::wstring wide (length, 0); + MultiByteToWideChar (CP_UTF8, 0, path, -1, &wide[0], length); + wide.resize (length - 1); + + if (wide.find (L"://") != std::wstring::npos) return wide; + + DWORD fullLength = GetFullPathNameW (wide.c_str (), 0, NULL, NULL); + if (fullLength == 0) return wide; + + std::wstring full (fullLength, 0); + fullLength = GetFullPathNameW (wide.c_str (), fullLength, &full[0], NULL); + full.resize (fullLength); + return full; + + } + + + class MFVideoBackend : public VideoBackend { + + + public: + + MFVideoBackend (); + ~MFVideoBackend (); + + virtual void Close (); + virtual VideoDecodeResult DecodeAudio (std::vector* pcm, double* time); + virtual VideoDecodeResult DecodeVideo (VideoPlanes* planes, double* time, double* duration); + virtual bool Open (const char* path, bool hardwareDecoding, VideoStreamInfo* info); + virtual bool Seek (double time); + + private: + + void ClearStaging (); + bool CopyToStaging (IMFSample* sample, LONGLONG timestamp, LONGLONG sampleDuration); + bool CreateDeviceManager (); + void GetPlanes (VideoPlanes* planes, BYTE* data, int pitch, int lumaRows); + VideoDecodeResult MapStaging (VideoPlanes* planes, double* time, double* duration); + bool OpenAudio (); + bool OpenVideo (bool hardware); + void ReadVideoFormat (); + void ReleaseDeviceManager (); + void UnlockVideo (); + + int audioChannels; + IMFSourceReader* audioReader; + int audioSampleRate; + int audioSourceChannels; + int bufferHeight; + int bufferWidth; + VideoColorMatrix colorMatrix; + int cropHeight; + int cropWidth; + int cropX; + int cropY; + ID3D11DeviceContext* context; + LONG defaultStride; + ID3D11Device* device; + IMFDXGIDeviceManager* deviceManager; + double frameRate; + bool fullRange; + bool hardwareActive; + IMF2DBuffer* locked2D; + IMFMediaBuffer* lockedBuffer; + ID3D11Texture2D* staging[STAGING_TEXTURES]; + LONGLONG stagingDurations[STAGING_TEXTURES]; + bool stagingFailed; + UINT stagingHeight; + int stagingMapped; + std::deque stagingQueue; + LONGLONG stagingTimes[STAGING_TEXTURES]; + UINT stagingWidth; + bool started; + std::wstring url; + bool videoEnded; + LONGLONG videoPosition; + IMFSourceReader* videoReader; + + + }; + + + MFVideoBackend::MFVideoBackend () { + + audioChannels = 0; + audioReader = NULL; + audioSampleRate = 0; + audioSourceChannels = 0; + bufferHeight = 0; + bufferWidth = 0; + colorMatrix = VIDEO_COLOR_MATRIX_BT709; + cropHeight = 0; + cropWidth = 0; + cropX = 0; + cropY = 0; + context = NULL; + defaultStride = 0; + device = NULL; + deviceManager = NULL; + frameRate = 0; + fullRange = false; + hardwareActive = false; + locked2D = NULL; + lockedBuffer = NULL; + stagingFailed = false; + stagingHeight = 0; + stagingMapped = -1; + stagingWidth = 0; + videoEnded = false; + videoPosition = 0; + videoReader = NULL; + + for (int i = 0; i < STAGING_TEXTURES; i++) staging[i] = NULL; + + InitializeCOM (); + started = SUCCEEDED (_MFStartup (MF_VERSION, MFSTARTUP_FULL)); + + } + + + MFVideoBackend::~MFVideoBackend () { + + Close (); + + if (started) _MFShutdown (); + + } + + + void MFVideoBackend::Close () { + + UnlockVideo (); + + if (videoReader) { + + videoReader->Release (); + videoReader = NULL; + + } + + if (audioReader) { + + audioReader->Release (); + audioReader = NULL; + + } + + ReleaseDeviceManager (); + + audioChannels = 0; + audioSampleRate = 0; + audioSourceChannels = 0; + hardwareActive = false; + stagingFailed = false; + videoEnded = false; + videoPosition = 0; + + } + + + void MFVideoBackend::ClearStaging () { + + if (stagingMapped >= 0) { + + context->Unmap (staging[stagingMapped], 0); + stagingMapped = -1; + + } + + stagingQueue.clear (); + + } + + + bool MFVideoBackend::CopyToStaging (IMFSample* sample, LONGLONG timestamp, LONGLONG sampleDuration) { + + if (!context || stagingFailed) return false; + + IMFMediaBuffer* buffer = NULL; + IMFDXGIBuffer* dxgiBuffer = NULL; + ID3D11Texture2D* texture = NULL; + UINT subresource = 0; + bool copied = false; + + if (SUCCEEDED (sample->GetBufferByIndex (0, &buffer)) && SUCCEEDED (buffer->QueryInterface (IID_PPV_ARGS (&dxgiBuffer))) + && SUCCEEDED (dxgiBuffer->GetResource (IID_PPV_ARGS (&texture))) && SUCCEEDED (dxgiBuffer->GetSubresourceIndex (&subresource))) { + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc (&desc); + + if (desc.Format == DXGI_FORMAT_NV12 && (desc.Width != stagingWidth || desc.Height != stagingHeight)) { + + ClearStaging (); + + for (int i = 0; i < STAGING_TEXTURES; i++) { + + if (staging[i]) staging[i]->Release (); + staging[i] = NULL; + + } + + D3D11_TEXTURE2D_DESC stagingDesc = {}; + stagingDesc.Width = desc.Width; + stagingDesc.Height = desc.Height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = DXGI_FORMAT_NV12; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + + bool created = true; + + for (int i = 0; i < STAGING_TEXTURES && created; i++) { + + created = SUCCEEDED (device->CreateTexture2D (&stagingDesc, NULL, &staging[i])); + + } + + stagingWidth = created ? desc.Width : 0; + stagingHeight = created ? desc.Height : 0; + + } + + if (desc.Format == DXGI_FORMAT_NV12 && stagingWidth == desc.Width && stagingHeight == desc.Height) { + + // Use a texture that is neither mapped nor waiting to be + int index = -1; + + for (int i = 0; i < STAGING_TEXTURES && index < 0; i++) { + + bool used = (i == stagingMapped); + for (size_t j = 0; j < stagingQueue.size () && !used; j++) used = (stagingQueue[j] == i); + if (!used) index = i; + + } + + if (index >= 0) { + + context->CopySubresourceRegion (staging[index], 0, 0, 0, 0, texture, subresource, NULL); + stagingDurations[index] = sampleDuration; + stagingTimes[index] = timestamp; + stagingQueue.push_back (index); + copied = true; + + } + + } + + } + + if (texture) texture->Release (); + if (dxgiBuffer) dxgiBuffer->Release (); + if (buffer) buffer->Release (); + + // The frames already queued would come out of order, so they are + // dropped if copying stops working + if (!copied) { + + stagingFailed = true; + ClearStaging (); + + } + + return copied; + + } + + + bool MFVideoBackend::CreateDeviceManager () { + + if (deviceManager) return true; + if (!_D3D11CreateDevice || !_MFCreateDXGIDeviceManager) return false; + + static const D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3 }; + + UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; + HRESULT hr = _D3D11CreateDevice (NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, ARRAYSIZE (levels), D3D11_SDK_VERSION, &device, NULL, NULL); + + if (hr == E_INVALIDARG) { + + // Windows 7 without the platform update does not know 11.1 + hr = _D3D11CreateDevice (NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels + 1, ARRAYSIZE (levels) - 1, D3D11_SDK_VERSION, &device, NULL, NULL); + + } + + if (FAILED (hr) || !device) { + + device = NULL; + return false; + + } + + device->GetImmediateContext (&context); + + // Media Foundation uses the device from its own threads + ID3D10Multithread* multithread = NULL; + + if (SUCCEEDED (device->QueryInterface (IID_PPV_ARGS (&multithread)))) { + + multithread->SetMultithreadProtected (TRUE); + multithread->Release (); + + } + + UINT token = 0; + + if (FAILED (_MFCreateDXGIDeviceManager (&token, &deviceManager)) || FAILED (deviceManager->ResetDevice (device, token))) { + + ReleaseDeviceManager (); + return false; + + } + + return true; + + } + + + VideoDecodeResult MFVideoBackend::DecodeAudio (std::vector* pcm, double* time) { + + if (!audioReader) return VIDEO_DECODE_END; + + InitializeCOM (); + + while (true) { + + DWORD flags = 0; + LONGLONG timestamp = 0; + IMFSample* sample = NULL; + + HRESULT hr = audioReader->ReadSample (MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &flags, ×tamp, &sample); + + if (FAILED (hr) || (flags & MF_SOURCE_READERF_ERROR)) { + + if (sample) sample->Release (); + return VIDEO_DECODE_ERROR; + + } + + if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { + + if (sample) sample->Release (); + return VIDEO_DECODE_END; + + } + + if (!sample) continue; + + IMFMediaBuffer* buffer = NULL; + hr = sample->ConvertToContiguousBuffer (&buffer); + sample->Release (); + + if (FAILED (hr)) return VIDEO_DECODE_ERROR; + + BYTE* data = NULL; + DWORD length = 0; + + if (FAILED (buffer->Lock (&data, NULL, &length))) { + + buffer->Release (); + return VIDEO_DECODE_ERROR; + + } + + *time = timestamp / 10000000.0; + + if (audioSourceChannels == audioChannels) { + + pcm->insert (pcm->end (), data, data + length); + + } else { + + DownmixToStereo ((const short*)data, length / (audioSourceChannels * 2), audioSourceChannels, pcm); + + } + + buffer->Unlock (); + buffer->Release (); + + return VIDEO_DECODE_OK; + + } + + } + + + VideoDecodeResult MFVideoBackend::DecodeVideo (VideoPlanes* planes, double* time, double* duration) { + + UnlockVideo (); + + if (!videoReader) return VIDEO_DECODE_END; + + InitializeCOM (); + + while (true) { + + if (!stagingQueue.empty () && (stagingQueue.size () >= (size_t)STAGING_DELAY || videoEnded)) { + + return MapStaging (planes, time, duration); + + } + + if (videoEnded) return VIDEO_DECODE_END; + + DWORD flags = 0; + LONGLONG timestamp = 0; + IMFSample* sample = NULL; + + HRESULT hr = videoReader->ReadSample (MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, &flags, ×tamp, &sample); + + if (FAILED (hr) || (flags & MF_SOURCE_READERF_ERROR)) { + + if (sample) sample->Release (); + + if (hardwareActive) { + + // Some drivers fail to decode a stream they accepted, so continue + // from the same position in software + ClearStaging (); + videoReader->Release (); + videoReader = NULL; + ReleaseDeviceManager (); + + if (OpenVideo (false)) { + + PROPVARIANT position; + PropVariantInit (&position); + position.vt = VT_I8; + position.hVal.QuadPart = videoPosition; + videoReader->SetCurrentPosition (TIME_FORMAT_100NS, position); + continue; + + } + + } + + return VIDEO_DECODE_ERROR; + + } + + if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) ReadVideoFormat (); + + if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { + + if (sample) sample->Release (); + videoEnded = true; + continue; + + } + + if (!sample) continue; + + LONGLONG sampleDuration = 0; + sample->GetSampleDuration (&sampleDuration); + + if (hardwareActive && CopyToStaging (sample, timestamp, sampleDuration)) { + + sample->Release (); + continue; + + } + + IMFMediaBuffer* buffer = NULL; + DWORD bufferCount = 0; + sample->GetBufferCount (&bufferCount); + + if (bufferCount == 1) { + + hr = sample->GetBufferByIndex (0, &buffer); + + } else { + + hr = sample->ConvertToContiguousBuffer (&buffer); + + } + + sample->Release (); + + if (FAILED (hr)) return VIDEO_DECODE_ERROR; + + BYTE* data = NULL; + LONG pitch = 0; + DWORD length = 0; + IMF2DBuffer2* buffer2D2 = NULL; + IMF2DBuffer* buffer2D = NULL; + + if (SUCCEEDED (buffer->QueryInterface (IID_PPV_ARGS (&buffer2D2)))) { + + BYTE* start = NULL; + + if (SUCCEEDED (buffer2D2->Lock2DSize (MF2DBuffer_LockFlags_Read, &data, &pitch, &start, &length))) { + + buffer2D = buffer2D2; + + } else { + + buffer2D2->Release (); + + } + + } + + if (!buffer2D && SUCCEEDED (buffer->QueryInterface (IID_PPV_ARGS (&buffer2D)))) { + + if (FAILED (buffer2D->Lock2D (&data, &pitch))) { + + buffer2D->Release (); + buffer2D = NULL; + + } + + } + + if (!buffer2D) { + + if (FAILED (buffer->Lock (&data, NULL, &length))) { + + buffer->Release (); + return VIDEO_DECODE_ERROR; + + } + + pitch = defaultStride > 0 ? defaultStride : bufferWidth; + + } + + lockedBuffer = buffer; + locked2D = buffer2D; + + if (pitch <= 0 || !data) { + + UnlockVideo (); + return VIDEO_DECODE_ERROR; + + } + + // The luma plane is normally the frame size from the media type, but + // some decoders align the surface further + int lumaRows = bufferHeight; + + if (length > 0) { + + int rows = (int)(length / pitch); + int alignedRows = (rows * 2) / 3; + if (alignedRows > lumaRows && alignedRows <= lumaRows + 64) lumaRows = alignedRows; + + if ((DWORD)pitch * (lumaRows + (lumaRows + 1) / 2) > length) { + + UnlockVideo (); + return VIDEO_DECODE_ERROR; + + } + + } + + GetPlanes (planes, data, pitch, lumaRows); + + videoPosition = timestamp; + *time = timestamp / 10000000.0; + *duration = sampleDuration > 0 ? sampleDuration / 10000000.0 : (frameRate > 0 ? 1.0 / frameRate : 0); + + return VIDEO_DECODE_OK; + + } + + } + + + void MFVideoBackend::GetPlanes (VideoPlanes* planes, BYTE* data, int pitch, int lumaRows) { + + planes->colorMatrix = colorMatrix; + planes->fullRange = fullRange; + planes->width = cropWidth; + planes->height = cropHeight; + planes->y = data + cropY * pitch + cropX; + planes->yStride = pitch; + planes->u = data + lumaRows * pitch + (cropY / 2) * pitch + (cropX & ~1); + planes->v = planes->u + 1; + planes->uvStride = pitch; + planes->uvPixelStride = 2; + + } + + + VideoDecodeResult MFVideoBackend::MapStaging (VideoPlanes* planes, double* time, double* duration) { + + int index = stagingQueue.front (); + stagingQueue.pop_front (); + + D3D11_MAPPED_SUBRESOURCE mapped; + if (FAILED (context->Map (staging[index], 0, D3D11_MAP_READ, 0, &mapped))) return VIDEO_DECODE_ERROR; + + stagingMapped = index; + + // The chroma plane of a mapped NV12 texture follows its luma rows + GetPlanes (planes, (BYTE*)mapped.pData, (int)mapped.RowPitch, (int)stagingHeight); + + videoPosition = stagingTimes[index]; + *time = stagingTimes[index] / 10000000.0; + *duration = stagingDurations[index] > 0 ? stagingDurations[index] / 10000000.0 : (frameRate > 0 ? 1.0 / frameRate : 0); + + return VIDEO_DECODE_OK; + + } + + + bool MFVideoBackend::Open (const char* path, bool hardwareDecoding, VideoStreamInfo* info) { + + Close (); + + if (!started || !path || !path[0]) return false; + + InitializeCOM (); + + url = GetURL (path); + if (url.empty ()) return false; + + info->hasVideo = OpenVideo (hardwareDecoding) || (hardwareDecoding && OpenVideo (false)); + info->hasAudio = OpenAudio (); + + if (!info->hasVideo && !info->hasAudio) return false; + + IMFSourceReader* reader = videoReader ? videoReader : audioReader; + PROPVARIANT duration; + PropVariantInit (&duration); + + if (SUCCEEDED (reader->GetPresentationAttribute (MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &duration)) && duration.vt == VT_UI8) { + + info->duration = duration.uhVal.QuadPart / 10000000.0; + + } + + PropVariantClear (&duration); + + info->audioChannels = audioChannels; + info->audioSampleRate = audioSampleRate; + info->frameRate = frameRate; + info->width = info->hasVideo ? cropWidth : 0; + info->height = info->hasVideo ? cropHeight : 0; + + return true; + + } + + + bool MFVideoBackend::OpenAudio () { + + IMFSourceReader* reader = NULL; + + if (FAILED (_MFCreateSourceReaderFromURL (url.c_str (), NULL, &reader))) return false; + + reader->SetStreamSelection (MF_SOURCE_READER_ALL_STREAMS, FALSE); + + IMFMediaType* nativeType = NULL; + + if (FAILED (reader->SetStreamSelection (MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE)) || FAILED (reader->GetNativeMediaType (MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, &nativeType))) { + + reader->Release (); + return false; + + } + + UINT32 sourceChannels = MFGetAttributeUINT32 (nativeType, MF_MT_AUDIO_NUM_CHANNELS, 0); + nativeType->Release (); + + IMFMediaType* type = NULL; + bool configured = false; + + // Ask the decoder to downmix first, and downmix here if it cannot + for (int attempt = 0; attempt < 2 && !configured; attempt++) { + + bool downmix = (attempt == 0 && sourceChannels > 2); + if (attempt == 1 && sourceChannels <= 2) break; + if (FAILED (_MFCreateMediaType (&type))) break; + + type->SetGUID (MF_MT_MAJOR_TYPE, MFMediaType_Audio); + type->SetGUID (MF_MT_SUBTYPE, MFAudioFormat_PCM); + type->SetUINT32 (MF_MT_AUDIO_BITS_PER_SAMPLE, 16); + if (downmix) type->SetUINT32 (MF_MT_AUDIO_NUM_CHANNELS, 2); + + configured = SUCCEEDED (reader->SetCurrentMediaType (MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, type)); + type->Release (); + type = NULL; + + } + + IMFMediaType* currentType = NULL; + + if (!configured || FAILED (reader->GetCurrentMediaType (MF_SOURCE_READER_FIRST_AUDIO_STREAM, ¤tType))) { + + reader->Release (); + return false; + + } + + UINT32 bits = MFGetAttributeUINT32 (currentType, MF_MT_AUDIO_BITS_PER_SAMPLE, 0); + UINT32 channels = MFGetAttributeUINT32 (currentType, MF_MT_AUDIO_NUM_CHANNELS, 0); + UINT32 sampleRate = MFGetAttributeUINT32 (currentType, MF_MT_AUDIO_SAMPLES_PER_SECOND, 0); + currentType->Release (); + + if (bits != 16 || channels == 0 || channels > 8 || sampleRate == 0) { + + reader->Release (); + return false; + + } + + audioReader = reader; + audioSampleRate = (int)sampleRate; + audioSourceChannels = (int)channels; + audioChannels = channels > 2 ? 2 : (int)channels; + + return true; + + } + + + bool MFVideoBackend::OpenVideo (bool hardware) { + + IMFAttributes* attributes = NULL; + if (FAILED (_MFCreateAttributes (&attributes, 4))) return false; + + if (hardware && CreateDeviceManager ()) { + + attributes->SetUnknown (MF_SOURCE_READER_D3D_MANAGER, deviceManager); + attributes->SetUINT32 (MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE); + attributes->SetUINT32 (MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE); + + } else { + + hardware = false; + attributes->SetUINT32 (MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE); + + } + + IMFSourceReader* reader = NULL; + HRESULT hr = _MFCreateSourceReaderFromURL (url.c_str (), attributes, &reader); + attributes->Release (); + + if (FAILED (hr)) { + + if (hardware) ReleaseDeviceManager (); + return false; + + } + + reader->SetStreamSelection (MF_SOURCE_READER_ALL_STREAMS, FALSE); + + IMFMediaType* type = NULL; + bool configured = SUCCEEDED (reader->SetStreamSelection (MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE)) && SUCCEEDED (_MFCreateMediaType (&type)); + + if (configured) { + + type->SetGUID (MF_MT_MAJOR_TYPE, MFMediaType_Video); + type->SetGUID (MF_MT_SUBTYPE, MFVideoFormat_NV12); + configured = SUCCEEDED (reader->SetCurrentMediaType (MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, type)); + type->Release (); + + } + + if (!configured) { + + reader->Release (); + if (hardware) ReleaseDeviceManager (); + return false; + + } + + videoReader = reader; + hardwareActive = hardware; + ReadVideoFormat (); + + if (cropWidth <= 0 || cropHeight <= 0) { + + videoReader->Release (); + videoReader = NULL; + if (hardware) ReleaseDeviceManager (); + return false; + + } + + return true; + + } + + + void MFVideoBackend::ReadVideoFormat () { + + IMFMediaType* type = NULL; + if (FAILED (videoReader->GetCurrentMediaType (MF_SOURCE_READER_FIRST_VIDEO_STREAM, &type))) return; + + UINT32 width = 0; + UINT32 height = 0; + MFGetAttributeSize (type, MF_MT_FRAME_SIZE, &width, &height); + + bufferWidth = (int)width; + bufferHeight = (int)height; + cropX = 0; + cropY = 0; + cropWidth = (int)width; + cropHeight = (int)height; + + MFVideoArea area; + + if (SUCCEEDED (type->GetBlob (MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&area, sizeof (area), NULL))) { + + int x = area.OffsetX.value; + int y = area.OffsetY.value; + + if (x >= 0 && y >= 0 && area.Area.cx > 0 && area.Area.cy > 0 && x + area.Area.cx <= (int)width && y + area.Area.cy <= (int)height) { + + cropX = x; + cropY = y; + cropWidth = area.Area.cx; + cropHeight = area.Area.cy; + + } + + } + + UINT32 stride = 0; + defaultStride = SUCCEEDED (type->GetUINT32 (MF_MT_DEFAULT_STRIDE, &stride)) ? (LONG)stride : (LONG)width; + + UINT32 numerator = 0; + UINT32 denominator = 0; + + if (SUCCEEDED (MFGetAttributeRatio (type, MF_MT_FRAME_RATE, &numerator, &denominator)) && denominator > 0) { + + frameRate = (double)numerator / denominator; + + } + + // Video processing can drop the color attributes, so fall back to the + // stream's own media type + IMFMediaType* nativeType = NULL; + videoReader->GetNativeMediaType (MF_SOURCE_READER_FIRST_VIDEO_STREAM, MF_SOURCE_READER_CURRENT_TYPE_INDEX, &nativeType); + + UINT32 matrix = MFGetAttributeUINT32 (type, MF_MT_YUV_MATRIX, MFVideoTransferMatrix_Unknown); + if (matrix == MFVideoTransferMatrix_Unknown && nativeType) matrix = MFGetAttributeUINT32 (nativeType, MF_MT_YUV_MATRIX, MFVideoTransferMatrix_Unknown); + + UINT32 range = MFGetAttributeUINT32 (type, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + if (range == MFNominalRange_Unknown && nativeType) range = MFGetAttributeUINT32 (nativeType, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + + if (nativeType) nativeType->Release (); + type->Release (); + + switch (matrix) { + + case MFVideoTransferMatrix_BT601: colorMatrix = VIDEO_COLOR_MATRIX_BT601; break; + case MFVideoTransferMatrix_BT709: colorMatrix = VIDEO_COLOR_MATRIX_BT709; break; + case 4: case 5: colorMatrix = VIDEO_COLOR_MATRIX_BT2020; break; + default: colorMatrix = GetDefaultColorMatrix (cropWidth, cropHeight); break; + + } + + fullRange = (range == MFNominalRange_0_255); + + } + + + void MFVideoBackend::ReleaseDeviceManager () { + + if (context) ClearStaging (); + + for (int i = 0; i < STAGING_TEXTURES; i++) { + + if (staging[i]) staging[i]->Release (); + staging[i] = NULL; + + } + + stagingHeight = 0; + stagingWidth = 0; + + if (context) { + + context->Release (); + context = NULL; + + } + + if (deviceManager) { + + deviceManager->Release (); + deviceManager = NULL; + + } + + if (device) { + + device->Release (); + device = NULL; + + } + + } + + + bool MFVideoBackend::Seek (double time) { + + UnlockVideo (); + stagingQueue.clear (); + videoEnded = false; + + PROPVARIANT position; + PropVariantInit (&position); + position.vt = VT_I8; + position.hVal.QuadPart = (LONGLONG)(time * 10000000.0); + + bool success = true; + + if (videoReader) { + + success = SUCCEEDED (videoReader->SetCurrentPosition (TIME_FORMAT_100NS, position)) && success; + videoPosition = position.hVal.QuadPart; + + } + + if (audioReader) success = SUCCEEDED (audioReader->SetCurrentPosition (TIME_FORMAT_100NS, position)) && success; + + return success; + + } + + + void MFVideoBackend::UnlockVideo () { + + if (stagingMapped >= 0) { + + context->Unmap (staging[stagingMapped], 0); + stagingMapped = -1; + + } + + if (locked2D) { + + locked2D->Unlock2D (); + locked2D->Release (); + locked2D = NULL; + + } else if (lockedBuffer) { + + lockedBuffer->Unlock (); + + } + + if (lockedBuffer) { + + lockedBuffer->Release (); + lockedBuffer = NULL; + + } + + } + + + VideoBackend* VideoBackend::Create () { + + return LoadMediaFoundation () ? new MFVideoBackend () : NULL; + + } + + + bool VideoBackend::IsSupported () { + + return LoadMediaFoundation (); + + } + + +} + + +#endif diff --git a/project/src/media/video/VideoDecoder.cpp b/project/src/media/video/VideoDecoder.cpp new file mode 100644 index 0000000000..0aa2c3b881 --- /dev/null +++ b/project/src/media/video/VideoDecoder.cpp @@ -0,0 +1,650 @@ +#include +#include + + +namespace lime { + + + // Decoding stops once this many frames or seconds of audio are queued + static const size_t MAX_QUEUED_FRAMES = 4; + static const double MAX_QUEUED_AUDIO = 0.75; + + + static inline unsigned char ClampByte (int value) { + + return value < 0 ? 0 : (value > 255 ? 255 : (unsigned char)value); + + } + + + // Folds the WAVE channel orders (3: FL FR FC, 4: FL FR BL BR, 5: FL FR FC BL + // BR, 6: FL FR FC LFE BL BR, 7.1 adds SL SR) into stereo, keeping the level + void VideoBackend::DownmixToStereo (const short* in, int frames, int channels, std::vector* pcm) { + + int center = (channels == 3 || channels == 5 || channels >= 6) ? 2 : -1; + int backLeft = channels == 4 ? 2 : (channels == 5 ? 3 : (channels >= 6 ? 4 : -1)); + int sideLeft = channels >= 8 ? 6 : -1; + float mix = 0.7071f; + float scale = 1.0f / (1.0f + (center >= 0 ? mix : 0) + (backLeft >= 0 ? mix : 0) + (sideLeft >= 0 ? mix : 0)); + + size_t offset = pcm->size (); + pcm->resize (offset + frames * 4); + short* out = (short*)(pcm->data () + offset); + + for (int i = 0; i < frames; i++) { + + const short* frame = in + i * channels; + float left = frame[0]; + float right = frame[1]; + + if (center >= 0) { left += frame[center] * mix; right += frame[center] * mix; } + if (backLeft >= 0) { left += frame[backLeft] * mix; right += frame[backLeft + 1] * mix; } + if (sideLeft >= 0) { left += frame[sideLeft] * mix; right += frame[sideLeft + 1] * mix; } + + out[i * 2] = (short)(left * scale); + out[i * 2 + 1] = (short)(right * scale); + + } + + } + + + VideoColorMatrix VideoBackend::GetDefaultColorMatrix (int width, int height) { + + // Streams without color information use BT.601 for SD and BT.709 for HD + return (width > 1024 || height >= 600) ? VIDEO_COLOR_MATRIX_BT709 : VIDEO_COLOR_MATRIX_BT601; + + } + + + #if !defined (LIME_VIDEO_MEDIA_FOUNDATION) && !defined (LIME_VIDEO_AVFOUNDATION) && !defined (LIME_VIDEO_MEDIACODEC) && !defined (LIME_VIDEO_GSTREAMER) + + VideoBackend* VideoBackend::Create () { + + return 0; + + } + + + bool VideoBackend::IsSupported () { + + return false; + + } + + #endif + + + VideoDecoder::VideoDecoder (VideoBackend* backend) : backend (backend) { + + audioEnded = true; + audioError = false; + audioQueued = 0; + audioQueueEnd = 0; + audioTime = 0; + format = VIDEO_FRAME_FORMAT_NV12; + frameColorMatrix = VIDEO_COLOR_MATRIX_BT709; + frameDuration = 0; + frameFullRange = false; + frameHeight = 0; + frameLength = 0; + frameTime = 0; + frameWidth = 0; + memset (&info, 0, sizeof (info)); + open = false; + quit = false; + seekAccurate = false; + seekPending = false; + seekTime = 0; + videoEnded = true; + videoError = false; + + } + + + VideoDecoder::~VideoDecoder () { + + Close (); + delete backend; + + } + + + void VideoDecoder::AudioThread () { + + std::vector pcm; + int blockAlign = info.audioChannels * 2; + double bytesPerSecond = (double)info.audioSampleRate * blockAlign; + size_t maxQueued = (size_t)(bytesPerSecond * MAX_QUEUED_AUDIO); + + while (true) { + + { + std::unique_lock lock (mutex); + audioCondition.wait (lock, [this, maxQueued] { return quit || (!seekPending && !audioEnded && audioQueued < maxQueued); }); + if (quit) break; + } + + std::lock_guard decodeLock (audioDecodeMutex); + + pcm.clear (); + double time = 0; + VideoDecodeResult result = backend->DecodeAudio (&pcm, &time); + + if (result != VIDEO_DECODE_OK) { + + std::lock_guard lock (mutex); + audioEnded = true; + audioError = (result == VIDEO_DECODE_ERROR); + continue; + + } + + size_t offset = 0; + size_t length = pcm.size () - (pcm.size () % blockAlign); + + if (seekAccurate && time < seekTime) { + + // Drop the audio before an accurate seek target + size_t skip = (size_t)((seekTime - time) * info.audioSampleRate + 0.5) * blockAlign; + if (skip >= length) continue; + offset = skip; + time = seekTime; + + } + + if (offset >= length) continue; + + std::lock_guard lock (mutex); + + AudioChunk* chunk; + + if (freeChunks.empty ()) { + + chunk = new AudioChunk (); + + } else { + + chunk = freeChunks.back (); + freeChunks.pop_back (); + + } + + chunk->data.assign (pcm.begin () + offset, pcm.begin () + length); + chunk->offset = 0; + chunk->time = time; + + audioChunks.push_back (chunk); + audioQueued += chunk->data.size (); + audioQueueEnd = time + chunk->data.size () / bytesPerSecond; + + } + + } + + + void VideoDecoder::Close () { + + if (!open) return; + + StopThreads (); + backend->Close (); + + std::lock_guard lock (mutex); + Flush (); + + for (size_t i = 0; i < freeChunks.size (); i++) delete freeChunks[i]; + for (size_t i = 0; i < freeFrames.size (); i++) delete freeFrames[i]; + freeChunks.clear (); + freeFrames.clear (); + + open = false; + audioEnded = true; + videoEnded = true; + memset (&info, 0, sizeof (info)); + + } + + + void VideoDecoder::Flush () { + + for (size_t i = 0; i < audioChunks.size (); i++) freeChunks.push_back (audioChunks[i]); + for (size_t i = 0; i < frames.size (); i++) freeFrames.push_back (frames[i]); + + audioChunks.clear (); + audioQueued = 0; + frames.clear (); + + } + + + int VideoDecoder::GetFrameLength (VideoFrameFormat format, int width, int height) { + + if (width <= 0 || height <= 0) return 0; + + switch (format) { + + case VIDEO_FRAME_FORMAT_NV12: return width * height + ((width + 1) / 2) * 2 * ((height + 1) / 2); + case VIDEO_FRAME_FORMAT_RGBA: return width * height * 4; + default: return 0; + + } + + } + + + bool VideoDecoder::Open (const char* path, bool hardwareDecoding, VideoFrameFormat format) { + + Close (); + + if (!backend || !path) return false; + + VideoStreamInfo streamInfo; + memset (&streamInfo, 0, sizeof (streamInfo)); + + if (!backend->Open (path, hardwareDecoding, &streamInfo)) { + + backend->Close (); + return false; + + } + + if (streamInfo.audioChannels < 1 || streamInfo.audioChannels > 2 || streamInfo.audioSampleRate <= 0) { + + streamInfo.hasAudio = false; + + } + + if (!streamInfo.hasAudio) { + + streamInfo.audioChannels = 0; + streamInfo.audioSampleRate = 0; + + } + + if (!streamInfo.hasAudio && !streamInfo.hasVideo) { + + backend->Close (); + return false; + + } + + info = streamInfo; + this->format = format; + + audioEnded = !info.hasAudio; + audioError = false; + audioQueueEnd = 0; + audioTime = 0; + frameColorMatrix = VideoBackend::GetDefaultColorMatrix (info.width, info.height); + frameDuration = info.frameRate > 0 ? 1.0 / info.frameRate : 0; + frameFullRange = false; + frameHeight = info.height; + frameLength = GetFrameLength (format, info.width, info.height); + frameTime = 0; + frameWidth = info.width; + seekAccurate = false; + seekPending = false; + seekTime = 0; + videoEnded = !info.hasVideo; + videoError = false; + + open = true; + StartThreads (); + return true; + + } + + + int VideoDecoder::ReadAudio (unsigned char* data, int length) { + + std::lock_guard lock (mutex); + + if (!open || !info.hasAudio) return VIDEO_READ_END; + + int blockAlign = info.audioChannels * 2; + double bytesPerSecond = (double)info.audioSampleRate * blockAlign; + length -= length % blockAlign; + + int written = 0; + + while (written < length && !audioChunks.empty ()) { + + AudioChunk* chunk = audioChunks.front (); + size_t available = chunk->data.size () - chunk->offset; + size_t count = (size_t)(length - written) < available ? (size_t)(length - written) : available; + + memcpy (data + written, chunk->data.data () + chunk->offset, count); + chunk->offset += count; + written += (int)count; + audioQueued -= count; + + if (chunk->offset >= chunk->data.size ()) { + + audioTime = chunk->time + chunk->data.size () / bytesPerSecond; + audioChunks.pop_front (); + freeChunks.push_back (chunk); + + } else { + + audioTime = chunk->time + chunk->offset / bytesPerSecond; + + } + + } + + if (written > 0) { + + audioCondition.notify_one (); + return written; + + } + + if (audioEnded) return audioError ? VIDEO_READ_ERROR : VIDEO_READ_END; + return VIDEO_READ_NOT_READY; + + } + + + int VideoDecoder::ReadFrame (unsigned char* data, int length, double time) { + + std::lock_guard lock (mutex); + + if (!open || !info.hasVideo) return VIDEO_READ_END; + + bool dropped = false; + + if (time >= 0) { + + // Drop frames that a later queued frame replaces by time + while (frames.size () > 1 && frames[1]->time <= time) { + + freeFrames.push_back (frames.front ()); + frames.pop_front (); + dropped = true; + + } + + } + + if (dropped) videoCondition.notify_one (); + + if (frames.empty ()) { + + if (videoEnded) return videoError ? VIDEO_READ_ERROR : VIDEO_READ_END; + return VIDEO_READ_NOT_READY; + + } + + Frame* frame = frames.front (); + + if (time >= 0 && frame->time > time) return VIDEO_READ_NOT_READY; + + frameColorMatrix = frame->colorMatrix; + frameDuration = frame->duration; + frameFullRange = frame->fullRange; + frameHeight = frame->height; + frameLength = frame->length; + frameTime = frame->time; + frameWidth = frame->width; + + if (!data || length < frame->length) return VIDEO_READ_BUFFER_TOO_SMALL; + + memcpy (data, frame->data.data (), frame->length); + + frames.pop_front (); + freeFrames.push_back (frame); + videoCondition.notify_one (); + + return frameLength; + + } + + + void VideoDecoder::Seek (double time, bool accurate) { + + if (!open) return; + if (time < 0) time = 0; + + { + std::lock_guard lock (mutex); + seekPending = true; + Flush (); + } + + audioCondition.notify_all (); + videoCondition.notify_all (); + + // Wait for the frame or packet in progress, then seek with both streams idle + std::lock_guard videoLock (videoDecodeMutex); + std::lock_guard audioLock (audioDecodeMutex); + + backend->Seek (time); + + std::lock_guard lock (mutex); + Flush (); + + audioEnded = !info.hasAudio; + audioError = false; + audioQueueEnd = time; + audioTime = time; + frameTime = time; + seekAccurate = accurate; + seekPending = false; + seekTime = time; + videoEnded = !info.hasVideo; + videoError = false; + + audioCondition.notify_all (); + videoCondition.notify_all (); + + } + + + void VideoDecoder::StartThreads () { + + quit = false; + + if (info.hasAudio) audioThread = std::thread (&VideoDecoder::AudioThread, this); + if (info.hasVideo) videoThread = std::thread (&VideoDecoder::VideoThread, this); + + } + + + void VideoDecoder::StopThreads () { + + { + std::lock_guard lock (mutex); + quit = true; + Flush (); + } + + audioCondition.notify_all (); + videoCondition.notify_all (); + + if (audioThread.joinable ()) audioThread.join (); + if (videoThread.joinable ()) videoThread.join (); + + } + + + void VideoDecoder::VideoThread () { + + while (true) { + + { + std::unique_lock lock (mutex); + videoCondition.wait (lock, [this] { return quit || (!seekPending && !videoEnded && frames.size () < MAX_QUEUED_FRAMES); }); + if (quit) break; + } + + std::lock_guard decodeLock (videoDecodeMutex); + + VideoPlanes planes; + double time = 0; + double duration = 0; + VideoDecodeResult result = backend->DecodeVideo (&planes, &time, &duration); + + if (result != VIDEO_DECODE_OK) { + + std::lock_guard lock (mutex); + videoEnded = true; + videoError = (result == VIDEO_DECODE_ERROR); + continue; + + } + + if (duration <= 0) duration = info.frameRate > 0 ? 1.0 / info.frameRate : 0; + + // Drop the frames that end before an accurate seek target + if (seekAccurate && time + duration <= seekTime + 0.0001) continue; + + int length = GetFrameLength (format, planes.width, planes.height); + if (length <= 0) continue; + + Frame* frame = 0; + + { + std::lock_guard lock (mutex); + + if (!freeFrames.empty ()) { + + frame = freeFrames.back (); + freeFrames.pop_back (); + + } + } + + if (!frame) frame = new Frame (); + + if ((int)frame->data.size () < length) frame->data.resize (length); + + frame->colorMatrix = planes.colorMatrix; + frame->duration = duration; + frame->fullRange = planes.fullRange; + frame->height = planes.height; + frame->length = WriteFrame (&planes, format, frame->data.data (), (int)frame->data.size ()); + frame->time = time; + frame->width = planes.width; + + std::lock_guard lock (mutex); + + if (frame->length > 0) { + + frames.push_back (frame); + + } else { + + freeFrames.push_back (frame); + + } + + } + + } + + + int VideoDecoder::WriteFrame (const VideoPlanes* planes, VideoFrameFormat format, unsigned char* data, int length) { + + int frameLength = GetFrameLength (format, planes->width, planes->height); + + if (frameLength <= 0 || !data) return VIDEO_READ_ERROR; + if (length < frameLength) return VIDEO_READ_BUFFER_TOO_SMALL; + + int width = planes->width; + int height = planes->height; + int chromaWidth = (width + 1) / 2; + int chromaHeight = (height + 1) / 2; + int pixelStride = planes->uvPixelStride; + + if (format == VIDEO_FRAME_FORMAT_NV12) { + + for (int row = 0; row < height; row++) { + + memcpy (data + row * width, planes->y + row * planes->yStride, width); + + } + + unsigned char* uv = data + width * height; + bool interleaved = (pixelStride == 2 && planes->v == planes->u + 1); + + for (int row = 0; row < chromaHeight; row++) { + + unsigned char* out = uv + row * chromaWidth * 2; + const unsigned char* u = planes->u + row * planes->uvStride; + + if (interleaved) { + + memcpy (out, u, chromaWidth * 2); + + } else { + + const unsigned char* v = planes->v + row * planes->uvStride; + + for (int x = 0; x < chromaWidth; x++) { + + out[x * 2] = u[x * pixelStride]; + out[x * 2 + 1] = v[x * pixelStride]; + + } + + } + + } + + return frameLength; + + } + + // Kr and Kb from ITU-R BT.601, BT.709 and BT.2020 + + double kr, kb; + + switch (planes->colorMatrix) { + + case VIDEO_COLOR_MATRIX_BT601: kr = 0.299; kb = 0.114; break; + case VIDEO_COLOR_MATRIX_BT2020: kr = 0.2627; kb = 0.0593; break; + default: kr = 0.2126; kb = 0.0722; break; + + } + + double kg = 1.0 - kr - kb; + double yScale = planes->fullRange ? 1.0 : 255.0 / 219.0; + double cScale = planes->fullRange ? 1.0 : 255.0 / 224.0; + int yOffset = planes->fullRange ? 0 : 16; + + int yFactor = (int)(yScale * 65536.0 + 0.5); + int rv = (int)(2.0 * (1.0 - kr) * cScale * 65536.0 + 0.5); + int gu = (int)(2.0 * kb * (1.0 - kb) / kg * cScale * 65536.0 + 0.5); + int gv = (int)(2.0 * kr * (1.0 - kr) / kg * cScale * 65536.0 + 0.5); + int bu = (int)(2.0 * (1.0 - kb) * cScale * 65536.0 + 0.5); + + for (int row = 0; row < height; row++) { + + const unsigned char* y = planes->y + row * planes->yStride; + const unsigned char* u = planes->u + (row / 2) * planes->uvStride; + const unsigned char* v = planes->v + (row / 2) * planes->uvStride; + unsigned char* out = data + row * width * 4; + + for (int x = 0; x < width; x++) { + + int cu = u[(x / 2) * pixelStride] - 128; + int cv = v[(x / 2) * pixelStride] - 128; + int luma = (y[x] - yOffset) * yFactor + 32768; + + out[0] = ClampByte ((luma + rv * cv) >> 16); + out[1] = ClampByte ((luma - gu * cu - gv * cv) >> 16); + out[2] = ClampByte ((luma + bu * cu) >> 16); + out[3] = 255; + out += 4; + + } + + } + + return frameLength; + + } + + +} diff --git a/project/src/media/video/VideoDecoderBindings.cpp b/project/src/media/video/VideoDecoderBindings.cpp new file mode 100644 index 0000000000..52339b5cee --- /dev/null +++ b/project/src/media/video/VideoDecoderBindings.cpp @@ -0,0 +1,364 @@ +#include +#include +#include +#include +#include +#include + + +namespace lime { + + + static int id_audioChannels; + static int id_audioSampleRate; + static int id_colorMatrix; + static int id_duration; + static int id_frameRate; + static int id_fullRange; + static int id_hasAudio; + static int id_hasVideo; + static int id_height; + static int id_length; + static int id_time; + static int id_width; + static bool init = false; + static bool hl_init = false; + + + inline void _initializeVideo () { + + if (!init) { + + id_audioChannels = val_id ("audioChannels"); + id_audioSampleRate = val_id ("audioSampleRate"); + id_colorMatrix = val_id ("colorMatrix"); + id_duration = val_id ("duration"); + id_frameRate = val_id ("frameRate"); + id_fullRange = val_id ("fullRange"); + id_hasAudio = val_id ("hasAudio"); + id_hasVideo = val_id ("hasVideo"); + id_height = val_id ("height"); + id_length = val_id ("length"); + id_time = val_id ("time"); + id_width = val_id ("width"); + init = true; + + } + + } + + + inline void _hl_initializeVideo () { + + if (!hl_init) { + + id_audioChannels = hl_hash_utf8 ("audioChannels"); + id_audioSampleRate = hl_hash_utf8 ("audioSampleRate"); + id_colorMatrix = hl_hash_utf8 ("colorMatrix"); + id_duration = hl_hash_utf8 ("duration"); + id_frameRate = hl_hash_utf8 ("frameRate"); + id_fullRange = hl_hash_utf8 ("fullRange"); + id_hasAudio = hl_hash_utf8 ("hasAudio"); + id_hasVideo = hl_hash_utf8 ("hasVideo"); + id_height = hl_hash_utf8 ("height"); + id_length = hl_hash_utf8 ("length"); + id_time = hl_hash_utf8 ("time"); + id_width = hl_hash_utf8 ("width"); + hl_init = true; + + } + + } + + + void gc_video_decoder (value handle) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + delete decoder; + + } + + + void hl_gc_video_decoder (HL_CFFIPointer* handle) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + delete decoder; + + } + + + void lime_video_decoder_close (value handle) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + + System::GCEnterBlocking (); + decoder->Close (); + System::GCExitBlocking (); + + } + + + HL_PRIM void HL_NAME(hl_video_decoder_close) (HL_CFFIPointer* handle) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + + hl_blocking (true); + decoder->Close (); + hl_blocking (false); + + } + + + value lime_video_decoder_create () { + + VideoBackend* backend = VideoBackend::Create (); + if (!backend) return alloc_null (); + + VideoDecoder* decoder = new VideoDecoder (backend); + return CFFIPointer (decoder, gc_video_decoder); + + } + + + HL_PRIM HL_CFFIPointer* HL_NAME(hl_video_decoder_create) () { + + VideoBackend* backend = VideoBackend::Create (); + if (!backend) return NULL; + + VideoDecoder* decoder = new VideoDecoder (backend); + return HLCFFIPointer (decoder, (hl_finalizer)hl_gc_video_decoder); + + } + + + double lime_video_decoder_get_audio_time (value handle) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + return decoder->audioTime; + + } + + + HL_PRIM double HL_NAME(hl_video_decoder_get_audio_time) (HL_CFFIPointer* handle) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + return decoder->audioTime; + + } + + + value lime_video_decoder_get_frame_info (value handle) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + + _initializeVideo (); + + value info = alloc_empty_object (); + alloc_field (info, id_colorMatrix, alloc_int (decoder->frameColorMatrix)); + alloc_field (info, id_duration, alloc_float (decoder->frameDuration)); + alloc_field (info, id_fullRange, alloc_bool (decoder->frameFullRange)); + alloc_field (info, id_height, alloc_int (decoder->frameHeight)); + alloc_field (info, id_length, alloc_int (decoder->frameLength)); + alloc_field (info, id_time, alloc_float (decoder->frameTime)); + alloc_field (info, id_width, alloc_int (decoder->frameWidth)); + return info; + + } + + + HL_PRIM vdynamic* HL_NAME(hl_video_decoder_get_frame_info) (HL_CFFIPointer* handle) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + + _hl_initializeVideo (); + + vdynamic* info = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_seti (info, id_colorMatrix, &hlt_i32, decoder->frameColorMatrix); + hl_dyn_setd (info, id_duration, decoder->frameDuration); + hl_dyn_seti (info, id_fullRange, &hlt_bool, decoder->frameFullRange); + hl_dyn_seti (info, id_height, &hlt_i32, decoder->frameHeight); + hl_dyn_seti (info, id_length, &hlt_i32, decoder->frameLength); + hl_dyn_setd (info, id_time, decoder->frameTime); + hl_dyn_seti (info, id_width, &hlt_i32, decoder->frameWidth); + return info; + + } + + + bool lime_video_decoder_is_supported () { + + return VideoBackend::IsSupported (); + + } + + + HL_PRIM bool HL_NAME(hl_video_decoder_is_supported) () { + + return VideoBackend::IsSupported (); + + } + + + value lime_video_decoder_open (value handle, HxString path, bool hardwareDecoding, int format) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + std::string source = path.c_str () ? path.c_str () : ""; + + System::GCEnterBlocking (); + bool success = decoder->Open (source.c_str (), hardwareDecoding, (VideoFrameFormat)format); + System::GCExitBlocking (); + + if (!success) return alloc_null (); + + _initializeVideo (); + + value info = alloc_empty_object (); + alloc_field (info, id_audioChannels, alloc_int (decoder->info.audioChannels)); + alloc_field (info, id_audioSampleRate, alloc_int (decoder->info.audioSampleRate)); + alloc_field (info, id_duration, alloc_float (decoder->info.duration)); + alloc_field (info, id_frameRate, alloc_float (decoder->info.frameRate)); + alloc_field (info, id_hasAudio, alloc_bool (decoder->info.hasAudio)); + alloc_field (info, id_hasVideo, alloc_bool (decoder->info.hasVideo)); + alloc_field (info, id_height, alloc_int (decoder->info.height)); + alloc_field (info, id_width, alloc_int (decoder->info.width)); + return info; + + } + + + HL_PRIM vdynamic* HL_NAME(hl_video_decoder_open) (HL_CFFIPointer* handle, hl_vstring* path, bool hardwareDecoding, int format) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + std::string source = path ? hl_to_utf8 (path->bytes) : ""; + + hl_blocking (true); + bool success = decoder->Open (source.c_str (), hardwareDecoding, (VideoFrameFormat)format); + hl_blocking (false); + + if (!success) return NULL; + + _hl_initializeVideo (); + + vdynamic* info = (vdynamic*)hl_alloc_dynobj (); + hl_dyn_seti (info, id_audioChannels, &hlt_i32, decoder->info.audioChannels); + hl_dyn_seti (info, id_audioSampleRate, &hlt_i32, decoder->info.audioSampleRate); + hl_dyn_setd (info, id_duration, decoder->info.duration); + hl_dyn_setd (info, id_frameRate, decoder->info.frameRate); + hl_dyn_seti (info, id_hasAudio, &hlt_bool, decoder->info.hasAudio); + hl_dyn_seti (info, id_hasVideo, &hlt_bool, decoder->info.hasVideo); + hl_dyn_seti (info, id_height, &hlt_i32, decoder->info.height); + hl_dyn_seti (info, id_width, &hlt_i32, decoder->info.width); + return info; + + } + + + int lime_video_decoder_read_audio (value handle, value buffer, int position, int length) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + Bytes bytes (buffer); + + if (!bytes.b || position < 0 || length < 0 || position + length > bytes.length) return VIDEO_READ_ERROR; + + return decoder->ReadAudio (bytes.b + position, length); + + } + + + HL_PRIM int HL_NAME(hl_video_decoder_read_audio) (HL_CFFIPointer* handle, Bytes* buffer, int position, int length) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + + if (!buffer || !buffer->b || position < 0 || length < 0 || position + length > buffer->length) return VIDEO_READ_ERROR; + + return decoder->ReadAudio (buffer->b + position, length); + + } + + + int lime_video_decoder_read_frame (value handle, value buffer, int position, int length, double time) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + Bytes bytes (buffer); + + if (!bytes.b || position < 0 || length < 0 || position + length > bytes.length) { + + return decoder->ReadFrame (NULL, 0, time); + + } + + return decoder->ReadFrame (bytes.b + position, length, time); + + } + + + HL_PRIM int HL_NAME(hl_video_decoder_read_frame) (HL_CFFIPointer* handle, Bytes* buffer, int position, int length, double time) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + + if (!buffer || !buffer->b || position < 0 || length < 0 || position + length > buffer->length) { + + return decoder->ReadFrame (NULL, 0, time); + + } + + return decoder->ReadFrame (buffer->b + position, length, time); + + } + + + void lime_video_decoder_seek (value handle, double time, bool accurate) { + + VideoDecoder* decoder = (VideoDecoder*)val_data (handle); + + System::GCEnterBlocking (); + decoder->Seek (time, accurate); + System::GCExitBlocking (); + + } + + + HL_PRIM void HL_NAME(hl_video_decoder_seek) (HL_CFFIPointer* handle, double time, bool accurate) { + + VideoDecoder* decoder = (VideoDecoder*)handle->ptr; + + hl_blocking (true); + decoder->Seek (time, accurate); + hl_blocking (false); + + } + + + DEFINE_PRIME1v (lime_video_decoder_close); + DEFINE_PRIME0 (lime_video_decoder_create); + DEFINE_PRIME1 (lime_video_decoder_get_audio_time); + DEFINE_PRIME1 (lime_video_decoder_get_frame_info); + DEFINE_PRIME0 (lime_video_decoder_is_supported); + DEFINE_PRIME4 (lime_video_decoder_open); + DEFINE_PRIME4 (lime_video_decoder_read_audio); + DEFINE_PRIME5 (lime_video_decoder_read_frame); + DEFINE_PRIME3v (lime_video_decoder_seek); + + + #define _TBYTES _OBJ (_I32 _BYTES) + #define _TCFFIPOINTER _DYN + + DEFINE_HL_PRIM (_VOID, hl_video_decoder_close, _TCFFIPOINTER); + DEFINE_HL_PRIM (_TCFFIPOINTER, hl_video_decoder_create, _NO_ARG); + DEFINE_HL_PRIM (_F64, hl_video_decoder_get_audio_time, _TCFFIPOINTER); + DEFINE_HL_PRIM (_DYN, hl_video_decoder_get_frame_info, _TCFFIPOINTER); + DEFINE_HL_PRIM (_BOOL, hl_video_decoder_is_supported, _NO_ARG); + DEFINE_HL_PRIM (_DYN, hl_video_decoder_open, _TCFFIPOINTER _STRING _BOOL _I32); + DEFINE_HL_PRIM (_I32, hl_video_decoder_read_audio, _TCFFIPOINTER _TBYTES _I32 _I32); + DEFINE_HL_PRIM (_I32, hl_video_decoder_read_frame, _TCFFIPOINTER _TBYTES _I32 _I32 _F64); + DEFINE_HL_PRIM (_VOID, hl_video_decoder_seek, _TCFFIPOINTER _F64 _BOOL); + + +} + + +extern "C" int lime_video_register_prims () { + + return 0; + +} diff --git a/src/lime/_internal/backend/native/NativeCFFI.hx b/src/lime/_internal/backend/native/NativeCFFI.hx index 3f2a89c06e..32aa030e18 100644 --- a/src/lime/_internal/backend/native/NativeCFFI.hx +++ b/src/lime/_internal/backend/native/NativeCFFI.hx @@ -352,6 +352,24 @@ class NativeCFFI @:cffi private static function lime_tray_icon_set_tooltip(handle:Dynamic, tooltip:String):Void; + @:cffi private static function lime_video_decoder_close(handle:Dynamic):Void; + + @:cffi private static function lime_video_decoder_create():Dynamic; + + @:cffi private static function lime_video_decoder_get_audio_time(handle:Dynamic):Float; + + @:cffi private static function lime_video_decoder_get_frame_info(handle:Dynamic):Dynamic; + + @:cffi private static function lime_video_decoder_is_supported():Bool; + + @:cffi private static function lime_video_decoder_open(handle:Dynamic, path:String, hardwareDecoding:Bool, format:Int):Dynamic; + + @:cffi private static function lime_video_decoder_read_audio(handle:Dynamic, buffer:Dynamic, position:Int, length:Int):Int; + + @:cffi private static function lime_video_decoder_read_frame(handle:Dynamic, buffer:Dynamic, position:Int, length:Int, time:Float):Int; + + @:cffi private static function lime_video_decoder_seek(handle:Dynamic, time:Float, accurate:Bool):Void; + @:cffi private static function lime_window_alert(handle:Dynamic, message:String, title:String):Void; @:cffi private static function lime_window_close(handle:Dynamic):Void; @@ -1004,6 +1022,22 @@ class NativeCFFI false)); private static var lime_tray_icon_set_tooltip = new cpp.CallableString->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_tray_icon_set_tooltip", "osv", false)); + private static var lime_video_decoder_close = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_video_decoder_close", "ov", false)); + private static var lime_video_decoder_create = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", "lime_video_decoder_create", "o", false)); + private static var lime_video_decoder_get_audio_time = new cpp.CallableFloat>(cpp.Prime._loadPrime("lime", + "lime_video_decoder_get_audio_time", "od", false)); + private static var lime_video_decoder_get_frame_info = new cpp.Callablecpp.Object>(cpp.Prime._loadPrime("lime", + "lime_video_decoder_get_frame_info", "oo", false)); + private static var lime_video_decoder_is_supported = new cpp.CallableBool>(cpp.Prime._loadPrime("lime", "lime_video_decoder_is_supported", "b", + false)); + private static var lime_video_decoder_open = new cpp.CallableString->Bool->Int->cpp.Object>(cpp.Prime._loadPrime("lime", + "lime_video_decoder_open", "osbio", false)); + private static var lime_video_decoder_read_audio = new cpp.Callablecpp.Object->Int->Int->Int>(cpp.Prime._loadPrime("lime", + "lime_video_decoder_read_audio", "ooiii", false)); + private static var lime_video_decoder_read_frame = new cpp.Callablecpp.Object->Int->Int->Float->Int>(cpp.Prime._loadPrime("lime", + "lime_video_decoder_read_frame", "ooiidi", false)); + private static var lime_video_decoder_seek = new cpp.CallableFloat->Bool->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_video_decoder_seek", + "odbv", false)); private static var lime_window_alert = new cpp.CallableString->String->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_alert", "ossv", false)); private static var lime_window_close = new cpp.Callablecpp.Void>(cpp.Prime._loadPrime("lime", "lime_window_close", "ov", false)); @@ -1451,6 +1485,15 @@ class NativeCFFI private static var lime_tray_icon_set_icon = CFFI.load("lime", "lime_tray_icon_set_icon", 2); private static var lime_tray_icon_set_menu = CFFI.load("lime", "lime_tray_icon_set_menu", 2); private static var lime_tray_icon_set_tooltip = CFFI.load("lime", "lime_tray_icon_set_tooltip", 2); + private static var lime_video_decoder_close = CFFI.load("lime", "lime_video_decoder_close", 1); + private static var lime_video_decoder_create = CFFI.load("lime", "lime_video_decoder_create", 0); + private static var lime_video_decoder_get_audio_time = CFFI.load("lime", "lime_video_decoder_get_audio_time", 1); + private static var lime_video_decoder_get_frame_info = CFFI.load("lime", "lime_video_decoder_get_frame_info", 1); + private static var lime_video_decoder_is_supported = CFFI.load("lime", "lime_video_decoder_is_supported", 0); + private static var lime_video_decoder_open = CFFI.load("lime", "lime_video_decoder_open", 4); + private static var lime_video_decoder_read_audio = CFFI.load("lime", "lime_video_decoder_read_audio", 4); + private static var lime_video_decoder_read_frame = CFFI.load("lime", "lime_video_decoder_read_frame", 5); + private static var lime_video_decoder_seek = CFFI.load("lime", "lime_video_decoder_seek", 3); private static var lime_window_alert = CFFI.load("lime", "lime_window_alert", 3); private static var lime_window_close = CFFI.load("lime", "lime_window_close", 1); private static var lime_window_context_flip = CFFI.load("lime", "lime_window_context_flip", 1); @@ -2218,6 +2261,48 @@ class NativeCFFI @:hlNative("lime", "hl_tray_icon_set_tooltip") private static function lime_tray_icon_set_tooltip(handle:CFFIPointer, tooltip:String):Void {} + @:hlNative("lime", "hl_video_decoder_close") private static function lime_video_decoder_close(handle:CFFIPointer):Void {} + + @:hlNative("lime", "hl_video_decoder_create") private static function lime_video_decoder_create():CFFIPointer + { + return null; + } + + @:hlNative("lime", "hl_video_decoder_get_audio_time") private static function lime_video_decoder_get_audio_time(handle:CFFIPointer):Float + { + return 0; + } + + @:hlNative("lime", "hl_video_decoder_get_frame_info") private static function lime_video_decoder_get_frame_info(handle:CFFIPointer):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_video_decoder_is_supported") private static function lime_video_decoder_is_supported():Bool + { + return false; + } + + @:hlNative("lime", "hl_video_decoder_open") private static function lime_video_decoder_open(handle:CFFIPointer, path:String, hardwareDecoding:Bool, + format:Int):Dynamic + { + return null; + } + + @:hlNative("lime", "hl_video_decoder_read_audio") private static function lime_video_decoder_read_audio(handle:CFFIPointer, buffer:Bytes, position:Int, + length:Int):Int + { + return 0; + } + + @:hlNative("lime", "hl_video_decoder_read_frame") private static function lime_video_decoder_read_frame(handle:CFFIPointer, buffer:Bytes, position:Int, + length:Int, time:Float):Int + { + return 0; + } + + @:hlNative("lime", "hl_video_decoder_seek") private static function lime_video_decoder_seek(handle:CFFIPointer, time:Float, accurate:Bool):Void {} + @:hlNative("lime", "hl_window_alert") private static function lime_window_alert(handle:CFFIPointer, message:String, title:String):Void {} @:hlNative("lime", "hl_window_close") private static function lime_window_close(handle:CFFIPointer):Void {} diff --git a/src/lime/media/VideoColorMatrix.hx b/src/lime/media/VideoColorMatrix.hx new file mode 100644 index 0000000000..dd75ff1309 --- /dev/null +++ b/src/lime/media/VideoColorMatrix.hx @@ -0,0 +1,25 @@ +package lime.media; + +/** + The matrix that converts a video's YCbCr samples to RGB. + + Streams without color information use `BT601` for standard definition and + `BT709` for high definition. +**/ +#if (haxe_ver >= 4.0) enum #else @:enum #end abstract VideoColorMatrix(Int) from Int to Int +{ + /** + ITU-R BT.601, used by standard definition video. + **/ + var BT601 = 0; + + /** + ITU-R BT.709, used by high definition video. + **/ + var BT709 = 1; + + /** + ITU-R BT.2020, used by ultra high definition and HDR video. + **/ + var BT2020 = 2; +} diff --git a/src/lime/media/VideoDecoder.hx b/src/lime/media/VideoDecoder.hx new file mode 100644 index 0000000000..63c7fd5794 --- /dev/null +++ b/src/lime/media/VideoDecoder.hx @@ -0,0 +1,391 @@ +package lime.media; + +import haxe.io.Bytes; +import lime._internal.backend.native.NativeCFFI; +import lime.utils.Assets; +import lime.utils.UInt8Array; +#if sys +import haxe.io.Path; +import lime.system.System; +import sys.FileSystem; +#end + +#if !lime_debug +@:fileXml('tags="haxe,release"') +@:noDebug +#end + +/** + Decodes the pictures and sound of a video file. + + Decoding runs on two background threads, one for each stream, which keep a + few frames and a fraction of a second of audio ready ahead of the reader. + `readFrame` and `readAudio` never wait for the decoder, so they can be + called every frame from the main thread. Audio can also be read from another + thread. + + `VideoSource` plays a video with this class, handling the audio output and + the timing of frames. Use `VideoDecoder` directly to process the frames or + audio yourself. + + Example usage: + ```haxe + var decoder = VideoDecoder.fromFile("assets/intro.mp4"); + var frame = new VideoFrame(); + + // in the render loop, with time in seconds + if (decoder.readFrame(frame, time)) + { + // upload frame.data + } + ``` + + Availability: native targets, using Media Foundation on Windows, + AVFoundation on macOS and iOS, MediaCodec on Android and GStreamer on Linux. + Which formats can be decoded depends on the codecs the platform provides, + but H.264 video with AAC audio in an MP4 file works everywhere. +**/ +@:access(lime._internal.backend.native.NativeCFFI) +class VideoDecoder +{ + @:noCompletion private static inline var READ_END:Int = -1; + @:noCompletion private static inline var READ_ERROR:Int = -2; + @:noCompletion private static inline var READ_BUFFER_TOO_SMALL:Int = -3; + + /** + Whether this platform can decode video. + **/ + public static var isSupported(get, never):Bool; + + /** + The number of audio channels, 1 or 2. Sources with more channels are + mixed down to stereo. + **/ + public var audioChannels(default, null):Int = 0; + + /** + Whether all of the audio has been read, or the audio could not be + decoded. Seeking resets it. + **/ + public var audioComplete(default, null):Bool = true; + + /** + The audio sample rate in Hz. + **/ + public var audioSampleRate(default, null):Int = 0; + + /** + The time of the next sample `readAudio` returns, in seconds. + **/ + public var audioTime(get, never):Float; + + /** + The length of the video in seconds, or 0 when it is unknown, such as for + a live stream. + **/ + public var duration(default, null):Float = 0; + + /** + The layout of the frames this decoder returns, chosen when it is opened. + **/ + public var format(default, null):VideoFrameFormat = NV12; + + /** + The nominal frame rate in frames per second, or 0 when it is unknown. + **/ + public var frameRate(default, null):Float = 0; + + /** + Whether to decode on the GPU when the platform supports it, which + greatly reduces CPU use. Set it before calling `open`. Decoding falls + back to the CPU when the GPU cannot decode the video. + **/ + public var hardwareDecoding:Bool = true; + + /** + Whether the video has an audio stream. + **/ + public var hasAudio(default, null):Bool = false; + + /** + Whether the video has a picture stream. + **/ + public var hasVideo(default, null):Bool = false; + + /** + The height of the frames in pixels. + **/ + public var height(default, null):Int = 0; + + /** + The path or URL that was opened. + **/ + public var source(default, null):String; + + /** + Whether all of the frames have been read, or the video could not be + decoded. Seeking resets it. + **/ + public var videoComplete(default, null):Bool = true; + + /** + The width of the frames in pixels. + **/ + public var width(default, null):Int = 0; + + @:noCompletion private var __handle:Dynamic; + + /** + Creates a decoder. Call `open` to start decoding a video. + **/ + public function new() {} + + /** + Stops decoding and releases the video. The decoder can be opened again. + **/ + public function close():Void + { + #if (lime_cffi && !macro) + if (__handle != null) + { + NativeCFFI.lime_video_decoder_close(__handle); + } + #end + + audioChannels = 0; + audioComplete = true; + audioSampleRate = 0; + duration = 0; + frameRate = 0; + hasAudio = false; + hasVideo = false; + height = 0; + source = null; + videoComplete = true; + width = 0; + } + + /** + Opens a video file, returning `null` when it cannot be decoded. + + @param path A file path, asset ID or URL + @param format The layout of the frames to return + **/ + public static function fromFile(path:String, format:VideoFrameFormat = NV12):VideoDecoder + { + var decoder = new VideoDecoder(); + return decoder.open(path, format) ? decoder : null; + } + + /** + Opens a video and starts decoding it, closing any video already open. + + Opening reads the start of the file, and for a URL waits for the server, + so it may take a moment. + + @param path A file path, asset ID or URL + @param format The layout of the frames to return + @return Whether the video can be decoded + **/ + public function open(path:String, format:VideoFrameFormat = NV12):Bool + { + close(); + + if (path == null || path == "") return false; + + #if (lime_cffi && !macro) + if (__handle == null) + { + __handle = NativeCFFI.lime_video_decoder_create(); + if (__handle == null) return false; + } + + var info:Dynamic = NativeCFFI.lime_video_decoder_open(__handle, __resolvePath(path), hardwareDecoding, format); + if (info == null) return false; + + audioChannels = info.audioChannels; + audioSampleRate = info.audioSampleRate; + duration = info.duration; + frameRate = info.frameRate; + hasAudio = info.hasAudio; + hasVideo = info.hasVideo; + height = info.height; + width = info.width; + + audioComplete = !hasAudio; + videoComplete = !hasVideo; + source = path; + this.format = format; + return true; + #else + return false; + #end + } + + /** + Copies decoded audio as interleaved signed 16-bit little-endian PCM, + `audioChannels * 2` bytes per sample frame. + + @param buffer The bytes to write to + @param position The offset in `buffer` to start writing at + @param length The most bytes to write + @return The number of bytes written, which is 0 when no audio is ready + yet or when `audioComplete` is `true` + **/ + public function readAudio(buffer:Bytes, position:Int, length:Int):Int + { + #if (lime_cffi && !macro) + if (__handle == null || audioComplete || buffer == null) return 0; + + var result:Int = NativeCFFI.lime_video_decoder_read_audio(__handle, buffer, position, length); + + if (result < 0) + { + audioComplete = true; + return 0; + } + + return result; + #else + return 0; + #end + } + + /** + Reads the next decoded frame into `frame`. + + With a `time`, frames that a later frame replaces by then are skipped + without being copied, and a frame is only returned once its time has + come. This keeps the picture in step with a clock even when rendering + falls behind. + + @param frame The frame to fill + @param time The current time on the video's timeline in seconds, or + a negative value to read every frame in order + @return Whether `frame` holds a new frame. It is `false` while no frame + is due or ready yet, and once `videoComplete` is `true`. + **/ + public function readFrame(frame:VideoFrame, time:Float = -1):Bool + { + #if (lime_cffi && !macro) + if (__handle == null || videoComplete || frame == null) return false; + + var result:Int = __readFrame(frame.data, time); + + if (result == READ_BUFFER_TOO_SMALL) + { + var info:Dynamic = NativeCFFI.lime_video_decoder_get_frame_info(__handle); + frame.data = new UInt8Array(info.length); + result = __readFrame(frame.data, time); + } + + if (result > 0) + { + var info:Dynamic = NativeCFFI.lime_video_decoder_get_frame_info(__handle); + frame.colorMatrix = info.colorMatrix; + frame.duration = info.duration; + frame.format = format; + frame.fullRange = info.fullRange; + frame.height = info.height; + frame.length = result; + frame.time = info.time; + frame.width = info.width; + return true; + } + + if (result == READ_END || result == READ_ERROR) + { + videoComplete = true; + } + + return false; + #else + return false; + #end + } + + /** + Moves both streams to a new time. + + @param time The time in seconds + @param accurate Whether to start exactly at `time`, decoding from the + keyframe before it. Otherwise reading starts from that keyframe, which is + faster. + **/ + public function seek(time:Float, accurate:Bool = true):Void + { + #if (lime_cffi && !macro) + if (__handle == null || source == null) return; + + NativeCFFI.lime_video_decoder_seek(__handle, time, accurate); + audioComplete = !hasAudio; + videoComplete = !hasVideo; + #end + } + + @:noCompletion private function __readFrame(data:UInt8Array, time:Float):Int + { + #if (lime_cffi && !macro) + if (data == null) + { + return NativeCFFI.lime_video_decoder_read_frame(__handle, null, 0, 0, time); + } + + return NativeCFFI.lime_video_decoder_read_frame(__handle, data.buffer, data.byteOffset, data.byteLength, time); + #else + return READ_ERROR; + #end + } + + @:noCompletion private static function __resolvePath(path:String):String + { + if (path.indexOf("://") > -1) return path; + + var resolved = path; + + if (Assets.exists(path)) + { + var assetPath = Assets.getPath(path); + if (assetPath != null) resolved = assetPath; + } + + #if sys + // Asset paths are relative to the application, which may not be the + // working directory + if (!Path.isAbsolute(resolved) && !FileSystem.exists(resolved)) + { + var directory = System.applicationDirectory; + + if (directory != null && directory != "") + { + var applicationPath = Path.join([directory, resolved]); + if (FileSystem.exists(applicationPath)) resolved = applicationPath; + } + } + #end + + return resolved; + } + + // Get & Set Methods + @:noCompletion private function get_audioTime():Float + { + #if (lime_cffi && !macro) + if (__handle != null && source != null) + { + return NativeCFFI.lime_video_decoder_get_audio_time(__handle); + } + #end + + return 0; + } + + @:noCompletion private static function get_isSupported():Bool + { + #if (lime_cffi && !macro) + return NativeCFFI.lime_video_decoder_is_supported(); + #else + return false; + #end + } +} diff --git a/src/lime/media/VideoFrame.hx b/src/lime/media/VideoFrame.hx new file mode 100644 index 0000000000..6ff259c9d9 --- /dev/null +++ b/src/lime/media/VideoFrame.hx @@ -0,0 +1,111 @@ +package lime.media; + +import lime.utils.UInt8Array; + +/** + A decoded video frame, filled by `VideoDecoder.readFrame` or + `VideoSource.readFrame`. + + A frame can be read into again and again. Its `data` is only reallocated + when a larger frame arrives. + + @see lime.media.VideoFrameFormat +**/ +class VideoFrame +{ + /** + The height of the chroma plane of an `NV12` frame, in rows. + **/ + public var chromaHeight(get, never):Int; + + /** + The byte offset of the chroma plane in `data` for an `NV12` frame. + **/ + public var chromaOffset(get, never):Int; + + /** + The width of the chroma plane of an `NV12` frame, in Cb/Cr pairs. + **/ + public var chromaWidth(get, never):Int; + + /** + The matrix that converts this frame's YCbCr samples to RGB. + **/ + public var colorMatrix:VideoColorMatrix; + + /** + The frame's pixels in `format`. Only the first `length` bytes belong to + this frame. + **/ + public var data:UInt8Array; + + /** + How long the frame is displayed, in seconds. + **/ + public var duration:Float; + + /** + The layout of `data`. + **/ + public var format:VideoFrameFormat; + + /** + Whether the YCbCr samples use the full 0-255 range rather than the + 16-235 (luma) and 16-240 (chroma) video range. + **/ + public var fullRange:Bool; + + /** + The height of the frame in pixels. + **/ + public var height:Int; + + /** + The number of bytes of `data` used by the frame. + **/ + public var length:Int; + + /** + On HTML5, the `