diff --git a/targets/app/linux/Linux_Minecraft.cpp b/targets/app/linux/Linux_Minecraft.cpp index 909c47f16..199ba2592 100644 --- a/targets/app/linux/Linux_Minecraft.cpp +++ b/targets/app/linux/Linux_Minecraft.cpp @@ -61,6 +61,7 @@ static void sigsegv_handler(int sig) { #include "app/linux/Linux_App.h" #include "app/linux/Linux_UIController.h" #include "console_helpers/compression.h" +#include "console_helpers/StringHelpers.h" #include "minecraft/client/Minecraft.h" #include "minecraft/client/renderer/Tesselator.h" #include "minecraft/client/renderer/Textures.h" @@ -407,246 +408,6 @@ void DefineActions(void) { _360_JOY_BUTTON_DPAD_DOWN); } -#if !defined(__linux__) -HINSTANCE g_hInst = nullptr; -HWND g_hWnd = nullptr; -D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; -D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0; -ID3D11Device* g_pd3dDevice = nullptr; -ID3D11DeviceContext* g_pImmediateContext = nullptr; -IDXGISwapChain* g_pSwapChain = nullptr; -ID3D11RenderTargetView* g_pRenderTargetView = nullptr; -ID3D11DepthStencilView* g_pDepthStencilView = nullptr; -ID3D11Texture2D* g_pDepthStencilBuffer = nullptr; - -// -// FUNCTION: WndProc(HWND, uint32_t, WPARAM, LPARAM) -// -// PURPOSE: Processes messages for the main window. -// -// WM_COMMAND - process the application menu -// WM_PAINT - Paint the main window -// WM_DESTROY - post a quit message and return -// -// -LRESULT CALLBACK WndProc(HWND hWnd, uint32_t message, WPARAM wParam, - LPARAM lParam) { - int wmId, wmEvent; - PAINTSTRUCT ps; - HDC hdc; - - switch (message) { - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - break; - case WM_PAINT: - hdc = BeginPaint(hWnd, &ps); - // TODO: Add any drawing code here... - EndPaint(hWnd, &ps); - break; - case WM_DESTROY: - PostQuitMessage(0); - break; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} - -// -// FUNCTION: MyRegisterClass() -// -// PURPOSE: Registers the window class. -// -ATOM MyRegisterClass(HINSTANCE hInstance) { - WNDCLASSEX wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, "Minecraft"); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = "Minecraft"; - wcex.lpszClassName = "MinecraftClass"; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassEx(&wcex); -} - -// -// FUNCTION: InitInstance(HINSTANCE, int) -// -// PURPOSE: Saves instance handle and creates main window -// -// COMMENTS: -// -// In this function, we save the instance handle in a global variable and -// create and display the main program window. -// -BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { - g_hInst = hInstance; // Store instance handle in our global variable - - g_hWnd = CreateWindow("MinecraftClass", "Minecraft", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, - hInstance, nullptr); - - if (!g_hWnd) { - return false; - } - - ShowWindow(g_hWnd, nCmdShow); - UpdateWindow(g_hWnd); - - return true; -} - -//-------------------------------------------------------------------------------------- -// Create Direct3D device and swap chain -//-------------------------------------------------------------------------------------- -int32_t InitDevice() { - int32_t hr = S_OK; - - RECT rc; - GetClientRect(g_hWnd, &rc); - uint32_t width = rc.right - rc.left; - uint32_t height = rc.bottom - rc.top; - - uint32_t createDeviceFlags = 0; -#if defined(_DEBUG) - createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - - D3D_DRIVER_TYPE driverTypes[] = { - D3D_DRIVER_TYPE_HARDWARE, - D3D_DRIVER_TYPE_WARP, - D3D_DRIVER_TYPE_REFERENCE, - }; - uint32_t numDriverTypes = ARRAYSIZE(driverTypes); - - D3D_FEATURE_LEVEL featureLevels[] = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - }; - uint32_t numFeatureLevels = ARRAYSIZE(featureLevels); - - DXGI_SWAP_CHAIN_DESC sd; - memset(&sd, 0, sizeof(sd)); - sd.BufferCount = 1; - sd.BufferDesc.Width = width; - sd.BufferDesc.Height = height; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 60; - sd.BufferDesc.RefreshRate.Denominator = 1; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = g_hWnd; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = true; - - for (uint32_t driverTypeIndex = 0; driverTypeIndex < numDriverTypes; - driverTypeIndex++) { - g_driverType = driverTypes[driverTypeIndex]; - hr = D3D11CreateDeviceAndSwapChain( - nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, - numFeatureLevels, D3D11_SDK_VERSION, &sd, &g_pSwapChain, - &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext); - if (HRESULT_SUCCEEDED(hr)) break; - } - if (FAILED(hr)) return hr; - - // Create a render target view - ID3D11Texture2D* pBackBuffer = nullptr; - hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), - (void**)&pBackBuffer); - if (FAILED(hr)) return hr; - - // Create a depth stencil buffer - D3D11_TEXTURE2D_DESC descDepth; - - descDepth.Width = width; - descDepth.Height = height; - descDepth.MipLevels = 1; - descDepth.ArraySize = 1; - descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - descDepth.SampleDesc.Count = 1; - descDepth.SampleDesc.Quality = 0; - descDepth.Usage = D3D11_USAGE_DEFAULT; - descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; - descDepth.CPUAccessFlags = 0; - descDepth.MiscFlags = 0; - hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, - &g_pDepthStencilBuffer); - - D3D11_DEPTH_STENCIL_VIEW_DESC descDSView; - descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - descDSView.Texture2D.MipSlice = 0; - - hr = g_pd3dDevice->CreateDepthStencilView( - g_pDepthStencilBuffer, &descDSView, &g_pDepthStencilView); - - hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, - &g_pRenderTargetView); - pBackBuffer->Release(); - if (FAILED(hr)) return hr; - - g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, - g_pDepthStencilView); - - // Setup the viewport - D3D11_VIEWPORT vp; - vp.Width = (float)width; - vp.Height = (float)height; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pImmediateContext->RSSetViewports(1, &vp); - - RenderManager.Initialise(g_pd3dDevice, g_pSwapChain); - - return 0; -} - -//-------------------------------------------------------------------------------------- -// Render the frame -//-------------------------------------------------------------------------------------- -void Render() { - // Just clear the backbuffer - float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // red,green,blue,alpha - - g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor); - g_pSwapChain->Present(0, 0); -} - -//-------------------------------------------------------------------------------------- -// Clean up the objects we've created -//-------------------------------------------------------------------------------------- -void CleanupDevice() { - if (g_pImmediateContext) g_pImmediateContext->ClearState(); - - if (g_pRenderTargetView) g_pRenderTargetView->Release(); - if (g_pSwapChain) g_pSwapChain->Release(); - if (g_pImmediateContext) g_pImmediateContext->Release(); - if (g_pd3dDevice) g_pd3dDevice->Release(); -} -#endif - int main(int argc, const char* argv[]) { #if defined(__linux__) && defined(__GLIBC__) struct sigaction sa; @@ -878,62 +639,11 @@ int main(int argc, const char* argv[]) { std::vector vRichPresenceStrings; -// convert std::wstring to UTF-8 string -// wchar_t is 32bit on all Linux systems, and interpreted as UTF-32 -// the code base stores all strings internally as UCS-2 (16bit, subset of -// UTF-16), which, scince it only stores BMP code points, is trivially -// convertable to UTF-32 as well as UTF-16. hence this parser simply parses -// UTF-32 - -// all implementations of libc (including glibc, musl, uClibc...) implement -// wchar_t as 4byte/32bit (scince around 1999), it would break the libc ABI, -// if this ever will get changed, hence this assert -static_assert(sizeof(wchar_t) == 4, "Linux with non 32bit wchar_t"); - -std::string wstring_to_utf8(const std::wstring& str) { - std::string result; - // preallocation, so it will never need to resize. - // same allocation size as for the 4byte wstring representation. - // it well get destructed instantly, in the function that it gets called - // from - result.reserve(str.size() * 4); - - for (size_t i = 0; i < str.size(); ++i) { - uint32_t cp = static_cast(str[i]); - - // outside of valid unicode range or preserved UTF-16 surrogate pairs - // (just in case) - if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) { - cp = 0xFFFD; // unicode replacement character - } - - if (cp < 0x80) { - // ASCII - result += static_cast(cp); - // extract multibyte unicode into multiple bytes of UTF-8 - } else if (cp < 0x800) { - result += static_cast(0xC0 | (cp >> 6)); - result += static_cast(0x80 | (cp & 0x3F)); - } else if (cp < 0x10000) { - result += static_cast(0xE0 | (cp >> 12)); - result += static_cast(0x80 | ((cp >> 6) & 0x3F)); - result += static_cast(0x80 | (cp & 0x3F)); - } else { - result += static_cast(0xF0 | (cp >> 18)); - result += static_cast(0x80 | ((cp >> 12) & 0x3F)); - result += static_cast(0x80 | ((cp >> 6) & 0x3F)); - result += static_cast(0x80 | (cp & 0x3F)); - } - } - - return result; -} - uint8_t* mallocAndCreateUTF8ArrayFromString(int iID) { const wchar_t* wchString = app.GetString(iID); std::wstring srcString = wchString; - std::string dstString = wstring_to_utf8(srcString); + std::u8string dstString = wstring_to_u8string(srcString); int dst_len = dstString.size() + 1; uint8_t* strUtf8 = (uint8_t*)malloc(dst_len); diff --git a/targets/console_helpers/include/console_helpers/StringHelpers.h b/targets/console_helpers/include/console_helpers/StringHelpers.h index 3dc558475..339daddf0 100644 --- a/targets/console_helpers/include/console_helpers/StringHelpers.h +++ b/targets/console_helpers/include/console_helpers/StringHelpers.h @@ -35,6 +35,7 @@ T _fromHEXString(const std::wstring& s) { std::wstring convStringToWstring(const std::string& converting); std::wstring u16string_to_wstring(const std::u16string& converting); std::u16string wstring_to_u16string(const std::wstring& converting); +std::u8string wstring_to_u8string(const std::wstring& converting); const char* wstringtofilename(const std::wstring& name); std::wstring filenametowstring(const char* name); diff --git a/targets/console_helpers/src/StringHelpers.cpp b/targets/console_helpers/src/StringHelpers.cpp index a00460d8d..7fac18871 100644 --- a/targets/console_helpers/src/StringHelpers.cpp +++ b/targets/console_helpers/src/StringHelpers.cpp @@ -70,7 +70,7 @@ std::wstring u16string_to_wstring(const std::u16string& converting) { return result; } else { - static_assert(sizeof(wchar_t) != 2 || sizeof(wchar_t) != 4, + static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "Here's a nickel, Kid. Go buy yourself a real computer."); } } @@ -85,19 +85,49 @@ std::u16string wstring_to_u16string(const std::wstring& converting) { // POSIX, UTF-32 if (converting.empty()) return {}; - const char32_t* data32 = - reinterpret_cast(converting.data()); - const std::size_t len32 = converting.size(); + auto data32 = reinterpret_cast(converting.data()); + auto len32 = converting.size(); std::u16string result(simdutf::utf16_length_from_utf32(data32, len32), u'\0'); - std::size_t convertedLength = + auto len = simdutf::convert_utf32_to_utf16(data32, len32, result.data()); - result.resize(convertedLength); + result.resize(len); return result; } else { - static_assert(sizeof(wchar_t) != 2 || sizeof(wchar_t) != 4, + static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, + "Here's a nickel, Kid. Go buy yourself a real computer."); + } +} + +std::u8string wstring_to_u8string(const std::wstring& converting) { + if (converting.empty()) return {}; + + if constexpr (sizeof(wchar_t) == 2) { + auto data16 = reinterpret_cast(converting.data()); + auto len16 = converting.size(); + + std::u8string result(simdutf::utf8_length_from_utf16le(data16, len16), + u'\0'); + auto len = + simdutf::convert_utf16_to_utf8(data16, len16, reinterpret_cast(result.data())); + result.resize(len); + + return result; + } else if constexpr (sizeof(wchar_t) == 4) { + auto data32 = reinterpret_cast(converting.data()); + auto len32 = converting.size(); + + std::u8string result(simdutf::utf8_length_from_utf32(data32, len32), + u'\0'); + auto len = + simdutf::convert_utf32_to_utf8(data32, len32, reinterpret_cast(result.data())); + result.resize(len); + + return result; + } else { + static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "Here's a nickel, Kid. Go buy yourself a real computer."); } }