Files
Cesarus85--mjolnir-vr/libs/d3d8/pixeljar.cpp
T

443 lines
13 KiB
C++

/* Pixel-container reconstruction against the January Halo binary.
* Algorithms adapted from RXDK-Libs, 2026 Team Resurgent.
* SPDX-License-Identifier: GPL-3.0-or-later
* Target-specific APIs and layouts differ from the reference.
*/
#include "device_layout.h"
#include "pixeljar.h"
#include "resource_internal.h"
#pragma code_seg("D3D")
namespace D3D
{
/* Period math helper and target both use BSF. Keep an explicit C return. */
DWORD __fastcall Log2(
DWORD value)
{
DWORD result;
__asm
{
mov ecx, value
bsf eax, ecx
mov result, eax
}
return result;
}
D3DFORMAT WINAPI MapToLinearD3DFORMAT(
D3DFORMAT format)
{
switch (format)
{
case D3DFMT_A8R8G8B8: format = D3DFMT_LIN_A8R8G8B8; break;
case D3DFMT_X8R8G8B8: format = D3DFMT_LIN_X8R8G8B8; break;
case D3DFMT_R5G6B5: format = D3DFMT_LIN_R5G6B5; break;
case D3DFMT_X1R5G5B5: format = D3DFMT_LIN_X1R5G5B5; break;
case D3DFMT_A1R5G5B5: format = D3DFMT_LIN_A1R5G5B5; break;
case D3DFMT_D16: format = D3DFMT_LIN_D16; break;
case D3DFMT_D24S8: format = D3DFMT_LIN_D24S8; break;
case D3DFMT_F16: format = D3DFMT_LIN_F16; break;
case D3DFMT_F24S8: format = D3DFMT_LIN_F24S8; break;
}
return format;
}
bool WINAPI IsCompressedD3DFORMAT(
DWORD format)
{
bool compressed = false;
switch (format)
{
case D3DFMT_DXT1:
case D3DFMT_DXT2:
case D3DFMT_DXT4:
compressed = true;
break;
}
return compressed;
}
DWORD WINAPI CalcPitch(
DWORD width,
DWORD texelSize)
{
return (width * texelSize / 8 + D3DTEXTURE_PITCH_ALIGNMENT - 1) &
~(D3DTEXTURE_PITCH_ALIGNMENT - 1);
}
DWORD WINAPI VideoBitsPerPixelOfD3DFORMAT(
DWORD format)
{
DWORD bitsPerPixel;
if (format == D3DFMT_X1R5G5B5 || format == D3DFMT_LIN_X1R5G5B5)
{
bitsPerPixel = 15;
}
else
{
bitsPerPixel = BitsPerPixelOfD3DFORMAT(format);
}
return bitsPerPixel;
}
DWORD WINAPI CalcTilePitch(
DWORD width,
D3DFORMAT format)
{
DWORD pitch = CalcPitch(width, BitsPerPixelOfD3DFORMAT(format));
DWORD i;
for (i = 0; i < 16; i++)
{
if (pitch <= g_TilePitches[i])
{
pitch = g_TilePitches[i];
break;
}
}
return pitch;
}
namespace PixelJar
{
void WINAPI GetDepthBufferScale(
D3DPixelContainer *pixel,
float *scale)
{
switch (GetFormat(pixel))
{
case D3DFMT_D16:
case D3DFMT_LIN_D16:
*scale = (float)D3DZ_MAX_D16;
break;
case D3DFMT_D24S8:
case D3DFMT_LIN_D24S8:
*scale = (float)D3DZ_MAX_D24S8;
break;
case D3DFMT_F16:
case D3DFMT_LIN_F16:
*scale = (float)D3DZ_MAX_F16;
break;
case D3DFMT_F24S8:
case D3DFMT_LIN_F24S8:
*scale = (float)D3DZ_MAX_F24S8;
break;
}
return;
}
void WINAPI GetSize(
D3DPixelContainer *pixel,
DWORD level,
DWORD *width,
DWORD *height,
DWORD *depth,
DWORD *pitch,
DWORD *slice)
{
DWORD size = pixel->Size;
if (!size)
{
long logWidth = GetLogWidth(pixel) - level;
long logHeight = GetLogHeight(pixel) - level;
long logDepth = GetLogDepth(pixel) - level;
DWORD bitsPerPixel = GetBitsPerPixel(pixel);
*height = 1 << (logHeight > 0 ? logHeight : 0);
*depth = 1 << (logDepth > 0 ? logDepth : 0);
*width = 1 << (logWidth > 0 ? logWidth : 0);
long logMin = (long)MinimumTextureSizeOfD3DFORMAT(GetFormat(pixel));
DWORD physicalWidth = 1 << max(logMin, logWidth);
DWORD physicalHeight = 1 << max(logMin, logHeight);
switch (GetFormat(pixel))
{
case D3DFMT_DXT1:
*pitch = physicalWidth * 2;
break;
case D3DFMT_DXT2:
case D3DFMT_DXT4:
*pitch = physicalWidth * 4;
break;
default:
*pitch = physicalWidth * bitsPerPixel / 8;
break;
}
*slice = physicalWidth * physicalHeight * bitsPerPixel / 8;
}
else
{
*width = (size & D3DSIZE_WIDTH_MASK) + 1;
*height = ((size & D3DSIZE_HEIGHT_MASK) >> D3DSIZE_HEIGHT_SHIFT) + 1;
*depth = 1;
*pitch = PitchFromSize(size);
*slice = *pitch * *height;
}
return;
}
void WINAPI Get2DSurfaceDesc(
D3DPixelContainer *pixel,
UINT level,
D3DSURFACE_DESC *desc)
{
desc->Format = GetFormat(pixel);
desc->Type = pixel->GetType();
desc->Usage = 0;
if (level == 0)
{
if (IsValidRenderTarget(pixel))
{
desc->Usage = D3DUSAGE_RENDERTARGET;
}
else if (IsValidDepthBuffer(pixel))
{
desc->Usage = D3DUSAGE_DEPTHSTENCIL;
}
}
if (pixel->Data == g_pDevice->m_FrameBufferSurfaces[0].Data &&
(D3D__RenderState[D3DRS_MULTISAMPLETYPE] & 0x3000))
{
desc->MultiSampleType = (D3DMULTISAMPLE_TYPE)D3D__RenderState[D3DRS_MULTISAMPLETYPE];
}
else
{
desc->MultiSampleType = D3DMULTISAMPLE_NONE;
}
DWORD width, height, depth, pitch, slice;
GetSize(pixel, level, &width, &height, &depth, &pitch, &slice);
desc->Width = width;
desc->Height = height;
desc->Size = slice;
return;
}
void WINAPI Get3DSurfaceDesc(
D3DPixelContainer *pixel,
UINT level,
D3DVOLUME_DESC *desc)
{
desc->Format = GetFormat(pixel);
desc->Type = pixel->GetType();
desc->Usage = 0;
DWORD width, height, depth, pitch, slice;
GetSize(pixel, level, &width, &height, &depth, &pitch, &slice);
desc->Width = width;
desc->Height = height;
desc->Depth = depth;
desc->Size = slice * depth;
return;
}
void WINAPI FindSurfaceWithinTexture(
D3DPixelContainer *pixel,
D3DCUBEMAP_FACES face,
UINT level,
BYTE **outData,
DWORD *outRowPitch,
DWORD *outSlicePitch,
DWORD *outFormat,
DWORD *outSize)
{
BYTE *data = GetDataFromResource(pixel);
DWORD texelSize = GetBitsPerPixel(pixel);
DWORD rowPitch, slicePitch;
DWORD size = pixel->Size;
if (!size)
{
DWORD logWidth = GetLogWidth(pixel);
DWORD logHeight = GetLogHeight(pixel);
DWORD logDepth = GetLogDepth(pixel);
DWORD logMin = MinimumTextureSizeOfD3DFORMAT(GetFormat(pixel));
if (face != D3DCUBEMAP_FACE_POSITIVE_X)
{
DWORD levels = GetMipmapLevelCount(pixel);
DWORD faceWidth = logWidth;
DWORD faceHeight = logHeight;
DWORD faceDepth = logDepth;
DWORD faceSize = 0;
for (; levels; levels--)
{
faceSize += (1 << (max(faceWidth, logMin) + max(faceHeight, logMin))) * texelSize / 8;
if (faceWidth > 0) faceWidth--;
if (faceHeight > 0) faceHeight--;
if (faceDepth > 0) faceDepth--;
}
faceSize = (faceSize + D3DTEXTURE_CUBEFACE_ALIGNMENT - 1) &
~(D3DTEXTURE_CUBEFACE_ALIGNMENT - 1);
data += faceSize * face;
}
if (level)
{
DWORD levels = level;
DWORD logSize;
for (; levels; levels--)
{
logSize = max(logWidth, logMin) + max(logHeight, logMin) + logDepth;
data += (1 << logSize) * texelSize / 8;
if (logWidth > 0) logWidth--;
if (logHeight > 0) logHeight--;
if (logDepth > 0) logDepth--;
}
}
DWORD format = pixel->Format & ~(D3DFORMAT_USIZE_MASK | D3DFORMAT_VSIZE_MASK | D3DFORMAT_PSIZE_MASK);
format |= logWidth << D3DFORMAT_USIZE_SHIFT;
format |= logHeight << D3DFORMAT_VSIZE_SHIFT;
format |= logDepth << D3DFORMAT_PSIZE_SHIFT;
logWidth = max(logWidth, logMin);
logHeight = max(logHeight, logMin);
switch (GetFormat(pixel))
{
case D3DFMT_DXT1: rowPitch = (1 << logWidth) * 2; break;
case D3DFMT_DXT2:
case D3DFMT_DXT4: rowPitch = (1 << logWidth) * 4; break;
default: rowPitch = (1 << logWidth) * texelSize / 8; break;
}
slicePitch = (1 << (logWidth + logHeight)) * texelSize / 8;
*outFormat = format;
*outSize = pixel->Size;
}
else
{
DWORD textureHeight = ((size & D3DSIZE_HEIGHT_MASK) >> D3DSIZE_HEIGHT_SHIFT) + 1;
rowPitch = PitchFromSize(size);
slicePitch = rowPitch * textureHeight;
*outFormat = pixel->Format;
*outSize = pixel->Size;
}
*outData = data;
*outRowPitch = rowPitch;
*outSlicePitch = slicePitch;
return;
}
static void WINAPI LockSurface(
D3DPixelContainer *pixel,
D3DCUBEMAP_FACES face,
UINT level,
DWORD flags,
BYTE **data,
DWORD *rowPitch,
DWORD *slicePitch)
{
if (!(flags & D3DLOCK_NOOVERWRITE))
{
BlockOnResource(pixel);
}
DWORD format, size;
FindSurfaceWithinTexture(pixel, face, level, data, rowPitch, slicePitch, &format, &size);
if (flags & D3DLOCK_TILED)
{
/* Target Xbox tiled framebuffer mapping. This is an address-space
* conversion, not an aliasing/lifetime trick. */
*data = (BYTE *)(((DWORD)*data & ~0xf0000000UL) | 0xf0000000UL);
}
return;
}
void WINAPI Lock2DSurface(
D3DPixelContainer *pixel,
D3DCUBEMAP_FACES face,
UINT level,
D3DLOCKED_RECT *locked,
const RECT *rect,
DWORD flags)
{
DWORD rowPitch, slicePitch;
BYTE *data;
LockSurface(pixel, face, level, flags, &data, &rowPitch, &slicePitch);
if (rect)
{
DWORD texelSize = GetBitsPerPixel(pixel);
data += rect->top * rowPitch + rect->left * texelSize / 8;
}
locked->Pitch = rowPitch;
locked->pBits = data;
return;
}
void WINAPI Lock3DSurface(
D3DPixelContainer *pixel,
UINT level,
D3DLOCKED_BOX *locked,
const D3DBOX *box,
DWORD flags)
{
DWORD rowPitch, slicePitch;
BYTE *data;
LockSurface(pixel, D3DCUBEMAP_FACE_POSITIVE_X, level, flags, &data, &rowPitch, &slicePitch);
if (box)
{
DWORD texelSize = GetBitsPerPixel(pixel);
data += box->Front * slicePitch + box->Top * rowPitch + box->Left * texelSize / 8;
}
locked->RowPitch = rowPitch;
locked->SlicePitch = slicePitch;
locked->pBits = data;
return;
}
DWORD WINAPI EncodeFormat(
DWORD width,
DWORD height,
DWORD depth,
DWORD levels,
D3DFORMAT d3dFormat,
DWORD pitch,
bool videoMemory,
bool cubeMap,
bool volume,
DWORD *outFormat,
DWORD *outSize)
{
DWORD size = 0;
DWORD texelSize = BitsPerPixelOfD3DFORMAT(d3dFormat);
DWORD logWidth, logHeight, logDepth, sizeWidth, sizeHeight;
if ((g_TextureFormat[d3dFormat] & 1) || IsCompressedD3DFORMAT(d3dFormat))
{
logWidth = Log2(width);
logHeight = Log2(height);
logDepth = Log2(depth);
sizeWidth = 0;
sizeHeight = 0;
DWORD logMin = MinimumTextureSizeOfD3DFORMAT(d3dFormat);
if (levels == 0)
{
levels = max(logWidth, max(logHeight, logDepth)) + 1;
}
DWORD currentLevel;
DWORD currentWidth = logWidth;
DWORD currentHeight = logHeight;
DWORD currentDepth = logDepth;
DWORD logSize;
for (currentLevel = levels; currentLevel; currentLevel--)
{
logSize = max(currentWidth, logMin) + max(currentHeight, logMin) + currentDepth;
size += (1 << logSize) * texelSize / 8;
if (currentWidth > 0) currentWidth--;
if (currentHeight > 0) currentHeight--;
if (currentDepth > 0) currentDepth--;
}
if (cubeMap)
{
size = (size + D3DTEXTURE_CUBEFACE_ALIGNMENT - 1) & ~(D3DTEXTURE_CUBEFACE_ALIGNMENT - 1);
size *= 6;
}
}
else
{
logWidth = logHeight = logDepth = 0;
if (levels == 0) levels = 1;
if (pitch == 0) pitch = CalcPitch(width, texelSize);
sizeWidth = width;
sizeHeight = height;
size = pitch * height;
}
*outFormat = (cubeMap ? D3DFORMAT_CUBEMAP : 0)
| (volume ? 3 : 2) << D3DFORMAT_DIMENSION_SHIFT
| d3dFormat << D3DFORMAT_FORMAT_SHIFT
| levels << D3DFORMAT_MIPMAP_SHIFT
| logWidth << D3DFORMAT_USIZE_SHIFT
| logHeight << D3DFORMAT_VSIZE_SHIFT
| logDepth << D3DFORMAT_PSIZE_SHIFT
| (videoMemory ? D3DFORMAT_DMACHANNEL_B : D3DFORMAT_DMACHANNEL_A)
| D3DFORMAT_BORDERSOURCE_COLOR;
if (sizeWidth)
{
*outSize = (sizeWidth - 1)
| (sizeHeight - 1) << D3DSIZE_HEIGHT_SHIFT
| ((pitch / D3DTEXTURE_PITCH_ALIGNMENT) - 1) << D3DSIZE_PITCH_SHIFT;
}
else
{
*outSize = 0;
}
return size;
}
}
}