Silent-Hill-2-Enhancements icon indicating copy to clipboard operation
Silent-Hill-2-Enhancements copied to clipboard

use compressed textures for fonts, switch to .dds file

Open belek666 opened this issue 1 year ago • 14 comments

  • allow to change format for font texture
  • use .dds files with dxt compression as font texture

belek666 avatar Aug 31 '22 09:08 belek666

Thank you again for your incredible work here, Belek!

@elishacloud This change was made to help support the upcoming Japanese language restoration. The default value for CustomFontRow will eventually need to be changed from 14 to 150 at some point. This value change will show all Japanese characters in the upcoming, revised HD font sheet.

Note that, if this value changes to 150 and someone is still using the current, publicly released font sheet, it'll break text display for them with the HD fonts. The new HD font sheet will release as part of an update to the Essential Files Pack.

Polymega avatar Aug 31 '22 20:08 Polymega

Note that, if this value changes to 150 and someone is still using the current, publicly released font sheet, it'll break text display for them with the HD fonts. The new HD font sheet will release as part of an update to the Essential Files Pack.

I don't like the idea where a user could have a mismatch between the HD font sheet and the CustomFontRow setting. We should figure out a way to check if the user has the correct font before changing the default value. Is there some way we can build in the value so that there is not a mismatch between the HD font and the CustomFontRow?

For example, adding 8 bytes (2 DWORDs) to the end of the file. The first DWORD is an indication of the SH2EE project and then second DWORD indicates the CustomFontRow size for this pack.

DWORD 1: 0x45324853 // Hex equivalent of 'SH2E' (little-endian) DWORD 2: 0x8C000000 // Value of 140 (little-endian)

elishacloud avatar Sep 03 '22 15:09 elishacloud

We should figure out a way to check if the user has the correct font before changing the default value.

Sure. We can do something to differentiate them. We can add a form of metadata to the file as you suggested. If you'd like to do this, just give me a rundown of how to add these 8 bytes into the file via HxD properly.

Another idea might be to have two versions of the font sheet (named different) and offer an INI option to use one or the other? So one font sheet is like it currently is in the public release (14 rows), and another the new one that supports all of the Japanese characters (150 rows).

I bring this up as a possible suggestion as, from now including the Japanese characters, the font sheet will grow substantially from 4400x896 to 4400x9600. This new, massive size will be unrenderable for certain PCs with IGPs. While our system requirements state to use a dedicated GPU, we know that's not always followed by players and this new font sheet may not render where as the old one did.

Maybe make the option in the config tool a dropdown list with three options?

  1. Enable (all characters) - Loads whatevername.dds and sets CustomFontRow = 150
  2. Enable (Latin only characters) - Loads differentname.dds and sets CustomFontRow = 14
  3. Disable

Polymega avatar Sep 03 '22 16:09 Polymega

I suppose another approach is to get the height of the font DDS file and divide it by 64 to determine the amount of rows.

Examples: 9600 / 64 = 150 rows 896 / 64 = 14 rows

No matter the approach, I'll make two versions of the DDS here soon.

Polymega avatar Sep 03 '22 16:09 Polymega

If you'd want to experiment with the determining rows by DDS height thing, I've attached two font sheets: font_sheets.zip

  • font000.dds: Full font sheet (includes Japanese characters), 4400x9600, 150 rows
  • font001.dds: Latin characters only font sheet, 4400x640, 10 rows

^ I managed to reduce the Latin-only font sheet from 14 rows to 10 rows.

Polymega avatar Sep 03 '22 16:09 Polymega

I suppose another approach is to get the height of the font DDS file and divide it by 64 to determine the amount of rows.

If a single character in a font sheet is always 64x64 then I can use the dimensions of the font sheet to determine the number of rows and columns. But if there is ever a case where the font could change to a different size that would be an issue. For instance, if the default low resolution font that comes with the game has characters using smaller than 64x64 for each character then it would be an issue.

Another solution would be if the game uses some variable to determine the character size. In this case we could use that variable along with the dimensions of the font sheet to determine the row and column size. But even that could have an issue. What if the variable does not match the actual font sheet being used?

If it is possible for characters to be a different size then I think it is better to add those values as metadata and just add some bytes to the end of the font sheet.

Metadata example:

DWORD 1:  0x45324853 // Hex equivalent of 'SH2E' (little-endian).  This indicates that there is metadata.
DWORD 2:  0x40004000 // Character size 64x64 (little-endian).  The first WORD (2 bytes) is for width, second is for height.
DWORD 3:  0x8C000000 // Row size 140 (little-endian)
DWORD 4:  0x0A000000 // Column size 10 (little-endian)

If this was the metadata then you would just add those 16 hex bytes to the end of the file:

0x 45324853 40004000 8C000000 0A000000

Note: we don't need to use little-endian if that is confusing for you. Little-endian just means that the bytes are in reverse order. For instance, the below is a normal DWORD:

   BYTE
  1 2 3 4
  V V V V
0x12345678

In this example 0x12 is the first byte, 0x34 is the second byte, etc. If you wrote this DWORD as little-endian then you would reverse all the bytes like this: 0x78563412 <-- (little-endian)

elishacloud avatar Sep 03 '22 17:09 elishacloud

BTW: from the check-in I see lots of variable, such as multiple character's widths and heights, character spacing, etc. If any of these could be changed in the font sheet then we should add all of those to the metadata as well. I just want to avoid the case were there is a mismatch between the font sheet and any of the internal settings.

elishacloud avatar Sep 03 '22 17:09 elishacloud

Each character in the font sheet is contained in a 44 x 64 cell (see image below), regardless of character dimensions/characteristics, so you would be safe to use the overall texture height to determine the amount of rows. You could also use the texture width to determine CustomFontCol. (Example: 4400 / 44 = 100)

image

I'd consider opting for this approach instead of adding customized metadata to the end of the file because there will likely be people who will make their own language packs without our input/assistance and, if they don't know about the metadata requirement, it will stump them along the way. But I'd like to know what you think in this regard.

from the check-in I see lots of variable, such as multiple character's widths and heights, character spacing, etc. If any of these could be changed in the font sheet then we should add all of those to the metadata as well.

From how I understand it, those variables are used within the game for all the Latin characters. So the game will grab a Latin character's 44x64 cell then offset its position from these variables. This is another way of saying the characters within the font sheet texture itself will always be contained in their own 44 x 64 cells, if that makes sense.

Polymega avatar Sep 03 '22 17:09 Polymega

Each character in the font sheet is contained in a 44 x 64 cell (see image below), regardless of character dimensions/characteristics, so you would be safe to use the overall texture height to determine the amount of rows. You could also use the texture width to determine CustomFontCol. (Example: 4400 / 44 = 100)

Perfect! Then we should update the code to verify the CustomFontCol and CustomFontRow settings.

Also, the hidden settings also has options for CustomFontCharHeight and CustomFontCharWidth. How can we verify these options are correct also?

I want to make sure that if someone is using the old font sheet or even the original font sheet that comes with the game they will not run into issues displaying the correct font.

elishacloud avatar Sep 03 '22 17:09 elishacloud

How can we verify these options are correct also?

Oh man... There's probably several ways we could approach this, and I'm not sure which way would be the best approach. I'm going to throw out an initial (probably bad) idea to see if that can get your gears grinding:

For the Essential Files Pack, we include a font000.dds (all characters) and font001.dds (Latin only) files. Offer both of these so, if font000 doesn't render because its resolution is too large for a GPU to handle, they can fall back on font001 at the expense of no Japanese HD characters.

Change the INI option for 'Use high resolution font' in the Config Tool to a dropdown list with the following options:

  • Enable (all characters) - Loads font000.dds and sets CustomFontRow = 150
  • Enable (Latin only characters) - Loads font001.dds and sets CustomFontRow = 10
  • Disable

If CustomFontRow or CustomFontCol exists in the INI, have it overwrite the values mentioned above.

...this feels kind of messy. But I'm hoping it may get the ball rolling on something better.


I want to make sure that if someone is using the old font sheet or even the original font sheet that comes with the game they will not run into issues displaying the correct font.

If the user disables UseCustomFonts the game will load its original font sheet (found within its own, main binary) with no issues, just as its always done.

The PR Belek has submitted will drop TGA support (what font000.tga currently is) in favor of DDS support (what font000.dds will become) for our HD fonts. So when this update gets pushed, a user will also need to update the Essential Files Pack which will contain new .dds font sheets.

I plan to work with people who have made language packs in the past with our help (as I've previously done with the Russian, Brazilian Portuguese, Polish, and Turkish communities) to bring their font sheets up to spec with this change.

Polymega avatar Sep 03 '22 18:09 Polymega

Also, the hidden settings also has options for CustomFontCharHeight and CustomFontCharWidth. How can we verify these options are correct also?

Er, sorry, I glanced over and misread these option names as CustomFontRow and CustomFontCol. These values should stay hidden as, realistically, they'll never be adjusted. They haven't been adjusted to date, as far as I'm aware. I believe if font width data needs to be changed, it's exclusively done by modifying the fontwdata.bin file that is part of the HD font package.

Those two settings really would only be changed for a custom language pack, and I'm not sure if they've ever needed to be changed for a custom language pack.

Polymega avatar Sep 03 '22 18:09 Polymega

Sorry for all the messages in a row, but I think you might have been asking what if CustomFontCharHeight or CustomFontCharWidth gets changed and how would that affect something like the original/vanilla font sheet? It should be fine and safe. These special settings only affect the HD font sheet, I believe. If UseCustomFonts gets disabled, so do all of these other special options. And if the font000 file doesn't exist, I don't believe any of these special options will work.

Polymega avatar Sep 03 '22 18:09 Polymega

@elishacloud maybe use dwReserved1[11] from dds header as a place for defining size of font table? I'm thinking also about using the same method for generating font texture as game normally use - smaller texture with fixed glyphs number and corresponding table with ids. Texture will be updated with single glyph if requested id is not found. That should fix any issue with IGP which @Polymega mentioned.

belek666 avatar Sep 06 '22 20:09 belek666

That should fix any issue with IGP which @Polymega mentioned.

Thanks so much, Belek. If there's anything I can do with the font sheet to assist with testing, just let me know.

Polymega avatar Sep 06 '22 20:09 Polymega

For the Essential Files Pack, we include a font000.dds (all characters) and font001.dds (Latin only) files. Offer both of these so, if font000 doesn't render because its resolution is too large for a GPU to handle, they can fall back on font001 at the expense of no Japanese HD characters.

Why not detect that the game cannot load font000.dds and then auto fail-over to font001.dds? This seem better than having the user manually change it. We can add a warning in the log file when we fail over.

I glanced over and misread these option names as CustomFontRow and CustomFontCol. These values should stay hidden as, realistically, they'll never be adjusted. They haven't been adjusted to date, as far as I'm aware. I believe if font width data needs to be changed, it's exclusively done by modifying the fontwdata.bin file that is part of the HD font package.

Why do we have the values CustomFontRow and CustomFontCol if they are already stored in the fontwdata.bin file? Why not remove them from the ini file and just get them from the fontwdata.bin file?

I think you might have been asking what if CustomFontCharHeight or CustomFontCharWidth gets changed and how would that affect something like the original/vanilla font sheet? It should be fine and safe. These special settings only affect the HD font sheet, I believe.

I think it would be better if this value was in some metadata.

maybe use dwReserved1[11] from dds header as a place for defining size of font table? I'm thinking also about using the same method for generating font texture as game normally use - smaller texture with fixed glyphs number and corresponding table with ids.

I like this idea. The first four bytes can be used for the CustomFontCharWidth and the second four bytes for the CustomFontCharHeight? this should keep all the settings self contained and allow for different sized HD fonts.

elishacloud avatar Sep 16 '22 02:09 elishacloud

Why not detect that the game cannot load font000.dds and then auto fail-over to font001.dds? This seem better than having the user manually change it. We can add a warning in the log file when we fail over.

Oh, I did not know we had the capability to know this. If we can detect it's not loading/displaying and have it fall back to a smaller font sheet, that would be great then.

I'm thinking also about using the same method for generating font texture as game normally use - smaller texture with fixed glyphs number and corresponding table with ids. Texture will be updated with single glyph if requested id is not found. That should fix any issue with IGP which @Polymega mentioned.

@belek666, it sounds like your idea here is also to have two versions of the HD font sheet? One with Japanese characters and one without Japanese characters (to fall back on)? Or is your idea different?

Why do we have the values CustomFontRow and CustomFontCol if they are already stored in the fontwdata.bin file? Why not remove them from the ini file and just get them from the fontwdata.bin file?

@belek666 will need to answer this, as there might be differences between them that I'm forgetting or not aware of.

Polymega avatar Sep 16 '22 03:09 Polymega

@belek666, is is possible to cleanly support backwards compatibility so that if someone does not upgrade the fonts file (for whatever reason) it won't break?

Maybe just keep the old code somewhere and have an if statement if it does not find the dds font then switch to using the old code, or something like that. Can this be done cleanly so that we don't need to worry about maintaining the old code, just keep it for backwards compatibility?

elishacloud avatar Sep 16 '22 15:09 elishacloud

Why not detect that the game cannot load font000.dds and then auto fail-over to font001.dds? This seem better than having the user manually change it. We can add a warning in the log file when we fail over.

I could be added. The texture with higher number in filename can be first to use. Default one would be font000.*

Why do we have the values CustomFontRow and CustomFontCol if they are already stored in the fontwdata.bin file? Why not remove them from the ini file and just get them from the fontwdata.bin file?

CustomFontCol describes how many glyphs texture has in width and CustomFontRow describes in height. fontwdata.bin is individual glyph width

I think it would be better if this value was in some metadata.

I like this idea. The first four bytes can be used for the CustomFontCharWidth and the second four bytes for the CustomFontCharHeight? this should keep all the settings self contained and allow for different sized HD fonts.

I've updated code with new method. At end of external font file metadata can be placed as additional 16 bytes. First 8 bytes are SH2EEFNT as id, next 4 bytes is CustomFontCol and 4 bytes as CustomFontRow. This is optional and if not found those values will be based on texture width and height assuming constant glyph resolution (44x64). So it is backward compatible. Now I'm using stb_image for loading image files and fonts can be in "tga", "png", "jpg", "dds" format. Instead copying all bitmap data from external file I use now what game normally implements - smaller texture, updated if needed.

@polymega

d3d8.zip

Could You test this build with IGP?

belek666 avatar Sep 18 '22 08:09 belek666

Could You test this build with IGP?

Of course, I'm happy to. Using a full HD font sheet (150 col, 100 row) in .dds format, the font displays like this with an IGP:

sh2pc 2022-09-18 12-15-37

If I include CustomFontCol = 100 and CustomFontRow = 150 in the ini then nothing is displayed:

sh2pc 2022-09-18 12-18-28

Polymega avatar Sep 18 '22 16:09 Polymega

Could You test this build with IGP?

Of course, I'm happy to. Using a full HD font sheet (150 col, 100 row) in .dds format, the font displays like this with an IGP:

sh2pc 2022-09-18 12-15-37

If I include CustomFontCol = 100 and CustomFontRow = 150 in the ini then nothing is displayed:

sh2pc 2022-09-18 12-18-28

Yeah, I have the same. There is something wrong with stb and dxt support or I'm missing something. But uncompressed dds works. You can also use png, tga, jpg. CustomFontCol and CustomFontRow shouldn't be changed in ini as they are not for external font now. Instead you can define it inside external font file by adding new 16 bytes at end, first 8 as id "SH2EEFNT" and then 4 bytes is CustomFontCol and 4 bytes as CustomFontRow. But it's not necessary. Those values will be calculated from font resolution if metadata isn't found and when single cell form font texture has resolution 44x64 - so any file complies with this should work without any changes.

belek666 avatar Sep 18 '22 17:09 belek666

There is something wrong with stb and dxt support or I'm missing something. But uncompressed dds works.

SH2 uses DXT for just about all of its textures, but its files use a custom header. I would be surprised if this isn't supported. Although, I've never heard of an uncompressed DDS file before. I thought DXT, by its very nature, was only lossy (compressed)?

I tried using a PNG of the font sheet but received the same results:

sh2pc 2022-09-18 13-30-34

Here is a PNG file: font000.png

Also, you previously mentioned PNG will momentarily lag the game when used, so maybe we shouldn't use PNG?

TGA at this size will make the file around160 MB. We can of course use TGA if need be, but it might be better to do another format, if feasible.

Polymega avatar Sep 18 '22 17:09 Polymega

I tried using a PNG of the font sheet but received the same results:

This is incorrect, sorry. I forgot to delete the CustomFontCol and CustomFontRow lines from the INI from my previous test. It works with PNG on my laptop with IGP:

sh2pc 2022-09-18 13-36-33 sh2pc 2022-09-18 13-36-38

The PNG file is ridiculously small at ~10MB. Do you still experience the performance penalties when using PNG like before? If not, we can certainly use this format.

Polymega avatar Sep 18 '22 17:09 Polymega

There's some display issue, at least for the Japanese language, where characters are not being displayed. If you then re-examine the item, the text will display correctly:

sh2pc 2022-09-18 13-45-35 sh2pc 2022-09-18 13-45-44 sh2pc 2022-09-18 13-46-25 sh2pc 2022-09-18 13-46-37 sh2pc 2022-09-18 13-47-06 sh2pc 2022-09-18 13-47-11

Edit: Other languages as well:

sh2pc 2022-09-18 14-41-10 sh2pc 2022-09-18 14-41-15

Polymega avatar Sep 18 '22 17:09 Polymega

The PNG file is ridiculously small at ~10MB. Do you still experience the performance penalties when using PNG like before? If not, we can certainly use this format.

Thanks for testing. Performance should be the same as with the normal font since game use smaller texture. From my tests no lag at all. I probably found what may causing some text to disappear. d3d8.zip

belek666 avatar Sep 18 '22 20:09 belek666

SH2 uses DXT for just about all of its textures, but its files use a custom header. I would be surprised if this isn't supported. Although, I've never heard of an uncompressed DDS file before. I thought DXT, by its very nature, was only lossy (compressed)?

Actual font texture is uncompressed since it is updated with single chars when requested. It can hold 400 glyphs. So what patch do is first load external font image, uncompress it using external library stb to buffer. Then when game is requesting char by its id simply copy data from buffer to game font texture. So problem with dxt format is in stb library.

belek666 avatar Sep 18 '22 21:09 belek666

I probably found what may causing some text to disappear.

Hmm... still experiencing the issue. This is testing on my laptop with an IGP, for what it's worth. To try this yourself:

Launch the game, load a save file (such as the one below in the hospital), interact with something, and it should happen. It will fix itself after the first time. To test again, fully close and relaunch the game.

image

Polymega avatar Sep 19 '22 02:09 Polymega

Randomly tested this on my old Win7 desktop and the display issue is present there as well, so this doesn't appear to be an IGP-specific problem. Looks like you can also test this on the load screen (only happens on the first time, though):

https://user-images.githubusercontent.com/27395260/191081080-0033d3db-2e2f-457f-9ddf-e98340cb8f11.mp4

Polymega avatar Sep 19 '22 17:09 Polymega

Thank You again for testing. I was able to reproduce this problem and find the error. d3d8.zip Didn't test it much but works where problem occurred. I do more tests later.

belek666 avatar Sep 22 '22 21:09 belek666

Awesome! Looks to be resolved. Thank you very much. One final request: If you have both a TGA and PNG font sheet then it will currently choose TGA > PNG. Can we make it to where it chooses PNG > TGA?

Our new font sheet that will include all 150 rows will be in PNG, so this change will ensure players will be using the new font sheet over the old one if they have both in the font folder.

@elishacloud Please see Belek's comments at the end of his post here. A heads-up that CustomFontCol and CustomFontRow might need to be removed from settings.h once his PR is committed?

Polymega avatar Sep 23 '22 00:09 Polymega

CustomFontCol and CustomFontRow shouldn't be changed in ini as they are not for external font now. Instead you can define it inside external font file by adding new 16 bytes at end, first 8 as id "SH2EEFNT" and then 4 bytes is CustomFontCol and 4 bytes as CustomFontRow. But it's not necessary. Those values will be calculated from font resolution if metadata isn't found

It looks like this has not been implemented yet. If everything else is ready for this PR than I can merge it and we can work in removing these in the next update.

elishacloud avatar Sep 24 '22 16:09 elishacloud