Here I want to make some reflections on the current script-texture system and propose improvements. I will base myself on experience with OMSI 2, as I don't own LOTUS yet, because the macros are basically the same. I also made some reflections based on Busfanat's thread about his matrix.
A few weeks ago I tried to implement a matrix with scrolling text in OMSI 2 (this effect), so the script-texture had to be updated every frame.
These are the main steps I perform:
When the destination/line number changes: do all the calculations to format and position the text. For each text line save: string, starting position, font index, width, available width and if it should scroll or not.
At each frame:
- create an empty memory-bitmap
- write the destination lines (scrolling one pixel left at each frame where necessary)
- blank out the area where the line number has to be written
- write the line number
- copy the memory bitmap to the texture
As you can easily state, this is just a modification of the standard approach used by the Krueger, and I also think that it's the most elegant way of dealing with scrolling matrix at the moment (I also saw people representing matrix with strings of points and spaces), but it has two main issues:
Due to the fact that the destination doesn't fit in the display, when the display is updated TexWriteLn has to start writing over the line number and the pre-existing destination, which leads to an overlapping. So it's necessary to "mask" the exceeding part and re-write also the static parts of the display at each frame, which in turn makes it easier to clean it up completely and re-write
it from scratch.
Transferring the bitmap
Once you're done writing the memory bitmap, it has to be copied to the final bitmap (which is twice the resolution) pixel-by-pixel.
This is very time consuming and basically it's the thing which makes it very impractical to have decent performance with scrolling destinations.
These problems may now be addressed with some ugly workarounds (like using double-resolution fonts to write directly on the final texture), but I tried to come up with more elegant solutions,
trying to be as little ground-braking as possible with the current system.
New macro for writing text
The fix for the overlapping problem would be to introduce a new macro for writing out text, which constrains text in the rectangular frame (x1, y1), (x2, fontHeight) so it does not overlap with existing text:
This macro is a modified version of TexWriteLn() with the following additions:
- the frame (x1, y1), (x2, fontHeight) is blanked out (nothing which was previously there should be seen afterwards)
- the first cropPixels pixels of the output text are cropped out (not written)
- writing starts at the pixel (x1,y1)
- writing stops when it reaches the horizontal coordinate x2
This solves the left-overlapping problem and also makes it deadly simple to have a scrolling destination, by incrementing cropPixels at each frame.
Alternative: Passing width instead of coordinate x2 (width = x2-x1)
Using nearest-point sampling
The reason we're transferring pixels from the memory bitmap to the final bitmap is just to get a higher resolution texture which matches with the dots/LEDs of the matrix display, but this operation does not bring in any new information (apart from the error-pixel maybe) and should possibly be avoided at this point, as it degrades performance (unless you have to copy the memory a few pixels at a time, as the Krueger does).
The need of a higher-res texture comes from the fact that the use of linear/bilinear texture filtering (I guess that's what you use) "smoothens" the edges of the lower-res texture, which does not match the underlying hi-res texture for the dots/LEDs. This is very clear in this image from Busfanat:
My suggestion is to do a test using the lo-res memory bitmap with nearest-point sampling, which gives out sharp edges when upscaling by a constant factor (2 in our case). Here a single pixel of the memory bitmap will be the dimension of four pixels of the matrix texture, no need for transferring.
I couldn't try this myself, but if it works fine users may be given the ability to choose the filtering method when creating the script-texture in the Content-Tool.
Thanks for reading this far.
This post is especially addressed to LOTUS developers Marcel Kuhnt and Janine , but the discussion is of course open to anyone, so feel free to comment on these features and bring in alternative solutions or other related features.
A note for LOTUS developers:
First of all thanks for making us part of the development of this wonderful project.
I based my proposals on how I guess you manage Script-Textures under-the-hood, as I obviously can't see the implementation, and wrote them down as clear as I could. If you need more information or suggestions on implementation just ask me and don't be afraid to go technical because I'm a developer too.
The last thing I want to ask you is if the operations on Script-Textures are handled synchronously or asynchronously with the script. This came to my mind when I worked with the lock/unlock statements in OMSI and saw some blinkering.
If you use an asynchronous approach, it may also be seen as an opportunity (or at least it's something to be aware of).