mirror of
https://github.com/4jcraft/4jcraft.git
synced 2026-05-13 13:27:13 +00:00
refactor: clean up Linux_Minecraft and rewrite wstring -> utf8string conversion with simdutf
This commit is contained in:
parent
658d72a89e
commit
d2d5cd6536
|
|
@ -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<uint8_t*> 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<uint32_t>(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<char>(cp);
|
||||
// extract multibyte unicode into multiple bytes of UTF-8
|
||||
} else if (cp < 0x800) {
|
||||
result += static_cast<char>(0xC0 | (cp >> 6));
|
||||
result += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else if (cp < 0x10000) {
|
||||
result += static_cast<char>(0xE0 | (cp >> 12));
|
||||
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
result += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else {
|
||||
result += static_cast<char>(0xF0 | (cp >> 18));
|
||||
result += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
|
||||
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
result += static_cast<char>(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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<const char32_t*>(converting.data());
|
||||
const std::size_t len32 = converting.size();
|
||||
auto data32 = reinterpret_cast<const char32_t*>(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<const char16_t*>(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<char*>(result.data()));
|
||||
result.resize(len);
|
||||
|
||||
return result;
|
||||
} else if constexpr (sizeof(wchar_t) == 4) {
|
||||
auto data32 = reinterpret_cast<const char32_t*>(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<char*>(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.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue