1
More Forks / Re: OXCE Lua/Vulkan
« on: February 18, 2025, 01:37:38 pm »
Just a quick update. I've finally managed to get most of the Vulkan stuff to a place I like. There's still some things I want to improve there, but I've got to make progress on the Lua side as well, so starting today I'm shifting focus to getting the Mod.cpp cut up and exposed through Lua.
The way things used to work has drastically changed. Before, you used to be able to write directly to surfaces, either by blitting or drawing directly on them. With Vulkan, you don't have that ability anymore. Everything is handled through primitives. When you create a primitive, a device local(GPU only) buffer is created and updated. The hardest primitive to make, by far, was the TextPrimitive(although an argument could be made for the line primitive since I did spend a week trying to find out why it was missing a single pixel).
Text wrapping, alignment, and placement is... complicated. Because of various localization needs, I ended up just using an established library called HarfBuzz for the text shaping, and yet another library called libunibreak for the word wrapping. The two combined should allow for languages like Hebrew and Arabic if the needs ever arises. Kerning is now a feature, which allows two character to adjust their overlap if that's something that is ever needed. However, something bothered me about the existing text rendering. Turns out, by using a special marker, you can change the font mid text, and fonts have multiple images associated with them. This messes up the render state which needs to track these changes and update the resource bindings. This meant I needed to implement Text Sections. While I was doing so, I decided that, well, since I have to support text sections, might as well see what else I can change about the text. That's when I decided to implement ANSI escape codes.
So, ANSI escape codes are a pain. I know. It would be nice if someone would just implement a CSS style processor that keeps track of a stack of states. However, the one really nice thing about ANSI escape codes is that I don't have to do that. I don't have to track a stack of states and manage all the details with the state changes. Instead, I can cut up the text into sections based on the escape code. If someone wants to write a stack based state management for text, feel free to do so. I had to make some choices as to where I wanted to spend my time. So, the cool thing is, now we have in-line text colors and styles. In a single line, you can have up to 16 colors. You can even change the background if you'd like(which will come in handy when it comes to text input selection). Cool, eh?
Here's the unit test running RGB colors through a single line of text:

And the code:
https://github.com/ken-noland/OpenXcom/blob/bd779c0f38a2d2eae8e056119e998f669cfa5bc3/src/Tests/Engine/Graphics/Primitives/TestText.cpp#L475
So, next up is Mod.cpp. Sorry, but that file is WAY too large and needs to be cut down. I'll be doing that with the use of Factories. I'm probably not going to do the whole thing, but pick and choose some of the rules that would get me the biggest results. After Mod.cpp, then I've got the input system to handle. That one gets a little complicated since I do want to have both Android and Windows/Mac/Linux all go through the same input interface.
The way things used to work has drastically changed. Before, you used to be able to write directly to surfaces, either by blitting or drawing directly on them. With Vulkan, you don't have that ability anymore. Everything is handled through primitives. When you create a primitive, a device local(GPU only) buffer is created and updated. The hardest primitive to make, by far, was the TextPrimitive(although an argument could be made for the line primitive since I did spend a week trying to find out why it was missing a single pixel).
Text wrapping, alignment, and placement is... complicated. Because of various localization needs, I ended up just using an established library called HarfBuzz for the text shaping, and yet another library called libunibreak for the word wrapping. The two combined should allow for languages like Hebrew and Arabic if the needs ever arises. Kerning is now a feature, which allows two character to adjust their overlap if that's something that is ever needed. However, something bothered me about the existing text rendering. Turns out, by using a special marker, you can change the font mid text, and fonts have multiple images associated with them. This messes up the render state which needs to track these changes and update the resource bindings. This meant I needed to implement Text Sections. While I was doing so, I decided that, well, since I have to support text sections, might as well see what else I can change about the text. That's when I decided to implement ANSI escape codes.
So, ANSI escape codes are a pain. I know. It would be nice if someone would just implement a CSS style processor that keeps track of a stack of states. However, the one really nice thing about ANSI escape codes is that I don't have to do that. I don't have to track a stack of states and manage all the details with the state changes. Instead, I can cut up the text into sections based on the escape code. If someone wants to write a stack based state management for text, feel free to do so. I had to make some choices as to where I wanted to spend my time. So, the cool thing is, now we have in-line text colors and styles. In a single line, you can have up to 16 colors. You can even change the background if you'd like(which will come in handy when it comes to text input selection). Cool, eh?
Here's the unit test running RGB colors through a single line of text:

And the code:
https://github.com/ken-noland/OpenXcom/blob/bd779c0f38a2d2eae8e056119e998f669cfa5bc3/src/Tests/Engine/Graphics/Primitives/TestText.cpp#L475
So, next up is Mod.cpp. Sorry, but that file is WAY too large and needs to be cut down. I'll be doing that with the use of Factories. I'm probably not going to do the whole thing, but pick and choose some of the rules that would get me the biggest results. After Mod.cpp, then I've got the input system to handle. That one gets a little complicated since I do want to have both Android and Windows/Mac/Linux all go through the same input interface.