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

678 lines
20 KiB
C++

/* State programming adapted from RXDK-Libs, 2026 Team Resurgent.
* SPDX-License-Identifier: GPL-3.0-or-later
* Older target method numbers/state layout are proved by its disassembly.
*/
#include "push_internal.h"
#include "pixeljar.h"
#include "state_internal.h"
#include "math_internal.h"
#include "vshader_internal.h"
#include "push_float_internal.h"
#pragma code_seg("D3D")
namespace D3D
{
DWORD *__fastcall CommonSetControl0(
CDevice *device,
DWORD *push)
{
DWORD control = 0x00100001;
if (D3D__RenderState[D3DRS_YUVENABLE]) control |= 0x10000000;
if (D3D__RenderState[D3DRS_ZENABLE] == D3DZB_USEW) control |= 0x00010000;
if (device->m_pZBuffer)
{
D3DFORMAT format = PixelJar::GetFormat(device->m_pZBuffer);
if (format == D3DFMT_F16 || format == D3DFMT_F24S8 ||
format == D3DFMT_LIN_F16 || format == D3DFMT_LIN_F24S8)
{
control |= 0x1000;
}
}
Push1(push, 0x290, control);
return push + 2;
}
DWORD *__fastcall CommonSetOccludeZStencilEn(
CDevice *device,
DWORD *push)
{
DWORD control = 0;
if (D3D__RenderState[D3DRS_STENCILCULLENABLE])
{
control |= 2;
}
if (D3D__RenderState[D3DRS_OCCLUSIONCULLENABLE] &&
(!D3D__RenderState[D3DRS_STENCILENABLE] ||
D3D__RenderState[D3DRS_STENCILFAIL] == D3DSTENCILOP_KEEP))
{
control |= 1;
}
Push1(push, 0x1d84, control);
return push + 2;
}
void __fastcall CommonSetAntiAliasingControl(
CDevice *device)
{
CommonSetPassthroughProgram(device);
DWORD *push = device->StartPush();
push = CommonSetViewport(device, push);
Push1(push, 0x1d7c,
(D3D__RenderState[D3DRS_MULTISAMPLEANTIALIAS] & 0xf) |
(D3D__RenderState[D3DRS_MULTISAMPLEMASK] << 16));
device->EndPush(push + 2);
return;
}
void __fastcall CommonSetDebugRegisters(
void)
{
CDevice *device = g_pDevice;
device->m_Miniport.m_DebugRegister[5] &= ~8UL;
if (D3D__RenderState[D3DRS_DONOTCULLUNCOMPRESSED])
{
device->m_Miniport.m_DebugRegister[5] |= 8;
}
device->m_Miniport.m_DebugRegister[6] &= ~0x18100000UL;
if (D3D__RenderState[D3DRS_ROPZCMPALWAYSREAD])
{
device->m_Miniport.m_DebugRegister[6] |= 0x100000;
}
if (D3D__RenderState[D3DRS_ROPZREAD])
{
device->m_Miniport.m_DebugRegister[6] |= 0x08000000;
}
DWORD *push = device->StartPush();
Push1(push, NV097_WAIT_FOR_IDLE, 0);
Push2(push + 2, 0x1d8c, 0x400094, device->m_Miniport.m_DebugRegister[5]);
Push1(push + 5, NV097_NO_OPERATION, 0x320);
Push2(push + 7, 0x1d8c, 0x400b80, device->m_Miniport.m_DebugRegister[6]);
Push1(push + 10, NV097_NO_OPERATION, 0x320);
device->EndPush(push + 12);
return;
}
}
using namespace D3D;
void __fastcall D3D::CommonSetSurfaceFormat(
CDevice *device)
{
float xScale = 1.0f;
float yScale = 1.0f;
DWORD antiAlias = 0;
D3DSurface *surface = device->m_pRenderTarget;
if (surface == &device->m_FrameBufferSurfaces[0])
{
DWORD sampling = D3D__RenderState[D3DRS_MULTISAMPLETYPE];
if (sampling & 0x3000)
{
xScale = (float)((sampling >> 4) & 15);
yScale = (float)(sampling & 15);
if (sampling & 0x1000)
{
xScale *= 0.5f;
antiAlias = 0x1000;
if (yScale > 1.0f)
{
yScale *= 0.5f;
antiAlias = 0x2000;
}
}
}
}
float scale = min(xScale, yScale);
device->m_SuperSampleScaleX = xScale;
device->m_SuperSampleScaleY = yScale;
if (scale != device->m_SuperSampleScale)
{
device->m_SuperSampleScale = scale;
device->m_SuperSampleLODBias = g_LODBias2x[Round(scale * 2.0f) - 2];
device->m_DirtyFlags |= 1;
D3DDevice_SetRenderStateNotInline(D3DRS_LINEWIDTH,
D3D__RenderState[D3DRS_LINEWIDTH]);
}
DWORD *push = device->StartPush();
Push1(push, 0x208, PixelJar::GetSurfaceFormat(surface, device->m_pZBuffer) | antiAlias);
device->EndPush(push + 2);
return;
}
void WINAPI D3DDevice_SetRenderState_MultiSampleType(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_MULTISAMPLETYPE] = value;
D3DDevice_SetRenderTarget(device->m_pRenderTarget, device->m_pZBuffer);
return;
}
void WINAPI D3DDevice_SetRenderState_PSTextureModes(
DWORD value)
{
CDevice *device = g_pDevice;
device->m_PSShaderStageProgram = value;
device->m_DirtyFlags |= 0x400;
D3D__RenderState[D3DRS_PSTEXTUREMODES] = value;
return;
}
void __fastcall D3DDevice_SetRenderState_Deferred(
D3DRENDERSTATETYPE state,
DWORD value)
{
g_Device.m_DirtyFlags |= g_DirtyFromRenderState[state - D3DRS_SIMPLE_MAX];
D3D__RenderState[state] = value;
return;
}
void __fastcall D3DDevice_SetTextureState_Deferred(
DWORD stage,
D3DTEXTURESTAGESTATETYPE state,
DWORD value)
{
g_Device.m_DirtyFlags |= g_DirtyFromTextureState[state];
D3D__TextureState[stage][state] = value;
return;
}
void WINAPI D3DDevice_SetRenderStateNotInline(
D3DRENDERSTATETYPE state,
DWORD value)
{
if (state < D3DRS_SIMPLE_MAX)
{
D3DDevice_SetRenderState_Simple(D3DSIMPLERENDERSTATEENCODE[state], value);
D3D__RenderState[state] = value;
}
else if (state < D3DRS_DEFERRED_MAX)
{
D3DDevice_SetRenderState_Deferred(state, value);
}
else
{
g_ComplexRenderStateFunctionTable[state - D3DRS_DEFERRED_MAX](value);
}
return;
}
void WINAPI D3DDevice_SetRenderState_EdgeAntiAlias(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push2(push, NV097_SET_LINE_SMOOTH_ENABLE, value, value);
device->EndPush(push + 3);
D3D__RenderState[D3DRS_EDGEANTIALIAS] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_ShadowFunc(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, NV097_SET_SHADOW_DEPTH_FUNC, value - D3DCMP_NEVER);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_SHADOWFUNC] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_FogColor(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, NV097_SET_FOG_COLOR, SwapRgb(value));
device->EndPush(push + 2);
D3D__RenderState[D3DRS_FOGCOLOR] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_CullMode(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
if (value == D3DCULL_NONE)
{
Push1(push, NV097_SET_CULL_FACE_ENABLE, FALSE);
device->EndPush(push + 2);
}
else
{
Push1(push, NV097_SET_CULL_FACE_ENABLE, TRUE);
DWORD cullFace = value == D3D__RenderState[D3DRS_FRONTFACE] ?
NV097_SET_CULL_FACE_V_FRONT : NV097_SET_CULL_FACE_V_BACK;
Push1(push + 2, NV097_SET_CULL_FACE, cullFace);
device->EndPush(push + 4);
}
D3D__RenderState[D3DRS_CULLMODE] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_FrontFace(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, NV097_SET_FRONT_FACE, value);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_FRONTFACE] = value;
D3DDevice_SetRenderState_CullMode(D3D__RenderState[D3DRS_CULLMODE]);
return;
}
void WINAPI D3DDevice_SetRenderState_NormalizeNormals(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, NV097_SET_NORMALIZATION_ENABLE, value);
device->EndPush(push + 2);
device->m_DirtyFlags |= 2;
D3D__RenderState[D3DRS_NORMALIZENORMALS] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_TextureFactor(
DWORD value)
{
CDevice *device = g_pDevice;
if (!device->m_pPixelShader)
{
DWORD *push = device->StartPush();
PushCount(push++, NV097_SET_COMBINER_FACTOR0, 16);
for (DWORD i = 0; i < 16; i++)
{
*push++ = value;
}
device->EndPush(push);
}
D3D__RenderState[D3DRS_TEXTUREFACTOR] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_Dxt1NoiseEnable(
DWORD value)
{
CDevice *device = g_pDevice;
BOOL noiseEnable = FALSE;
if (PixelJar::GetBitsPerPixel(device->m_pRenderTarget) == 32)
{
noiseEnable = value;
}
if (noiseEnable != (device->m_StateFlags & 1))
{
device->m_StateFlags ^= 1;
DWORD *push = device->StartPush();
Push1(push, NV097_WAIT_FOR_IDLE, 0);
/* January uses separate semaphore-offset argument and software method. */
Push1(push + 2, 0x1d8c, noiseEnable);
Push1(push + 4, NV097_NO_OPERATION, 0x31c);
device->EndPush(push + 6);
}
D3D__RenderState[D3DRS_DXT1NOISEENABLE] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_YuvEnable(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_YUVENABLE] = value;
DWORD *push = device->StartPush();
push = CommonSetControl0(device, push);
device->EndPush(push);
return;
}
void WINAPI D3DDevice_SetRenderState_OcclusionCullEnable(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_OCCLUSIONCULLENABLE] = value;
DWORD *push = device->StartPush();
push = CommonSetOccludeZStencilEn(device, push);
device->EndPush(push);
return;
}
void WINAPI D3DDevice_SetRenderState_StencilCullEnable(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_STENCILCULLENABLE] = value;
DWORD *push = device->StartPush();
push = CommonSetOccludeZStencilEn(device, push);
device->EndPush(push);
return;
}
void WINAPI D3DDevice_SetRenderState_RopZCmpAlwaysRead(
DWORD value)
{
D3D__RenderState[D3DRS_ROPZCMPALWAYSREAD] = value;
CommonSetDebugRegisters();
return;
}
void WINAPI D3DDevice_SetRenderState_RopZRead(
DWORD value)
{
D3D__RenderState[D3DRS_ROPZREAD] = value;
CommonSetDebugRegisters();
return;
}
void WINAPI D3DDevice_SetRenderState_DoNotCullUncompressed(
DWORD value)
{
D3D__RenderState[D3DRS_DONOTCULLUNCOMPRESSED] = value;
CommonSetDebugRegisters();
return;
}
void WINAPI D3DDevice_SetRenderState_LogicOp(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
if (value == D3DLOGICOP_NONE)
{
Push1(push, 0x17bc, FALSE);
push += 2;
}
else
{
Push2(push, 0x17bc, TRUE, value);
push += 3;
}
device->EndPush(push);
D3D__RenderState[D3DRS_LOGICOP] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_FillMode(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
DWORD back = D3D__RenderState[D3DRS_TWOSIDEDLIGHTING] ?
D3D__RenderState[D3DRS_BACKFILLMODE] : value;
Push2(push, 0x38c, value, back);
device->EndPush(push + 3);
D3D__RenderState[D3DRS_FILLMODE] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_BackFillMode(
DWORD value)
{
D3D__RenderState[D3DRS_BACKFILLMODE] = value;
D3DDevice_SetRenderState_FillMode(D3D__RenderState[D3DRS_FILLMODE]);
return;
}
void WINAPI D3DDevice_SetRenderState_TwoSidedLighting(
DWORD value)
{
CDevice *device = g_pDevice;
device->m_DirtyFlags |= 0x20;
D3D__RenderState[D3DRS_TWOSIDEDLIGHTING] = value;
D3DDevice_SetRenderState_FillMode(D3D__RenderState[D3DRS_FILLMODE]);
return;
}
void WINAPI D3DDevice_SetRenderState_VertexBlend(
DWORD value)
{
CDevice *device = g_pDevice;
device->m_DirtyFlags |= 2;
DWORD *push = device->StartPush();
Push1(push, 0x328, value);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_VERTEXBLEND] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_ZEnable(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, 0x30c, value != D3DZB_FALSE && device->m_pZBuffer != NULL);
device->EndPush(push + 2);
DWORD previous = D3D__RenderState[D3DRS_ZENABLE];
D3D__RenderState[D3DRS_ZENABLE] = value;
if (previous == D3DZB_USEW || value == D3DZB_USEW)
{
UpdateProjectionViewportTransform();
CommonSetPassthroughProgram(device);
DWORD *push = device->StartPush();
push = CommonSetControl0(device, push);
device->EndPush(push);
}
return;
}
void WINAPI D3DDevice_SetRenderState_StencilEnable(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
push = CommonSetOccludeZStencilEn(device, push);
Push1(push, 0x32c, value && device->m_pZBuffer != NULL);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_STENCILENABLE] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_StencilFail(
DWORD value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
push = CommonSetOccludeZStencilEn(device, push);
Push1(push, 0x370, value);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_STENCILFAIL] = value;
return;
}
void WINAPI D3DDevice_SetRenderState_MultiSampleAntiAlias(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_MULTISAMPLEANTIALIAS] = value;
CommonSetAntiAliasingControl(device);
return;
}
void WINAPI D3DDevice_SetRenderState_MultiSampleMask(
DWORD value)
{
CDevice *device = g_pDevice;
D3D__RenderState[D3DRS_MULTISAMPLEMASK] = value;
CommonSetAntiAliasingControl(device);
return;
}
void WINAPI D3DDevice_SetRenderState_LineWidth(
DWORD Value)
{
CDevice *device = g_pDevice;
float width;
memcpy(&width, &Value, sizeof(width));
DWORD scaled = FloatToLong(width * device->m_SuperSampleScale * 8.0f + 0.5f);
if (scaled > 511) { scaled = 511; }
DWORD *push = device->StartPush();
Push1(push, 0x380, scaled);
device->EndPush(push + 2);
D3D__RenderState[D3DRS_LINEWIDTH] = Value;
return;
}
void WINAPI D3DDevice_SetRenderState_ZBias(
DWORD Value)
{
BOOL enabled = Value != 0;
float bias = -(float)Value;
float scale = bias * 0.25f;
DWORD payload;
memcpy(&payload, &scale, sizeof(payload));
D3DDevice_SetRenderStateNotInline(D3DRS_POLYGONOFFSETZSLOPESCALE, payload);
memcpy(&payload, &bias, sizeof(payload));
D3DDevice_SetRenderStateNotInline(D3DRS_POLYGONOFFSETZOFFSET, payload);
D3DDevice_SetRenderStateNotInline(D3DRS_POINTOFFSETENABLE, enabled);
D3DDevice_SetRenderStateNotInline(D3DRS_WIREFRAMEOFFSETENABLE, enabled);
D3DDevice_SetRenderStateNotInline(D3DRS_SOLIDOFFSETENABLE, enabled);
D3D__RenderState[D3DRS_ZBIAS] = Value;
return;
}
void WINAPI D3DDevice_SetTextureState_TexCoordIndex(
DWORD Stage,
DWORD Value)
{
CDevice *device = g_pDevice;
D3D__TextureState[Stage][D3DTSS_TEXCOORDINDEX] = Value;
DWORD needsInverse = FALSE;
DWORD mode;
switch (Value & 0xffff0000)
{
case D3DTSS_TCI_PASSTHRU:
device->m_DirtyFlags |= 0x180;
mode = 0;
break;
case D3DTSS_TCI_CAMERASPACENORMAL:
needsInverse = TRUE;
mode = 0x8511;
break;
case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
needsInverse = TRUE;
mode = 0x8512;
break;
case D3DTSS_TCI_CAMERASPACEPOSITION:
mode = 0x2400;
break;
case D3DTSS_TCI_OBJECT:
mode = 0x2401;
break;
default:
/* Target default, including sphere mapping. */
needsInverse = TRUE;
mode = 0x2402;
break;
}
if (!device->m_TexGenInverseNeeded && needsInverse) { device->m_DirtyFlags |= 2; }
device->m_TexGenInverseNeeded &= ~(1 << Stage);
device->m_TexGenInverseNeeded |= needsInverse << Stage;
DWORD *push = device->StartPush();
PushCount(push, 0x3c0 + Stage * 16, 3);
push[1] = mode;
push[2] = mode;
push[3] = mode;
device->EndPush(push + 4);
device->m_DirtyFlags |= 0x194;
return;
}
void WINAPI D3DDevice_SetTextureState_BumpEnv(
DWORD Stage,
D3DTEXTURESTAGESTATETYPE Type,
DWORD Value)
{
CDevice *device = g_pDevice;
DWORD unit = device->m_pPixelShader ? Stage : Stage + 1;
if (unit & 3)
{
DWORD *push = device->StartPush();
Push1(push, 0x1b28 + unit * 64 + 4 * (Type - D3DTSS_BUMPENVMAT00), Value);
device->EndPush(push + 2);
}
D3D__TextureState[Stage][Type] = Value;
return;
}
void WINAPI D3DDevice_SetTextureState_BorderColor(
DWORD Stage,
DWORD Value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, 0x1b24 + Stage * 64, Value);
device->EndPush(push + 2);
D3D__TextureState[Stage][D3DTSS_BORDERCOLOR] = Value;
return;
}
void WINAPI D3DDevice_SetTextureState_ColorKeyColor(
DWORD Stage,
DWORD Value)
{
CDevice *device = g_pDevice;
DWORD *push = device->StartPush();
Push1(push, 0xae0 + Stage * 4, Value);
device->EndPush(push + 2);
D3D__TextureState[Stage][D3DTSS_COLORKEYCOLOR] = Value;
return;
}
void WINAPI D3DDevice_SetTextureStageStateNotInline(
DWORD Stage,
D3DTEXTURESTAGESTATETYPE Type,
DWORD Value)
{
CDevice *device = g_pDevice;
if (Type < D3DTSS_DEFERRED_MAX)
{
DWORD dirty = g_DirtyFromTextureState[Type];
D3D__TextureState[Stage][Type] = Value;
device->m_DirtyFlags |= dirty;
}
else if (Type == D3DTSS_TEXCOORDINDEX) { D3DDevice_SetTextureState_TexCoordIndex(Stage, Value); }
else if (Type == D3DTSS_BORDERCOLOR) { D3DDevice_SetTextureState_BorderColor(Stage, Value); }
else if (Type == D3DTSS_COLORKEYCOLOR) { D3DDevice_SetTextureState_ColorKeyColor(Stage, Value); }
else if (Type >= D3DTSS_BUMPENVMAT00 && Type <= D3DTSS_BUMPENVLOFFSET)
{ D3DDevice_SetTextureState_BumpEnv(Stage, Type, Value); }
return;
}
namespace D3D
{
DWORD *__fastcall CommonSetTextureBumpEnv(
CDevice *device,
DWORD *push)
{
DWORD stage = device->m_pPixelShader ? 1 : 0;
for (DWORD unit = 1; unit <= 3; unit++)
{
PushCount(push, 0x1b28 + unit * 64, 6);
memcpy(push + 1, &D3D__TextureState[stage][D3DTSS_BUMPENVMAT00], 6 * sizeof(DWORD));
push += 7;
stage++;
}
return push;
}
}
namespace D3D
{
/* January PDB S_LDATA32: KELVIN_BORDER, const float, original value +0.53125.
* Kept as a real constant owner, not an address-based identifier. */
const float KELVIN_BORDER = 0.53125f;
DWORD *__fastcall CommonSetViewport(
CDevice *device,
DWORD *push)
{
float clipNear;
float clipFar;
float xViewport = device->m_Viewport.X * device->m_SuperSampleScaleX + KELVIN_BORDER;
float yViewport = device->m_Viewport.Y * device->m_SuperSampleScaleY + KELVIN_BORDER;
if ((D3D__RenderState[D3DRS_MULTISAMPLETYPE] & 0x1000) &&
D3D__RenderState[D3DRS_MULTISAMPLEANTIALIAS] &&
device->m_pRenderTarget == &device->m_FrameBufferSurfaces[0])
{
xViewport -= 0.5f;
yViewport -= 0.5f;
}
if (device->m_pVertexShader->Flags & (VERTEXSHADER_PASSTHROUGH | VERTEXSHADER_PROGRAM))
{
if (!(device->m_StateFlags & 0x200))
{
float fm11 = device->m_Viewport.Width * device->m_SuperSampleScaleX * 0.5f;
float fm22 = device->m_Viewport.Height * device->m_SuperSampleScaleY * -0.5f;
float fm33 = (device->m_Viewport.MaxZ - device->m_Viewport.MinZ) * device->m_ZScale;
float fm43 = device->m_ZScale * device->m_Viewport.MinZ;
Push4fSafe(push, 0xa20, fm11 + xViewport, -fm22 + yViewport, fm43, 0.0f);
Push4fSafe(push + 5, 0xaf0, fm11, fm22, fm33, 0.0f);
push += 10;
}
clipNear = 0.0f;
clipFar = device->m_ZScale;
}
else
{
Push4fSafe(push, 0xa20, xViewport, yViewport, 0.0f, 0.0f);
push += 5;
clipFar = device->m_ZScale * device->m_Viewport.MaxZ;
clipNear = device->m_ZScale * device->m_Viewport.MinZ;
}
Push2f(push, 0x394, clipNear, clipFar);
return push + 3;
}
}
HRESULT WINAPI D3DDevice_SetTextureState_ParameterCheck(
DWORD stage,
D3DTEXTURESTAGESTATETYPE type,
DWORD value)
{
/* January's retail API reports success; validation exists only in checked
* builds. The entire original return sequence is independently compared. */
return S_OK;
}