Replies: 2 comments 1 reply
-
Hello everyone, I've just started to explore the process of customizing a new Firstly, the rendering of a Next, in the editor's Then, we need to implement a Finally, under this |
Beta Was this translation helpful? Give feedback.
-
Hello everyone, I have roughly figured out the entire process. Since my implementation does not take into account the complete business logic and edge cases, I will not be directly sharing a repository (as it would not be directly usable even if shared), but I will explain the process in the following text. I will keep the discussion open in case someone wishes to further communicate. Due to the fact that the official font implementation of Stride does not meet my needs, and most of its scheduling processes are isolated at the internal level, I need to implement a font management system myself, which can be achieved through a library called FreeType2 (there is a wrapper library for .Net called FreeTypeSharp). Through this library, we can obtain the necessary font information and get the bitmap for each character. What we specifically need to do is to implement a font management class that can track and maintain the layout information and bitmap for each character (by drawing the bitmap on a large texture as an atlas), and other modules can call to get the layout information and texture information of a character through key-value pairs (including char, width, height, style, etc., which can be decided by you). Finally, the text is rendered through the renderer. In fact, there are still parts of the process that require calling the internal parts, but they can all be achieved through
Below is the specific implementation explanation. Since the FreeType2 API returns errors through error codes, we can wrap it into an exception-throwing method through extension methods.
We use the FreeType2 API to get several faces from the font file, each face contains all the characters of a specific style in a family. This is exactly where the official implementation of Stride is not good, their implementation assumes that the font only has three styles: regular, bold, and italic, and cannot recognize style identifiers like heavy, light, etc. We can read the string of the style name through the FreeType2 API and classify the faces based on this.
Then we need to define the query key and layout information for a single character. This part can be designed according to your business needs, and below is my implementation.
Next, we can implement the method to read the character glyph information from the font file. You can notice that I called the method to generate a bitmap at this time, which will be discussed next.
For texture management, what we need to do is track a texture atlas, draw the bitmap from FreeType2 to the texture through Stride's graphics API, and save the reference of the texture (the index of the texture list is also fine, as long as you can get this texture through the character information later) and the rectangle of this character on the texture into the character information. The algorithm for inserting graphics can directly use the GuillotinePacker implemented by the official Stride. What I demonstrate here is an implementation written just to run through the process, without considering optimization and edge cases. If you want to implement a complete font management, I suggest reading the source code.
After completing the above steps, we can come to the implementation of the renderer, and here only the override of the RenderColor method is demonstrated. The implementation of the renderer, in essence, is two parts of work. One part is to convert the world coordinate matrix of the UI element to the rendering view matrix, which can be copied from the official implementation; the other part is to complete the drawing at the original point after the conversion. The official implementation is relatively complex due to optimization needs and actual business logic, and here we only demonstrate the principle, so a very simple drawing logic can be implemented.
The official implementation above has already pointed the current matrix to the upper left corner of the text box, and we simply implement a logic of laying out the text from the upper left corner to the right. Regarding the typesetting knowledge, I suggest directly reading the official documentation of FreeType2, but in simple terms, what the listed code does is to offset the original point of the upper left corner to the baseline based on which the character layout is based. And once the baseline is obtained, we can adjust the specific position of the bitmap through the layout information of the character. All values are divided by 64 because of the data conversion reason of FreeType2.
With this, the most basic independent font rendering has been implemented. |
Beta Was this translation helpful? Give feedback.
-
I'm attempting to implement a new text block but encountered internal fields and methods after copying the code from DefaultTextBlockRenderer (e.g., SpriteFont.InternalUIDrawCommand, UIElement.LayoutingContext, TextBlock.WorldMatrixInternal, and UIBatch.DrawString). Since Stride doesn't seem to have functionality similar to Unity's assembly definition assets, my options appear to be either using reflection or modifying Stride's source code and building it myself. The latter seems like overkill, and the former isn't an ideal solution. Are there any recommended approaches for implementing a custom ElementRenderer?
Beta Was this translation helpful? Give feedback.
All reactions