aliens

Author Topic: OXCE Lua/Vulkan  (Read 6260 times)

Offline Whispers

  • Sergeant
  • **
  • Posts: 47
    • View Profile
Re: OXCE Lua/Vulkan
« Reply #15 on: December 03, 2024, 01:17:53 am »
I thought I'd give a bit more of an update now that I've returned from a short "break". Unfortunately, I've had to pay some bills these last few weeks so I wasn't able to make much progress, but while I was working on other things, I've been thinking about how to handle the Vulkan renderer moving forward.

When working on something like this, the main goal is just to get it to work and then iterate on it. Well, I managed to get it to work. Sortof...

It was mimicking the surface blitting from SDL with some fairly basic shaders. I even went so far as to make the texture coordinates as integers instead of floats, using a fixed sampler, and then I was able to pass in the same coordinates from before and it would render the text, windows, and so on. Palettes were handled by uniform buffers and the palette ID was passed in as part of the rendering pipeline. I even went so far as to fix the aspect ratio in the game surface to windows surface shader.

However, the structure of it all bothered me. It wasn't very flexible and it felt a little like I was cramming functions into objects just for one single thing. That's not good design!

So, I've started cutting it up into smaller and smaller bits. While I'm at it, I want to make it API agnostic as well. If you want to render using DirectX12, that is something someone else can handle, but it should be possible.

Why go through all this effort? Easy! In the process of creating the new renderer, I've created a handful of "managers". Under normal circumstances, I don't like calling things "Managers". The term itself is ubiquitous since technically everything you write in code manages something, but it actually makes things super easy to manage resources. I'll hold my disdain for calling things Managers for now, and I'll just tell myself it sounds better than calling it "System". However, I digress. So, with that out of the way, practically every resource gets it's own data type and manager. All the Windows, Buttons, Text Boxes, Images, Palettes, Fonts and more! When I get to Battlescape, I'll be repeating the same pattern.

For instance, the base game only had 3 fonts that I know of. There's the DOS font that you see at the startup of the game while Mod.cpp loads, then there's the two in-game fonts(Large and Small). Now, I've got a FontManager. You can register your own font, complete with multiple pages and unicode support if you need it. Using the Large or Small font is still there, but now they are explicitly used by their handles. Also, I've kept the "turn big font into small font if it doesn't fit onscreen" for now, but I'm seriously debating if I should keep it in. Anyway, I digress. With the FontManager, I can now tie that into the entity inspector and scripting to allow me to register and use my own font if I want to.

However, one thing that struck me while I was doing the Window Manager is that I can now allow modders to create their own custom frames. The old way of drawing the frames was to use FillRect with preset values. With Vulkan, that doesn't work so well. I mean, you CAN do it, but I didn't want to. Vulkan works best if you create resources and then upload them to the GPU once, and only once. Draing the frame using FillRect is possible, but since the frame itself is animated when popping up, I didn't want to have to push up images every frame when I could just pass up coordinates. I can just upload a texture, specify the 8 cardinal and diagonal directions, then render those at the window coordinates. Instead of hardcoding that 5x5 corners, and the 5x1 sides, and 1x5 top and bottom, I can just let the WindowManager create the frame and the WindowFrame can be driven by the data. Data, as you can probably guess, can be modified through mods.

Why this long-winded explanation? Well, it's because in the process of redoing all the Window stuff with the new Vulkan images, I realized that a dedicated modder could use this framework to simply replace the border texture by specifying a file and the coordinates, then they can have ornate frames around in-game windows. Cool, eh? (I know, not the "killer feature" for this branch, but I thought it was nifty)

I'm going to spend a little while longer on Vulkan, mainly because I still have a week or two of real work to pay the power bills, but also because I'm having a bit of fun with it. I really enjoy trying to make the interfaces as elegant and clear as possible, and being distracted by real work has given me the opportunity to really just slowly refine what I have into something much cooler!

Offline ashugg

  • Sergeant
  • **
  • Posts: 11
    • View Profile
Re: OXCE Lua/Vulkan
« Reply #16 on: December 05, 2024, 10:10:40 am »
Hi Whispers,

I've starred the repo, and just wanted to register my interest in attempting to build your fork on macOS.

Offline Whispers

  • Sergeant
  • **
  • Posts: 47
    • View Profile
Re: OXCE Lua/Vulkan
« Reply #17 on: December 10, 2024, 01:35:05 am »
Hi Whispers,

I've starred the repo, and just wanted to register my interest in attempting to build your fork on macOS.

Thanks!

I have a "hackintosh" that I've created that I use to check compatibility. Specifically, I check to make sure it works with homebrew. I don't spend as much time on it as I do Linux/Android/Windows though, so I do expect things to break there from time to time.

Offline ashugg

  • Sergeant
  • **
  • Posts: 11
    • View Profile
Re: OXCE Lua/Vulkan
« Reply #18 on: December 13, 2024, 12:22:01 am »
Occasional breakage is expected  ;D

Offline Whispers

  • Sergeant
  • **
  • Posts: 47
    • View Profile
Re: OXCE Lua/Vulkan
« Reply #19 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.