Closed dkollmann closed 1 year ago
Yes, I have seen this also. It looks like only the top part of the file is preserved. This could be for a couple of reasons:
Do you know how/when the surface is loaded into memory?
I just checked and the textures are not getting released and reloaded. Also, the requested type of texture is being created correctly. i.e. When the game requests D3DFMT_DXT3 then a D3DFMT_DXT3 texture is getting created.
I also checked the texture size (width & height) and the requested size is getting created.
Somehow it seems there is an issue with populating the texture. Maybe the way DirectDraw populates the texture does not work correctly with Direct3D9 textures?
Textures are done in blocks. It looks like the first row of blocks are getting populated but none of the other rows.
Here is a good post I found: https://www.g-truc.net/post-0335.html
So I did a test, where I instead of letting the game write into the surface buffer, I let it write into my own memory and saved that data as a DDS file. The result is the same. And the memory matches what we see, so most of it remains zero.
So it seems to me that the Unlock function is called too early.
That's weird. I am seeing the call to Unlock, but I don't see the call to Lock the DXT textures.
I hooked into
m_IDirectDrawSurfaceX::LockD39Surface(D3DLOCKED_RECT* pLockedRect, RECT* pRect, DWORD Flags)
I hooked into
m_IDirectDrawSurfaceX::LockD39Surface()
The weird thing is that Lock()
and Unlock()
are supposed to be a pair and LockD39Surface()
and UnlockD39Surface()
are supposed to be a pair. However, I am seeing Unlock()
being called without Lock()
ever getting called. Something weird is happening here and I am not sure yet if it is something weird with the game or with dxwrapper.
Perhaps completely unrelated, but on some compiles/platforms (like original Xbox) Lock got inlined, meaning any interface (re-)implementation wouldn't ever get called (instead, the code itself was compiled into the caller location)
Another idea to fix this could be to just call the other function if it is a DXT surface type.
It appears that the issue is an issue with lPitch
. DirectDraw returns 65535 whereas Direct3D9 returns 1024 for some of the DXT formats.
1024 is definitely correct. The format BC2 has 16 bytes per block, which is four pixels. So each pixel has four bytes. As the texture is 256x256, that is a pitch of 1024.
If you change the following line then it will be able to draw all the textures correctly:
From:
lpDDSurfaceDesc2->lPitch = LockedRect.Pitch;
to:
lpDDSurfaceDesc2->lPitch = LockedRect.Pitch * (ISDXTEX(surfaceFormat) ? 64 : 1);
OMG you are a genius!! Yes, that fixed it :)
Fixed this issue in the following check in: 6e2db420cd8dc80cab13f41cbecdba48d0442c4b
Closing issue.
There is something wrong with the surface created for DDS textures.
This is the original texture extracted from the game folder:![image](https://user-images.githubusercontent.com/936152/236626281-ff43760c-be38-4696-a03a-877b0b3e9275.png)
This is the surface, which I saved as a DDS file, afteer the surface is unlocked.![image](https://user-images.githubusercontent.com/936152/236626309-5986d6a0-b2cc-460f-8fd5-d625869c472c.png)
The texture is a DXT3 BC2_UNORM one: 18.zip
My guess is that the surface is already created with incorrect settings, so that the data layout of the memory does not align with the one from the surface.