What would it take to fix FF8's backgrounds (field files)?

  • Thread starter Thread starter Omzy
  • Start date Start date
Status
Not open for further replies.
I thought D3D and DX interceptors like TexMod intercept textures based on hash checks (or a similar calculation), making it possible for multiple textures to accidentally get replaced by a singular texture. Texture mods with too many replacements break down with those types of programs for this reason. At least TexMod does, I've never used PIX.

I'm about as eager as anyone to get higher resolution texture support in FF8. Maybe when my VO project is done I can look into it more.
 
I thought D3D and DX interceptors like TexMod intercept textures based on hash checks (or a similar calculation), making it possible for multiple textures to accidentally get replaced by a singular texture. Texture mods with too many replacements break down with those types of programs for this reason.
When I referred to a matching algorithm above, that sort of thing is what I had in mind--a hash function. As long as it is written such that no keys(field files) have collision or fall into the same 'bucket', then that should work. This is possible, I think, since we know what all of the texture data is before-hand. We'll have to test such a function to make sure there are as many unique keys as there are hashes. http://en.wikipedia.org/wiki/Perfect_hash_function
 
I have already used such a hash method in the past to debug the driver (so that I can set breakpoints when a particular texture shows up or compare output from the texture conversion process) but it is not workable in real-time.

Textures are usually 256 * 256, either 8- or 16-bit. Add 16 different palettes of 256 32-bit colors each and you've got 70-150kb of data to hash every time the game tries to upload a texture. Now add to the mix the fact that palettes are not static, the game (and especially field files) often writes directly to the palette causing the whole texture to be reloaded (and depending on how the palette is modified you could get a million or so different hashes just for that one texture). In FF7 that is still kind-of manageable, textures aren't reloaded all that often and you can disable these palette writes without completely ruining the game (you'll just make all the field scenes feel static and dead).

Of course, FF8 is a lot more liberal with these things. Every time the game touches the emulated VRAM it'll reload some texture, sometimes more than one, this process alone is enough to make the game run slow on a modern machine, I've already had to implement a bunch of checks just to make sure it doesn't try to reload the same textures every single frame. Now, as if that wasn't enough, both palettes and textures are not even guaranteed to be in a consistent form, you'll sometimes get a texture uploaded that just contains random garbage, wasting time and hash space.

Even if such an approach is theoretically possible it would be nothing but hacks upon hacks upon further hacks. It would be a nightmare to support.
 
I wish some team would re-design the game in an alternative engine like unity...
 
I have already used such a hash method in the past to debug the driver (so that I can set breakpoints when a particular texture shows up or compare output from the texture conversion process) but it is not workable in real-time.

Textures are usually 256 * 256, either 8- or 16-bit. Add 16 different palettes of 256 32-bit colors each and you've got 70-150kb of data to hash every time the game tries to upload a texture. Now add to the mix the fact that palettes are not static, the game (and especially field files) often writes directly to the palette causing the whole texture to be reloaded (and depending on how the palette is modified you could get a million or so different hashes just for that one texture). In FF7 that is still kind-of manageable, textures aren't reloaded all that often and you can disable these palette writes without completely ruining the game (you'll just make all the field scenes feel static and dead).

Of course, FF8 is a lot more liberal with these things. Every time the game touches the emulated VRAM it'll reload some texture, sometimes more than one, this process alone is enough to make the game run slow on a modern machine, I've already had to implement a bunch of checks just to make sure it doesn't try to reload the same textures every single frame. Now, as if that wasn't enough, both palettes and textures are not even guaranteed to be in a consistent form, you'll sometimes get a texture uploaded that just contains random garbage, wasting time and hash space.

Even if such an approach is theoretically possible it would be nothing but hacks upon hacks upon further hacks. It would be a nightmare to support.
So short of a new game engine (like q-gears) we are sadly just not going to get support for it eh?

Maybe they redesigned the Steam version and we could use that? I know it's doubtful.. But a man can dream
 
Steam version was a re-release unfortunately... that's about all the fuzz for mods anyway... but they managed to make directx 9 to work with the game. Only graphical updates so far are the sweetfx image management.
 
Only graphical updates so far are the sweetfx image management.
And the Japanese version has a pretty updated high-res font. I don't know the first thing about how they did that though.
 
Yeah I should correct myself by defining graphical updates as the in-game ones...
 
Correct me if I'm wrong, but the menu system seems to be developed consequently for PC. There were different resolutions in the first place, so I think it was pretty easy for them to replace the fonts (we have done this already too).
 
Textures are usually 256 * 256, either 8- or 16-bit. Add 16 different palettes of 256 32-bit colors each and you've got 70-150kb of data to hash every time the game tries to upload a texture. Now add to the mix the fact that palettes are not static, the game (and especially field files) often writes directly to the palette causing the whole texture to be reloaded (and depending on how the palette is modified you could get a million or so different hashes just for that one texture).
I wonder if a different hashing algorithm would make this easier. The hash can be computed from the values of specific pixels normalized to black and white and stored as a string of binary digits. Most backgrounds should have a different pattern of digits if enough digits are used and a few will fail this check if they are largely homeogenous like the credits having mostly black, etc. With carefully chosen pixels and enough of them we might achieve perfect hashing. This may eliminate dependence on palettes and be more specific to patterns. Did that make any sense or am I speaking crazy? I have yet to dig my fingers into the dirt so it might sound abstract right now but I'm going to do some experimenting with patterns and see if it works.
 
The original version offers the option to choose between the low-res PSX font texture (1 256x256px texture) or the hi-res PC texture (2 256x256px textures) but the 2013 version removed this option and the hi-res font is now set by default. As I pointed out in the SeeD thread, the new japanese PC release features really sharp font so it would be interesting to see how it works (several 256x256px *.tex files or maybe 1024x1024px/2048x2048px single texture). Also in the main.fs original files there is a 512x512px *.tim file but I'm not even sure if it is an unused file or not.
 
I've been playing with hash functions and came up with this, which samples 16 distinct pixels in the VRAM image and compares their grayscales to generate a hashvalue based on their differences. It uses a threshold value for how large the difference must be and that determines if a 0 or 1 is written. Based on only 1 frame of gameplay, this works, however it may need to be expanded to 32 pixels or additional comparisons instead of a linear comparison maybe odds vs evens, etc, if we are to expect different values for every texture/palette combo in the game. Hopefully this sort of technique can eliminate the need for distinguishing between palettes.

Written in python, forgive the poor syntax/lack of efficiency, I've never used it before so I just googled how to do things really quickly
Code: [Select]
Code:
import PILfrom PIL import Imageimg = PIL.Image.open("5.bmp")rgb_im = img.convert('RGB')diff = []binval = []for i in range(0, 16): diff.append(0) binval.append(0)currvalue = 255for i in range(0,16): x = i*16 pixel = rgb_im.getpixel((x,x)) # diagonal line of pixels to sample value = (pixel[0] + pixel[1] + pixel[2]) / 3 #grayscale diff[i] = currvalue - value # difference from last pixel value currvalue = value binval[i] = diff[i] if binval[i] < 10: # convert to binary value based on threshold  binval[i] = 0 else:  binval[i] = 1hashvalue = 0for i in range (0, 16): #generate hash value from binary values hashvalue *= 2 hashvalue += binval[i]print hashvaluea = input()
 
I wish some team would re-design the game in an alternative engine like unity...
This was something I was considering for a while. The problem being that the only legal way to make such an engine is to make it support the files that come with FF8, and we still don't completely understand how some of them work (as you can see from this thread). It's just not feasible at this time. Q-Gears is feasible because we know basically everything about FF7.

Given that we'd need to understand the game files completely before making such an engine (at which point we'd probably already have better texture support), the only real benefit you'd get is higher frame rates, shader support, and extended scripting capabilities.
 
You can't just port a game into another existing engine. It doesn't work that way.
 
Oh... I was actually referring to Unity or any already made engine. And yes... Q-gears is for VII  :|
I see what you're saying, I've played with Unity--it is the most awesome design tool around for sure. I could see someone rebuilding these games from scratch in Unity using code from things like Q-gears and rewriting systems entirely to support existing or modified Square assets, but it would take a dedicated team and a good chunk of time to pull off. Heck, being able to use Unity (porting Q-gears) might rally more developers to its cause, even. For now, I'm going to try to hack my way there--at least to see if its possible.
 
And Square hunts those type of projects as well, like beginning a kickstarter... I mean look what happened to the FFVII series project, they made them look untrustworthy and fools!
 
I've rewritten the hashing algorithm in C++ and have expanded it to 64 bits of comparison on 16 pixels. It compares the 16 pixels against each other in 4 different ways and generates a 64 bit hash value. If any two images differ by less than 10 bits, they are the same image with a different palette. Otherwise, they are different images. Typically, similar images with different palettes differ by only 3-6 out of 64 bits and images that are completely different differ by 20-45 out of 64 bits. When this algorithm is adapted to sample straight from VRAM instead of filling an image buffer first, it should run very fast.

Next stop, generate a dictionary of hash values mapped to filenames and try to see if it is accurate whilst the game is running. This dictionary will be placed in an external file in the game folder and read into memory when the game starts. That may take a bit longer to figure out.

*C++, uses CImg library
Code: [Select]
Code:
#include <iostream>#include "CImg.h"using namespace std;using namespace cimg_library;uint64_t hashval = 0;int pixval[16];void growhash(int columns){    int lastpixel = 127;    for (int i = 0; i < 16; i++)    {        if      (i < 1      ) { lastpixel = 127;                    }        else if (i < columns) { lastpixel = pixval[i+(15-columns)]; }        else if (i < 16     ) { lastpixel = pixval[i-columns];      }        hashval *= 2;        (pixval[i] - lastpixel) < 0 ? /*nothing*/: hashval++;    }}void gethash(CImg<unsigned char> image){    int pixelR, pixelG, pixelB;    for (int i = 0; i < 16; i++)    {        int x = i*16;        pixelR = image(x/2, x, 0);        pixelG = image(x/2, x, 1);        pixelB = image(x/2, x, 2);        pixval[i] = (pixelR + pixelG + pixelB) / 3;    }    growhash(2*2*2*2);    growhash(2*2*2*1);    growhash(2*2*1*1);    growhash(2*1*1*1);    return;}int main() {    char filename[] = "1.bmp";    CImg<unsigned char> image(filename), visu(512,512,1,3,0);    CImgDisplay main_disp(image, filename);    gethash(image);    cout << hashval << endl;    while (!main_disp.is_closed())    {        main_disp.wait();    }    return 0;}
Edit (notes):
VRAM order theory: VRAM loads the necessary parts of a scene by selecting the next necessary 128x256 portion of the field texture (block 1) and loading the next 128x256 block after it (block 2) to fill a 256x256 square of VRAM. It cycles through the necessary palettes for block 1 until it completes all portions of block 1. If there happened to be correct palettes for block 2, it will draw those portions but will likely need more palettes to complete block 2. It cycles and loads block 2 into block 1 slot and loads the next block into block 2 slot. The process repeats with the remaining palettes of block 1 loading and completing block 1, etc. The order of necessary blocks follows the file order in that blocks at the beginning of the file are prioritized first and blocks at the end are prioritized last. Animation blocks are not loaded at all unless the current frame demands a block containing a particular animation, in which case that block will be loaded when its turn in the file sequence comes.

This implies that instead of treating each texture file as a texture, each 128x256 block should be treated as its own texture since different combinations of the block will be loaded into the 256x256 VRAM square and recognized as a complete 256x256 texture by DirectX.

So, when checking filenames for DirectX textures, the first block should be identified and the second block should be identified separately with a different hash and in the dictionary these should be labeled filename_1, filename_2, filename_3...etc for all 128x256 blocks of the field texture file.

Rough total block count: 894 files x 1664/128/2 ~5000 blocks
 
Last edited:
You have lost me when you started to load block2 into block1:
7y8u6lwl.gif
 
Status
Not open for further replies.
Back
Top