前言
最近在研究GUI的各個方面,最后被導向了web render,真的是一言難盡。
這里就其中一個比較有意思的項目 RmlUi 淺試一下,沒想要還挺麻煩!這里留下note以供后人參考。
環境搭建
Windows + VS2022 + pre-binary library
需要指出的是 RmlUi官方的sample和demo很爛,對,可以說很爛!
因為按照他們的教程和示例,我玩了兩天也沒搞出來一個hello world!
也可能是我水平太菜了吧,但是我還是認為官方的資料是真的不行,只能提供思路的參考。
以當前最新版本v5.1為例,關鍵步驟如下:
- VS創建一個console C++項目,我們以x86為目標
- 將從
https://github.com/mikke89/RmlUi/releases
下載RmlUi-vs2017-win32.zip
. 解壓到指定目錄,將對應 include/lib/link 三件套手動配置到project中。添加 freetype.lib 的文件夾路徑到project, 添加 freetype.lib, RmlCore.lib依賴。 - 添加
Backends
文件夾到 include, 復制 freetype.dll, RmlCore.Dll到可執行文件夾。 - 修改 主 cpp文件。內容參考下面。
- 直接編譯,100% 各種error! 并且沒有教程可以參考!
到這里,你需要考慮一個問題:
你的GUI跑在什么后端上?
什么意思呢?
你的GUI渲染引擎是什么?OpenGL? Vulkan? SDL?
你的繪制引擎是什么?SDL? FLFW? SDL? X11? Win32?
如果回答不了,這里就無法進行下去了。
當然,有人說,我想要 GDI + Win32。我不想使用顯卡渲染!
對不起,不好意思,這個也不支持!!
RmlUi 實際上是一個更側重2D/3D渲染的引擎,對于UI渲染的目標就是 顯卡/SDL 渲染!
那么,我能選擇的是什么呢?
渲染引擎可選:GL2/GL3/SDL/VK
繪制引擎可選:SFML/SDL/WIn32/GLFW/X11
注意:以上兩種選擇,目前不支持自由組合!!
這里我選擇了windows上最容易準備的環境:SDL + SDL, 這個組合官方有現成的支持!
繼續配置:
- 將SDL和SDL_image的release包從GitHub下載下來,include/lib/link 三件套配置好
- 在VS project中將
RmlUi_Platform_SDL.h/.cpp
,RmlUi_Renderer_SDL.h/.cpp
,RmlUi_Backend_SDL_SDLrenderer.cpp
三套源文件加入。 - 準備 字體ttf 文件, 需要中文的,字體也要支持中文。
- 準備 rml 和 rcss 文件。
這里需要注意,rcss一定要通過 rml 中的 link 方式加載進去。 - 最后,debug 起來, 注意查看 VS 調試窗口的提示!
幾個常見問題:
1. Font load error。大概率是字體路徑或者權限問題,確保有讀寫權限。
2. No font face。font-family xxx ?rcss 文件可能沒加載,或者widget沒有設置 font-family.所有widget都需要設置,最好使用*篩選器設置全部的。還有一種可能:你沒有在rml中link 正確的rcss文件。一定要查看debug窗口里的提升輸出。
參考代碼
// rmldemo.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。
//#include <RmlUi/Core.h>
#include <RmlUi_Backend.h>struct ApplicationData {bool show_text = true;Rml::String animal = "dog";
} my_data;int main()
{int window_width = 1024;int window_height = 768;// Initializes the shell which provides common functionality used by the included samples.//if (!Shell::Initialize())// return -1;// // Constructs the system and render interfaces, creates a window, and attaches the renderer.if (!Backend::Initialize("Template Tutorial", window_width, window_height, true)){//Shell::Shutdown();return -1;}// Install the custom interfaces constructed by the backend before initializing RmlUi.Rml::SetSystemInterface(Backend::GetSystemInterface());Rml::SetRenderInterface(Backend::GetRenderInterface());// RmlUi initialisation.Rml::Initialise();// Create the main RmlUi context.Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));if (!context){Rml::Shutdown();Backend::Shutdown();//Shell::Shutdown();return -1;}//Rml::Debugger::Initialise(context);// Tell RmlUi to load the given fonts.Rml::LoadFontFace("C:\\myfont\\MappleMono\\MapleMono-NF-CN-Regular.ttf");// Fonts can be registered as fallback fonts, as in this case to display emojis.//Rml::LoadFontFace("C:\\Users\\andy\\Desktop\\myfont\\JetBrainsMono\\JetBrainsMono-Regular.ttf", true);// Set up data bindings to synchronize application data.if (Rml::DataModelConstructor constructor = context->CreateDataModel("animals")){constructor.Bind("show_text", &my_data.show_text);constructor.Bind("animal", &my_data.animal);}// Load and show the tutorial document.if (Rml::ElementDocument* document = context->LoadDocument("hello.rml"))document->Show();bool running = true;while (running){running = Backend::ProcessEvents(context, nullptr, true);context->Update();Backend::BeginFrame();context->Render();Backend::PresentFrame();}// Shutdown RmlUi.Rml::Shutdown();Backend::Shutdown();//Shell::Shutdown();return 0;
}
hello.rml
<rml>
<head><title>Hello world</title><link type="text/rcss" href="hello.rcss"/>
</head>
<body data-model="animals"><h1>RmlUi</h1><p>Hello <span id="world">world</span>!</p><p data-if="show_text">The quick brown fox jumps over the lazy {{animal}}.</p><input type="text" data-value="animal"/>
</body>
</rml>
hello.rcss
* {font-family: "Maple Mono NF CN";
}
body {font-size: 18px;color: #02475e;background: #fefecc;text-align: center;padding: 2em 1em;position: absolute;border: 2px #ccc;width: 500px;height: 200px;margin: auto;
}h1 {color: #f6470a;font-size: 1.5em;font-weight: bold;margin-bottom: 0.7em;
}p { margin: 0.7em 0;
}input.text {background-color: #fff;color: #555;border: 2px #999;padding: 5px;tab-index: auto;cursor: text;box-sizing: border-box;width: 200px;font-size: 0.9em;
}
后記
如果不想使用SDL,使用OpenGL怎么辦呢?
和一開始的問題一樣:你選擇什么組合?
我們以 GFLW + OpenGL2 為例:
- 需要準備 OpenGL2 開發SDK,將三件套添加到 project 中。
- 需要添加
RmlUi_Backend_GLFW_GL2.h/.cpp
,RmlUi_Platform_GLFW.h/.cpp
,RmlUi_Renderer_GL2.h/.cpp
添加到project中。 - 如果遇到 OpenGL2 依賴其他 image庫一類的,繼續下載對應 SDK 添加到 project中。
備注: RmlUi 對輸入法支持不行,目前作者還在開發中。
個人估計,IME 這塊開源項目想要自己實現,幾乎不可能!參考flutter,這么多年了,也沒修的很好。