Qt (Black Mesa)
On August 1st,
Black Mesa introduced new UI in
Xengine (working on it started in early 2018), using Qt framework, known amoung the community as the New UI. The main goals with implementing it was:
- VGUI does not work with controllers, and due to its inherent design there's no way to make it work.
- VGUI has deprecated design.
- VGUI is hard to code and work with.
- Limited VGUI modding tools without the engine, game UI, and client binary code changes.
- Optimization.
The legacy VGUI is still in the game and can be enabled via -oldgameui launch option, but it is not supported by Crowbar Collective, meaning bugs and issues won't get fixes or improvements. The new UI doesn't replace the all existing VGUI elements (e.g. spectator menu), instead, it runs on to of the game, and if runs, the game disables all game menu elements for VGUI.
Implementation
The UI itself is a separate application (subsystem), binary file BlackMesaUI, it runs on top of the game itself and receives signals from there, it knows practically nothing about the engine, the engine practically non-existent for it, only the interfaces are awake and that's all. The interfaces themselves do not hint at the existence of types from the engine in the UI and the same is true for the engine - it also does not suspect the existence of Qt. When UI is active, console command gamemenucommand doesn't exists, the GameMenu button assigned commands are disabled, as well as every dialog that uses a promptable command to be open, so this part of VGUI never can run, while the rest can (e.g. team select menu). If a syntax error appear in the QML code, the UI won't be displayed.
Qt Version
The UI is made in Qt 5.9.8 and Qt Quick Application. This makes the UI totally moddable, all the logic and visuals are written in QML, the code is placed in ui folder. The main limitation is what the API provides from the BlackMesaUI binary and Qt from Black Mesa\bin\thirdparty\qt-5.9.x-windows-x86-msvc2013-angle folder. The reason behind 5.9 is because it's the last version fully compitable with Visual Studio 2013, that is used to compile the game for
Windows. Total conversions can't add custom Qt plugins, because they are outside of folder with gameinfo.txt.
Rendering
ANGLE
Because Black Mesa uses Qt 5.9 version, it doesn't use DirectX directly, instead, used ANGLE rendering layer. ANGLE (Almost Native Graphics Layer Engine) in Qt 5.9 is a layer that allows Qt to render its OpenGL ES UI via DirectX rather than the native Windows OpenGL driver. This is especially important for Qt 5 on Windows, as Qt Quick/QML in Qt 5 relied on OpenGL/OpenGL ES and OpenGL drivers on Windows have historically been less predictable than DirectX. For Qt, this looks like OpenGL ES 2.0, but ANGLE internally translates these calls to DirectX.
DirectX Versions
If the game doesn't use DirectX Vulkan via -disabledxvk launch option (the default launch option in Steam UI), the UI can use two versions of DirectX. By default, it's DirectX 11 (can be used via -forceuid3d11 launch option as well), but can also be used DirectX 9 (-forceuid3d9 launch option). Due to the no-mixed-API restriction, if the game runs in DirectX Vulkan (via -enabledxvk launch option or DXVK launch option in Steam UI), Qt UI is forced to run DirectX 9, so it can be displayed.
Files Structure
All files related to the UI (qmldir. and QML files) are stored ui folder. The original game version folder also contains subfolders:
- fonts - includes fonts used by the UI.
- campaign/images - includes PNG images for the campaign chapter images, they are screenshots from the game with changed color correction and disable lensflares, except Endgame chapter (20), which uses Crowbar Collective icon on a black background.
- images - includes icons and images used by the main part of the UI, for instant, nav-background.png used as the "orange stripe" under the main menu buttons.
- images/navigation - includes icons for navigation buttons, both keyboard and controller.
Outside of ui folder, the original game also uses:
- cfg - for the CFG files.
- materials - for some of the VTF files.
- campaigns - for JSON files with information for official and workshop campaigns.
The UI can access any game's folder.
For information about all the QML files and their code, see the subpages, this includes: core and misc files, button prefix files, component prefix files, routeview files.
Tips
Resources
For beginner friendly step by step information, use Qt tutorials on YouTube, for instant, Somco-Software tutorial video series.
For the full Qt 5.9 documentation, use Qt 5.9 framework documentation, it contains all the API and necessary information.
For the BlackMesaUI API, read the subpage that contains all the information about data object schemas, BlackMesaEngine singleton type, enumerations, campaigns system, VFS protocol, image provider.
To get answers to specific questions, use DeepWiki (Devin AI) in MyGamepedia/black-mesa-new-qt-qml-ui-analysis repository, it will analyze the UI QML code and take a while before respond. Always use Deep Research mode for exact answers.
Development
Can be used any text editor to edit the QML code, Qt Creator recommended for syntax errors highlights, just throw a file on the window. Due to luck of Black Mesa API placeholders, that could work in Qt Creator for the UI prototyping, there is no clear way to put the UI in the editor and see changes on fly in the editor, everything needs to be tested and checked in the game.
Base Changes For a Total Conversion
To change main color for the UI, go to theme.qml, find property highlight, change the HEX color to what feets mod them, using Google's color palette.
It's very likely the total conversion won't use UI sections for workshop (to avoid breaking stuff), achievements, translators, policy, and multiplayer features (unless custom multiplayer or
SourceCoop support planned). To remove:
- Go to component-header.qml.
- Find and remove (or comment out) following lines:
append({ label: labels.multiplayer, routeName: "multiplayer" });append({ label: labels.achievements, routeName: "achievements" });append({ label: labels.workshop, routeName: "steamworkshop" });append({ label: labels.policy, routeName: "policy", isEnabled: true });append({ label: labels.translators, routeName: "translators", isEnabled: true })
To remove multiplayer settings, go to routeview-game.qml, find append with game_announcer value for key, remove (or comment out), the same for appends mp_multiplayer_character_model and mp_multiplayer_character_skin. To remove multiplayer bindings, go to routeview-bindings.qml, find ListModel with id categoriesModel, in categories body, remove (or comment out) multiplayer part.
The total conversion may won't use certain weapons, so binds in the list for such weapons are useless, go to component-binding-weapons.qml, remove (or comment out) lines where used unused weapon classname.
Images used by the UI also should be edited to math the new them.
Custom Signals Via Console Output
Without API modifications, it's not possible to add custom signals for the UI to call custom logic, it's even hard to do with engine plugins, because the BlackMesaUI reads index to define what signal it should call. However, if something can print to the console, it can be used to read message entry and compare by string. To implement such workaround, open component-devconsole.qml, find onGameConsoleMessagesReceived, add to the loop something like this after the after the line that assigns a value to messageEntry:
//mygamepedia: this is example, could be used as a hook for stuff you want by printing to the console, e.g. to open lights editor
if (messageEntry.text.indexOf("^@#!_lighteditor") !== -1) {
BlackMesaEngine.executeClientCommandUnrestricted("echo THIS IS A WIP FEATURE!!!");
}
This example will print THIS IS A WIP FEATURE!!! message to the console, once it receives ^@#!_lighteditor string. The only downside, it has a delay of 100 milliseconds, this means the trick is unsuitable for anything that needs to be frame-accurate or sub-100ms response.
Bugs
Black squares and checkboards during game level load
Seems to be UI glitch. Appears during any level load from background, this includes save load and background level load. The black void is actually what the game engine renders at the moment, normally the player supposed to see image applied on top of it.
Native Linux Version Rendering Issues
Some users have rendering issues of the UI on native
Linux game build. Based on the reports, different users face different problems, usually flickering. Use
Proton as a workaround.
Doesn't scale properly with Engine tools
The UI isn't connected to the window scale, so it covers the entire screen, instead of convering the game screen. This makes it uncomfortable to use the tools, as the UI covers a part of the VGUI. The only way to workaround it is using -oldgameui launch option to run the game with legacy VGUI.
See also
External links
- Official Qt 5.9 framework documentation
- Somco-Software tutorials
- MyGamepedia/black-mesa-new-qt-qml-ui-analysis repository on DeepWiki