Refactor getting host D3DFORMAT, use it for COLORSIGN, and add signed-to-unsigned mapping
This commit is contained in:
parent
734eeff548
commit
f4ba149c0d
|
@ -253,14 +253,23 @@ static bool alphakill[4] = ALPHAKILL;
|
|||
|
||||
static const float4 WarningColor = float4(0, 1, 1, 1); // Returned when unhandled scenario is encountered
|
||||
|
||||
#define unsigned_to_signed(x) (((x) * 2) - 1) // Shifts range from [0..1] to [-1..1] (just like s_bx2)
|
||||
#define signed_to_unsigned(x) (((x) + 1) / 2) // Shifts range from [-1..1] to [0..1]
|
||||
|
||||
float4 PerformColorSign(const float4 ColorSign, float4 t)
|
||||
{
|
||||
// Per color channel, optionally convert the value range into two's complement signed values (from (0, +1) to (-1, +1), using s_bx2):
|
||||
// This is often used for bumpmaps
|
||||
if (ColorSign.r > 0) t.r = s_bx2(t.r);
|
||||
if (ColorSign.g > 0) t.g = s_bx2(t.g);
|
||||
if (ColorSign.b > 0) t.b = s_bx2(t.b);
|
||||
if (ColorSign.a > 0) t.a = s_bx2(t.a);
|
||||
// Per color channel, based on the ColorSign setting :
|
||||
// either keep the value range as-is (when ColorSign is zero)
|
||||
// or convert from [0..1] to [-1..+1] (when ColorSign is more than zero, often used for bumpmaps),
|
||||
// or convert from [-1..1] to [0..1] (when ColorSign is less than zero):
|
||||
if (ColorSign.r > 0) t.r = unsigned_to_signed(t.r);
|
||||
if (ColorSign.g > 0) t.g = unsigned_to_signed(t.g);
|
||||
if (ColorSign.b > 0) t.b = unsigned_to_signed(t.b);
|
||||
if (ColorSign.a > 0) t.a = unsigned_to_signed(t.a);
|
||||
if (ColorSign.r < 0) t.r = signed_to_unsigned(t.r);
|
||||
if (ColorSign.g < 0) t.g = signed_to_unsigned(t.g);
|
||||
if (ColorSign.b < 0) t.b = signed_to_unsigned(t.b);
|
||||
if (ColorSign.a < 0) t.a = signed_to_unsigned(t.a);
|
||||
// TODO : Instead of the above, create a mirror texture with a host format that has identical component layout, but with all components signed.
|
||||
// Then, in here, when any component has to be read as signed, sample the signed texture (ouch : with what dimension and coordinate?!)
|
||||
// and replace the components that we read from the unsigned texture, but which have to be signed, with the signed components read from the signed mirror texture.
|
||||
|
|
|
@ -184,6 +184,7 @@ static xbox::PVOID g_pXbox_Palette_Data[xbox::X_D3DTS_STAGECOU
|
|||
static unsigned g_Xbox_Palette_Size[xbox::X_D3DTS_STAGECOUNT] = { 0 }; // cached palette size
|
||||
|
||||
|
||||
D3DFORMAT g_HostTextureFormats[xbox::X_D3DTS_STAGECOUNT]; // Updated by CxbxUpdateHostTextures(), read by CxbxCalcColorSign
|
||||
xbox::X_D3DBaseTexture *g_pXbox_SetTexture[xbox::X_D3DTS_STAGECOUNT] = {0,0,0,0}; // Set by our D3DDevice_SetTexture and D3DDevice_SwitchTexture patches
|
||||
static xbox::X_D3DBaseTexture CxbxActiveTextureCopies[xbox::X_D3DTS_STAGECOUNT] = {}; // Set by D3DDevice_SwitchTexture. Cached active texture
|
||||
|
||||
|
@ -905,8 +906,13 @@ void *GetDataFromXboxResource(xbox::X_D3DResource *pXboxResource)
|
|||
return (uint8_t*)pData;
|
||||
}
|
||||
|
||||
DWORD D3DUSAGE_INVALID = -1;
|
||||
|
||||
typedef struct _resource_info_t {
|
||||
|
||||
ComPtr<IDirect3DResource> pHostResource;
|
||||
D3DFORMAT HostFormat = D3DFMT_UNKNOWN;
|
||||
DWORD HostUsage = D3DUSAGE_INVALID;
|
||||
DWORD dwXboxResourceType = 0;
|
||||
void* pXboxData = xbox::zeroptr;
|
||||
size_t szXboxDataSize = 0;
|
||||
|
@ -1149,6 +1155,42 @@ void SetHostResource(xbox::X_D3DResource* pXboxResource, IDirect3DResource* pHos
|
|||
resourceInfo.lastUpdate = std::chrono::steady_clock::now();
|
||||
resourceInfo.nextHashTime = resourceInfo.lastUpdate + resourceInfo.hashLifeTime;
|
||||
resourceInfo.forceRehash = false;
|
||||
|
||||
HRESULT hRet = STATUS_INVALID_PARAMETER; // Default to an error condition, so we can use D3D_OK to check for success
|
||||
D3DSURFACE_DESC surfaceDesc;
|
||||
D3DVOLUME_DESC volumeDesc;
|
||||
UINT Level = 0; // TODO : When should Level every be something other than zero, and if so : what other value?
|
||||
switch (resourceInfo.dwXboxResourceType) {// TODO : Better check pHostResource class type
|
||||
case xbox::X_D3DRTYPE_SURFACE:
|
||||
hRet = ((IDirect3DSurface*)pHostResource)->GetDesc(&surfaceDesc);
|
||||
break;
|
||||
case xbox::X_D3DRTYPE_TEXTURE:
|
||||
hRet = ((IDirect3DTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc);
|
||||
break;
|
||||
case xbox::X_D3DRTYPE_VOLUMETEXTURE: {
|
||||
hRet = ((IDirect3DVolumeTexture*)pHostResource)->GetLevelDesc(Level, &volumeDesc);
|
||||
break; }
|
||||
case xbox::X_D3DRTYPE_CUBETEXTURE:
|
||||
hRet = ((IDirect3DCubeTexture*)pHostResource)->GetLevelDesc(Level, &surfaceDesc);
|
||||
break;
|
||||
}
|
||||
|
||||
D3DFORMAT hostFormat = D3DFMT_UNKNOWN;
|
||||
DWORD hostUsage = D3DUSAGE_INVALID;
|
||||
|
||||
if (SUCCEEDED(hRet)) {
|
||||
if (resourceInfo.dwXboxResourceType == xbox::X_D3DRTYPE_VOLUMETEXTURE) {
|
||||
hostFormat = volumeDesc.Format;
|
||||
hostUsage = volumeDesc.Usage;
|
||||
}
|
||||
else {
|
||||
hostFormat = surfaceDesc.Format;
|
||||
hostUsage = surfaceDesc.Usage;
|
||||
}
|
||||
}
|
||||
|
||||
resourceInfo.HostFormat = hostFormat;
|
||||
resourceInfo.HostUsage = hostUsage;
|
||||
}
|
||||
|
||||
IDirect3DSurface *GetHostSurface(xbox::X_D3DResource *pXboxResource, DWORD D3DUsage = 0)
|
||||
|
@ -2280,30 +2322,20 @@ static void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD
|
|||
auto& ResourceCache = GetResourceCache(key);
|
||||
auto it = ResourceCache.find(key);
|
||||
if (it != ResourceCache.end()) {
|
||||
// TODO : Should this check be (D3DUsage & D3DUSAGE_RENDERTARGET) instead?
|
||||
if (D3DUsage == D3DUSAGE_RENDERTARGET && IsResourceAPixelContainer(pResource) && EmuXBFormatIsRenderTarget(GetXboxPixelContainerFormat((xbox::X_D3DPixelContainer*)pResource))) {
|
||||
// Render targets have special behavior: We can't trash them on guest modification
|
||||
// this fixes an issue where CubeMaps were broken because the surface Set in GetCubeMapSurface
|
||||
// would be overwritten by the surface created in SetRenderTarget
|
||||
// However, if a non-rendertarget surface is used here, we'll need to recreate it as a render target!
|
||||
auto hostResource = it->second.pHostResource.Get();
|
||||
auto xboxSurface = (xbox::X_D3DSurface*)pResource;
|
||||
auto xboxTexture = (xbox::X_D3DTexture*)pResource;
|
||||
auto xboxResourceType = GetXboxD3DResourceType(pResource);
|
||||
|
||||
// Determine if the associated host resource is a render target already, if so, do nothing
|
||||
HRESULT hRet = STATUS_INVALID_PARAMETER; // Default to an error condition, so we can use D3D_OK to check for success
|
||||
D3DSURFACE_DESC surfaceDesc;
|
||||
if (xboxResourceType == xbox::X_D3DRTYPE_SURFACE) {
|
||||
hRet = ((IDirect3DSurface*)hostResource)->GetDesc(&surfaceDesc);
|
||||
} else if (xboxResourceType == xbox::X_D3DRTYPE_TEXTURE) {
|
||||
hRet = ((IDirect3DTexture*)hostResource)->GetLevelDesc(0, &surfaceDesc);
|
||||
}
|
||||
auto hostResource = it->second.pHostResource;
|
||||
assert(xboxResourceType == GetXboxD3DResourceType(pResource));
|
||||
|
||||
// Only continue checking if we were able to get the surface desc, if it failed, we fall-through
|
||||
// to previous resource management behavior
|
||||
if (SUCCEEDED(hRet)) {
|
||||
if (it->second.HostUsage != D3DUSAGE_INVALID) {
|
||||
// If this resource is already created as a render target on the host, simply return
|
||||
if (surfaceDesc.Usage & D3DUSAGE_RENDERTARGET) {
|
||||
if (it->second.HostUsage & D3DUSAGE_RENDERTARGET) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2311,6 +2343,8 @@ static void EmuVerifyResourceIsRegistered(xbox::X_D3DResource *pResource, DWORD
|
|||
// We need to re-create it as a render target
|
||||
switch (xboxResourceType) {
|
||||
case xbox::X_D3DRTYPE_SURFACE: {
|
||||
auto xboxSurface = (xbox::X_D3DSurface*)pResource;
|
||||
|
||||
// Free the host surface
|
||||
FreeHostResource(key);
|
||||
|
||||
|
@ -7301,7 +7335,6 @@ void CxbxUpdateHostTextures()
|
|||
auto pXboxBaseTexture = g_pXbox_SetTexture[stage];
|
||||
IDirect3DBaseTexture* pHostBaseTexture = nullptr;
|
||||
bool bNeedRelease = false;
|
||||
|
||||
if (pXboxBaseTexture != xbox::zeroptr) {
|
||||
DWORD XboxResourceType = GetXboxCommonResourceType(pXboxBaseTexture);
|
||||
switch (XboxResourceType) {
|
||||
|
@ -7320,6 +7353,15 @@ void CxbxUpdateHostTextures()
|
|||
LOG_TEST_CASE("ActiveTexture set to an unhandled resource type!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read HostFormat from GetResourceCache :
|
||||
// TODO : Optimize this, as we're doing the lookup twice (once in GetHostBaseTexture, once here)
|
||||
auto key = GetHostResourceKey(pXboxBaseTexture, stage);
|
||||
auto& ResourceCache = GetResourceCache(key);
|
||||
auto it = ResourceCache.find(key);
|
||||
if (it != ResourceCache.end()) {
|
||||
g_HostTextureFormats[stage] = it->second.HostFormat;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hRet = g_pD3DDevice->SetTexture(stage, pHostBaseTexture);
|
||||
|
|
|
@ -59,6 +59,8 @@ extern xbox::dword_xt g_Xbox_VertexShader_Handle;
|
|||
|
||||
extern xbox::X_PixelShader *g_pXbox_PixelShader;
|
||||
|
||||
extern D3DFORMAT g_HostTextureFormats[xbox::X_D3DTS_STAGECOUNT];
|
||||
|
||||
extern xbox::X_D3DBaseTexture *g_pXbox_SetTexture[xbox::X_D3DTS_STAGECOUNT];
|
||||
|
||||
namespace xbox {
|
||||
|
|
|
@ -4,17 +4,23 @@
|
|||
|
||||
static const float4 WarningColor = float4(0, 1, 1, 1); // Returned when unhandled scenario is encountered
|
||||
|
||||
#define s_bx2(x) (( 2 * max(0, x)) - 1) // PS_INPUTMAPPING_EXPAND_NORMAL= 0x40L, // invalid for final combiner // Shifts range from [0..1] to [-1..1]
|
||||
#define s_bias(x) (max(0, x) - 0.5) // PS_INPUTMAPPING_HALFBIAS_NORMAL= 0x80L, // invalid for final combiner // Clamps negative x to 0 and then subtracts 0.5
|
||||
#define unsigned_to_signed(x) (((x) * 2) - 1) // Shifts range from [0..1] to [-1..1] (just like s_bx2)
|
||||
#define signed_to_unsigned(x) (((x) + 1) / 2) // Shifts range from [-1..1] to [0..1]
|
||||
|
||||
float4 PerformColorSign(const float4 ColorSign, float4 t)
|
||||
{
|
||||
// Per color channel, optionally convert the value range into two's complement signed values (from (0, +1) to (-1, +1), using s_bx2):
|
||||
// This is often used for bumpmaps
|
||||
if (ColorSign.r > 0) t.r = s_bx2(t.r);
|
||||
if (ColorSign.g > 0) t.g = s_bx2(t.g);
|
||||
if (ColorSign.b > 0) t.b = s_bx2(t.b);
|
||||
if (ColorSign.a > 0) t.a = s_bx2(t.a);
|
||||
// Per color channel, based on the ColorSign setting :
|
||||
// either keep the value range as-is (when ColorSign is zero)
|
||||
// or convert from [0..1] to [-1..+1] (when ColorSign is more than zero, often used for bumpmaps),
|
||||
// or convert from [-1..1] to [0..1] (when ColorSign is less than zero):
|
||||
if (ColorSign.r > 0) t.r = unsigned_to_signed(t.r);
|
||||
if (ColorSign.g > 0) t.g = unsigned_to_signed(t.g);
|
||||
if (ColorSign.b > 0) t.b = unsigned_to_signed(t.b);
|
||||
if (ColorSign.a > 0) t.a = unsigned_to_signed(t.a);
|
||||
if (ColorSign.r < 0) t.r = signed_to_unsigned(t.r);
|
||||
if (ColorSign.g < 0) t.g = signed_to_unsigned(t.g);
|
||||
if (ColorSign.b < 0) t.b = signed_to_unsigned(t.b);
|
||||
if (ColorSign.a < 0) t.a = signed_to_unsigned(t.a);
|
||||
// TODO : Instead of the above, create a mirror texture with a host format that has identical component layout, but with all components signed.
|
||||
// Then, in here, when any component has to be read as signed, sample the signed texture (ouch : with what dimension and coordinate?!)
|
||||
// and replace the components that we read from the unsigned texture, but which have to be signed, with the signed components read from the signed mirror texture.
|
||||
|
|
|
@ -968,28 +968,54 @@ float AsFloat(uint32_t value)
|
|||
return *(float*)&v;
|
||||
}
|
||||
|
||||
// This mimicks behaviour of XDK LazySetShaderStageProgram, which we bypass due to our drawing patches without trampolines.
|
||||
DWORD CxbxGetColorSign(int stage_nr)
|
||||
// Determines the Cxbx ColorSign requirement, as handled in the HLSL shaders by PerformColorSign()
|
||||
float CxbxComponentColorSignFromXboxAndHost(bool XboxMarksComponentSigned, bool HostComponentIsSigned)
|
||||
{
|
||||
// When bump environment mapping is enabled
|
||||
if (XboxTextureStates.Get(stage_nr, xbox::X_D3DTSS_COLOROP) >= xbox::X_D3DTOP_BUMPENVMAP)
|
||||
// Always mark the blue (alias for U) and green (alias for V) color channels as signed :
|
||||
return xbox::X_D3DTSIGN_GSIGNED | xbox::X_D3DTSIGN_BSIGNED;
|
||||
// Equal "signedness" between Xbox and host implies we must not convert the component scale :
|
||||
if (XboxMarksComponentSigned == HostComponentIsSigned)
|
||||
return 0.0f;
|
||||
|
||||
// Xbox wants the components to be signed (even though host has them unsigned)
|
||||
if (XboxMarksComponentSigned)
|
||||
return 1.0f; // Mark the component for scaling from unsigned_to_signed
|
||||
|
||||
// Xbox doesn't want signed values, but host has them signed :
|
||||
return -1.0f; // Mark the component for scaling from signed_to_unsigned
|
||||
}
|
||||
|
||||
D3DXCOLOR CxbxCalcColorSign(int stage_nr)
|
||||
{
|
||||
// Without overrides, just use what the running executable put in COLORSIGN :
|
||||
DWORD XboxColorSign = XboxTextureStates.Get(stage_nr, xbox::X_D3DTSS_COLORSIGN);
|
||||
|
||||
{ // This mimicks behaviour of XDK LazySetShaderStageProgram, which we bypass due to our drawing patches without trampolines.
|
||||
// When bump environment mapping is enabled
|
||||
if (XboxTextureStates.Get(stage_nr, xbox::X_D3DTSS_COLOROP) >= xbox::X_D3DTOP_BUMPENVMAP)
|
||||
// Always mark the blue (alias for U) and green (alias for V) color channels as signed :
|
||||
XboxColorSign |= xbox::X_D3DTSIGN_GSIGNED | xbox::X_D3DTSIGN_BSIGNED;
|
||||
}
|
||||
|
||||
#if 0 // When this block is enabled, XDK samples BumpEarth and BumpLens turn red-ish, so keep this off for now...
|
||||
// TODO : Perhaps turn COLORSIGN off when the active host texture is already signed (like D3DFMT_L6V5U5 if supported)
|
||||
// and enable COLORSIGN when the active host texture was converted from signed to unsigned?
|
||||
|
||||
// Check if the pixel shader specifies bump mapping for this stage (TODO : How to handle this with the fixed function shader?)
|
||||
DWORD PSTextureModes = XboxRenderStates.GetXboxRenderState(xbox::X_D3DRS_PSTEXTUREMODES);
|
||||
PS_TEXTUREMODES StageTextureMode = (PS_TEXTUREMODES)((PSTextureModes >> (stage_nr * 5)) & PS_TEXTUREMODES_MASK);
|
||||
if (StageTextureMode == PS_TEXTUREMODES_BUMPENVMAP || StageTextureMode == PS_TEXTUREMODES_BUMPENVMAP_LUM)
|
||||
return xbox::X_D3DTSIGN_GSIGNED | xbox::X_D3DTSIGN_BSIGNED;
|
||||
XboxColorSign |= xbox::X_D3DTSIGN_GSIGNED | xbox::X_D3DTSIGN_BSIGNED;
|
||||
|
||||
#endif
|
||||
// Host D3DFMT's with one or more signed components : D3DFMT_V8U8, D3DFMT_Q8W8V8U8, D3DFMT_V16U16, D3DFMT_Q16W16V16U16, D3DFMT_CxV8U8
|
||||
D3DFORMAT HostTextureFormat = g_HostTextureFormats[stage_nr];
|
||||
bool HostTextureFormatIsSignedForA = (HostTextureFormat == D3DFMT_Q8W8V8U8); // No need to check for unused formats : D3DFMT_Q16W16V16U16, D3DFMT_CxV8U8, D3DFMT_A2W10V10U10
|
||||
bool HostTextureFormatIsSignedForR = (HostTextureFormat == D3DFMT_V8U8) || (HostTextureFormat == D3DFMT_V16U16) || (HostTextureFormat == D3DFMT_L6V5U5) || (HostTextureFormat == D3DFMT_X8L8V8U8) || HostTextureFormatIsSignedForA;
|
||||
bool HostTextureFormatIsSignedForG = HostTextureFormatIsSignedForR;
|
||||
bool HostTextureFormatIsSignedForB = HostTextureFormatIsSignedForA;
|
||||
|
||||
// Without overrides, just return what the running executable put in COLORSIGN :
|
||||
return XboxTextureStates.Get(stage_nr, xbox::X_D3DTSS_COLORSIGN);
|
||||
D3DXCOLOR CxbxColorSign;
|
||||
CxbxColorSign.r = CxbxComponentColorSignFromXboxAndHost(XboxColorSign & xbox::X_D3DTSIGN_RSIGNED, HostTextureFormatIsSignedForR); // Maps to COLORSIGN.r
|
||||
CxbxColorSign.g = CxbxComponentColorSignFromXboxAndHost(XboxColorSign & xbox::X_D3DTSIGN_GSIGNED, HostTextureFormatIsSignedForG); // Maps to COLORSIGN.g
|
||||
CxbxColorSign.b = CxbxComponentColorSignFromXboxAndHost(XboxColorSign & xbox::X_D3DTSIGN_BSIGNED, HostTextureFormatIsSignedForB); // Maps to COLORSIGN.b
|
||||
CxbxColorSign.a = CxbxComponentColorSignFromXboxAndHost(XboxColorSign & xbox::X_D3DTSIGN_ASIGNED, HostTextureFormatIsSignedForA); // Maps to COLORSIGN.a
|
||||
return CxbxColorSign;
|
||||
}
|
||||
|
||||
// Set constant state for the fixed function pixel shader
|
||||
|
@ -1010,11 +1036,11 @@ void UpdateFixedFunctionPixelShaderState()
|
|||
for (int i = 0; i < xbox::X_D3DTS_STAGECOUNT; i++) {
|
||||
auto stage = &ffPsState.stages[i];
|
||||
stage->COLORKEYOP = (float)XboxTextureStates.Get(i, xbox::X_D3DTSS_COLORKEYOP);
|
||||
DWORD colorsign = CxbxGetColorSign(i);
|
||||
stage->COLORSIGN.x = (colorsign & xbox::X_D3DTSIGN_RSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN.r
|
||||
stage->COLORSIGN.y = (colorsign & xbox::X_D3DTSIGN_GSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN.g
|
||||
stage->COLORSIGN.z = (colorsign & xbox::X_D3DTSIGN_BSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN.b
|
||||
stage->COLORSIGN.w = (colorsign & xbox::X_D3DTSIGN_ASIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN.a
|
||||
auto CxbxColorSign = CxbxCalcColorSign(i);
|
||||
stage->COLORSIGN.x = CxbxColorSign.r;
|
||||
stage->COLORSIGN.y = CxbxColorSign.g;
|
||||
stage->COLORSIGN.z = CxbxColorSign.b;
|
||||
stage->COLORSIGN.w = CxbxColorSign.a;
|
||||
stage->ALPHAKILL = (float)XboxTextureStates.Get(i, xbox::X_D3DTSS_ALPHAKILL);
|
||||
stage->BUMPENVMAT00 = AsFloat(XboxTextureStates.Get(i, xbox::X_D3DTSS_BUMPENVMAT00));
|
||||
stage->BUMPENVMAT01 = AsFloat(XboxTextureStates.Get(i, xbox::X_D3DTSS_BUMPENVMAT01));
|
||||
|
@ -1136,11 +1162,7 @@ void DxbxUpdateActivePixelShader() // NOPATCH
|
|||
|
||||
// Texture color sign
|
||||
for (int stage_nr = 0; stage_nr < xbox::X_D3DTS_STAGECOUNT; stage_nr++) {
|
||||
auto colorsign = CxbxGetColorSign(stage_nr);
|
||||
fColor[PSH_XBOX_CONSTANT_COLORSIGN + stage_nr].r = (colorsign & xbox::X_D3DTSIGN_RSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN[stage].r (treated as bool, true when > 0.0)
|
||||
fColor[PSH_XBOX_CONSTANT_COLORSIGN + stage_nr].g = (colorsign & xbox::X_D3DTSIGN_GSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN[stage].g
|
||||
fColor[PSH_XBOX_CONSTANT_COLORSIGN + stage_nr].b = (colorsign & xbox::X_D3DTSIGN_BSIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN[stage].b
|
||||
fColor[PSH_XBOX_CONSTANT_COLORSIGN + stage_nr].a = (colorsign & xbox::X_D3DTSIGN_ASIGNED) ? 1.0f : 0.0f; // Maps to COLORSIGN[stage].a
|
||||
fColor[PSH_XBOX_CONSTANT_COLORSIGN + stage_nr] = CxbxCalcColorSign(stage_nr);
|
||||
}
|
||||
|
||||
#if 0 // New, doesn't work yet
|
||||
|
|
Loading…
Reference in New Issue