Silent-Hill-2-Enhancements
Silent-Hill-2-Enhancements copied to clipboard
use compressed textures for fonts, switch to .dds file
- allow to change format for font texture
- use .dds files with dxt compression as font texture
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.
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)
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?
- Enable (all characters) - Loads whatevername.dds and sets
CustomFontRow = 150
- Enable (Latin only characters) - Loads differentname.dds and sets
CustomFontRow = 14
- Disable
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.
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.
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)
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.
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)
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.
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.
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.
Also, the hidden settings also has options for
CustomFontCharHeight
andCustomFontCharWidth
. 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.
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.
@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.
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.
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
andCustomFontCol
. 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 thefontwdata.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
orCustomFontCharWidth
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.
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
andCustomFontCol
if they are already stored in thefontwdata.bin
file? Why not remove them from the ini file and just get them from thefontwdata.bin
file?
@belek666 will need to answer this, as there might be differences between them that I'm forgetting or not aware of.
@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?
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
andCustomFontCol
if they are already stored in thefontwdata.bin
file? Why not remove them from the ini file and just get them from thefontwdata.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 theCustomFontCharHeight
? 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
Could You test this build with IGP?
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:
If I include CustomFontCol = 100
and CustomFontRow = 150
in the ini then nothing is displayed:
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:
If I include
CustomFontCol = 100
andCustomFontRow = 150
in the ini then nothing is displayed:
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.
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:
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.
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:
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.
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:
Edit: Other languages as well:
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
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.
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.
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
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.
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?
CustomFontCol
andCustomFontRow
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.