Files
2026-08-09 04:23:10 -07:00

572 lines
27 KiB
C++

/*
Do not use render parms in this file directly or they will be included in every single
vertex and fragment program which may come at a significant performance penalty.
For convenience render parms may be used in a #define declared in this file and such
a define may then be used in the actual vertex or fragment program that needs it.
*/
#if defined( XBOX )
#define BRANCH [branch]
#define IFANY [ifAny]
#elif defined( PS3 )
#define BRANCH [branch]
#define IFANY
#else
#define BRANCH
#define IFANY
#endif
static float dot2( float2 a, float2 b ) { return dot( a, b ); }
static float dot3( float3 a, float3 b ) { return dot( a, b ); }
static float dot3( float3 a, float4 b ) { return dot( a, b.xyz ); }
static float dot3( float4 a, float3 b ) { return dot( a.xyz, b ); }
static float dot3( float4 a, float4 b ) { return dot( a.xyz, b.xyz ); }
static float dot4( float4 a, float4 b ) { return dot( a, b ); }
static float dot4( float2 a, float4 b ) { return dot( float4( a, 0, 1 ), b ); }
#ifdef PC_D3D
#define sampler2D Texture2D
#define samplerCUBE TextureCube
#define samplerRECT Texture2D // FIXME: Rect support
#endif
#ifdef GLSL
#define anyEqual( x, y ) any( equal( x, y ) )
#define anyNotEqual( x, y ) any( notEqual( x, y ) )
#define anyNotEqualZero( x ) max( sign( x ), 0.0 )
#define fmod( x, y ) mod( x, y )
#define SineCosine( x, s, c ) s = sin( x ); c = cos( x );
#else
#define anyEqual( x, y ) any( (x) == (y) )
#define anyNotEqual( x, y ) any( (x) != (y) )
#define anyNotEqualZero( x ) any( (x) )
#define greaterThanEqual( x, y ) ( (x) >= (y) )
#define SineCosine( x, s, c ) sincos( x, s, c );
static half dot2( half2 a, half2 b ) { return dot( a, b ); }
static half dot3( half3 a, half3 b ) { return dot( a, b ); }
static half dot3( half3 a, half4 b ) { return dot( a, b.xyz ); }
static half dot3( half4 a, half3 b ) { return dot( a.xyz, b ); }
static half dot3( half4 a, half4 b ) { return dot( a.xyz, b.xyz ); }
static half dot4( half4 a, half4 b ) { return dot( a, b ); }
static half dot4( half2 a, half4 b ) { return dot( half4( a, 0, 1 ), b ); }
#define sampler2DShadow sampler2D
#define samplerCUBEShadow samplerCUBE
#define samplerRECTShadow samplerRECT
#endif
static half PAGE_SIZE = 128;
static half PAGE_BORDER = 4;
static half PAGE_SIZE_LOG2 = 7;
static half PAYLOAD_SIZE = PAGE_SIZE - 2 * PAGE_BORDER;
static half PAYLOAD_SIZE_LOG2 = 6.907;
#ifdef XBOX
// these are here because HLSL does not implement vector constructors with a single scalar parameter
half2 _half2( float x ) { return half2( x, x ); }
half3 _half3( float x ) { return half3( x, x, x ); }
half4 _half4( float x ) { return half4( x, x, x, x ); }
float2 _float2( float x ) { return float2( x, x ); }
float3 _float3( float x ) { return float3( x, x, x ); }
float4 _float4( float x ) { return float4( x, x, x, x ); }
static float4 h4tex2D( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4tex2Dproj( sampler2D image, float3 texcoord ) { return tex2Dproj( image, float4( texcoord.xy, 0, texcoord.z ) ); }
static float4 texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2D( image, texcoord, dx, dy ); }
static float4 h4texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2D( image, texcoord, dx, dy ); }
// return the depth value at texcoord.xy
static float tex2Ddepth( sampler2D image, float2 texcoord ) { return 1.0 - tex2D( image, texcoord ).x; }
static float tex2Ddepth_fast( sampler2D image, float2 texcoord ) { return 1.0 - tex2D( image, texcoord ).x; }
// compare texcoord.z with the depth value at texcoord.xy and return 1 if less and 0 if larger equal
static float shadow2Ddepth( sampler2DShadow image, float3 texcoord ) { return float( ( 1.0 - tex2D( image, texcoord.xy ).x ) >= texcoord.z ); }
static float4 swizzleColor( float4 color ) { return color.abgr; }
static float2 screenPosToTexcoord( float2 pos, float4 bias_scale ) { return ( pos * bias_scale.zw + bias_scale.xy ); }
bool bHardwareSkinning : register(b1);
bool bHardwareMorphing : register(b2);
#endif
#ifdef PS3
#define _half2( x ) half2( x )
#define _half3( x ) half3( x )
#define _half4( x ) half4( x )
#define _float2( x ) float2( x )
#define _float3( x ) float3( x )
#define _float4( x ) float4( x )
static float4 texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2D( image, texcoord, dx, dy ); }
static half4 h4texPhys( sampler2D image, float2 texcoord ) { return h4tex2D( image, texcoord ); }
static half4 h4texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return h4tex2D( image, texcoord, dx, dy ); }
// return the depth value at texcoord.xy
static float tex2Ddepth( sampler2D image, float2 texcoord ) { return texDepth2D_precise( image, texcoord ); }
static float tex2Ddepth_fast( sampler2D image, float2 texcoord ) {
// Perform most accurate integer reconstruction using a half precision multiply.
// Make sure the assember code looks like this:
//
// TEXR H0, R1, TEX0;
// MULH H0, H0, {0x437f0000(255), 0x00000000(0), 0x00000000(0), 0x00000000(0)}.x;
// DP3R R1.z, H0, {0x3b800000(0.00390625), 0x37800000(1.52588e-005), 0x33800000(5.96046e-008), 0x00000000(0)};
//
half4 dt = h4tex2D( image, texcoord ) * half( 255.0 );
return dot( dt, float4( 1.0 / 256, 1.0 / 256 / 256, 1.0 / 256 / 256 / 256, 0.0 ) );
}
// compare the depth value at texcoord.xy with texcoord.z and return 0 if less and 1 if larger equal
static float shadow2Ddepth( sampler2DShadow image, float3 texcoord ) { return tex2D( image, texcoord ).x; }
static float4 swizzleColor( float4 color ) { return color; }
static float2 screenPosToTexcoord( float2 pos, float4 bias_scale ) { return ( pos * bias_scale.zw + bias_scale.xy ); }
bool hardwareSkinning : b1;
bool hardwareMorphing : b2;
#endif
#if defined( PC_D3D )
// these are here because HLSL does not implement vector constructors with a single scalar parameter
half2 _half2( float x ) { return half2( x, x ); }
half3 _half3( float x ) { return half3( x, x, x ); }
half4 _half4( float x ) { return half4( x, x, x, x ); }
float2 _float2( float x ) { return float2( x, x ); }
float3 _float3( float x ) { return float3( x, x, x ); }
float4 _float4( float x ) { return float4( x, x, x, x ); }
SamplerState samplerGeneric : register( s0 ); // FIXME
static float4 tex2D( sampler2D image, float2 texcoord ) { return image.Sample( samplerGeneric, texcoord ); }
static float4 tex2Dproj( sampler2D image, float3 texcoord ) { return image.Sample( samplerGeneric, texcoord ); }
static float4 tex2DGrad( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return image.SampleGrad( samplerGeneric, texcoord, dx, dy ); }
static float4 tex2Dlod( sampler2D image, float4 texcoord ) { return image.SampleLevel( samplerGeneric, texcoord.xy, texcoord.w, 0 ); }
static float4 tex2Dbias( sampler2D image, float4 texcoord ) { return image.SampleBias( samplerGeneric, texcoord.xy, texcoord.w ); }
static float4 texCUBE( samplerCUBE image, float3 texcoord ) { return image.Sample( samplerGeneric, texcoord ); }
static float4 texCUBElod( samplerCUBE image, float4 texcoord ) { return image.SampleLevel( samplerGeneric, texcoord.xyz, texcoord.w ); }
static float4 h4tex2D( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4tex2Dproj( sampler2D image, float3 texcoord ) { return tex2Dproj( image, float4( texcoord.xy, 0, texcoord.z ) ); }
static float4 texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2DGrad( image, texcoord, dx, dy ); }
static float4 h4texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2DGrad( image, texcoord, dx, dy ); }
// return the depth value at texcoord.xy
static float tex2Ddepth( sampler2D image, float2 texcoord ) { return 1.0 - tex2D( image, texcoord ).x; }
static float tex2Ddepth_fast( sampler2D image, float2 texcoord ) { return 1.0 - tex2D( image, texcoord ).x; }
// compare texcoord.z with the depth value at texcoord.xy and return 1 if less and 0 if larger equal
static float shadow2Ddepth( sampler2DShadow image, float3 texcoord ) { return float( ( 1.0 - tex2D( image, texcoord.xy ).x ) >= texcoord.z ); }
static float4 swizzleColor( float4 color ) { return color.rgba; }
static float2 screenPosToTexcoord( float2 pos, float4 bias_scale ) { return ( pos * bias_scale.zw + bias_scale.xy ); }
bool bHardwareSkinning : register(b1);
bool bHardwareMorphing : register(b2);
#elif defined( PC )
#define _half2( x ) half2( x )
#define _half3( x ) half3( x )
#define _half4( x ) half4( x )
#define _float2( x ) float2( x )
#define _float3( x ) float3( x )
#define _float4( x ) float4( x )
static float4 h4tex2D( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4tex2Dproj( sampler2D image, float3 texcoord ) { return tex2Dproj( image, texcoord ); }
static float4 texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2D( image, texcoord, dx, dy ); }
static float4 h4texPhys( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ); }
static float4 h4texPhys( sampler2D image, float2 texcoord, float2 dx, float2 dy ) { return tex2D( image, texcoord, dx, dy ); }
// return the depth value at texcoord.xy
static float tex2Ddepth( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ).x; }
static float tex2Ddepth_fast( sampler2D image, float2 texcoord ) { return tex2D( image, texcoord ).x; }
// compare the depth value at texcoord.xy with texcoord.z and return 0 if less and 1 if larger equal
static float shadow2Ddepth( sampler2DShadow image, float3 texcoord ) { return tex2D( image, texcoord ).x; }
static float4 swizzleColor( float4 color ) { return color; }
static float2 screenPosToTexcoord( float2 pos, float4 bias_scale ) { return ( pos * bias_scale.zw + bias_scale.xy ); }
#endif
static const half4 matrixRGB1toCoCg1YX = half4( 0.50, 0.0, -0.50, 0.50196078 ); // Co
static const half4 matrixRGB1toCoCg1YY = half4( -0.25, 0.5, -0.25, 0.50196078 ); // Cg
static const half4 matrixRGB1toCoCg1YZ = half4( 0.0, 0.0, 0.0, 1.0 ); // 1.0
static const half4 matrixRGB1toCoCg1YW = half4( 0.25, 0.5, 0.25, 0.0 ); // Y
static const half4 matrixCoCg1YtoRGB1X = half4( 1.0, -1.0, 0.0, 1.0 );
static const half4 matrixCoCg1YtoRGB1Y = half4( 0.0, 1.0, -0.50196078, 1.0 ); // -0.5 * 256.0 / 255.0
static const half4 matrixCoCg1YtoRGB1Z = half4( -1.0, -1.0, 1.00392156, 1.0 ); // +1.0 * 256.0 / 255.0
// uses texel space coordinates, not normalized coordinates
static float ComputeLOD( float2 virtCoords ) {
float2 dx = ddx( virtCoords.xy );
float2 dy = ddy( virtCoords.xy );
float px = dot2( dx, dx );
float py = dot2( dy, dy );
float maxLod = 0.5 * log2( max( px, py ) ); // log2(sqrt()) = 0.5*log2()
return maxLod;
}
// uses texel space coordinates, not normalized coordinates
static float ComputeAnisoLOD( float2 virtCoords, float maxAnisoLog2 ) {
float2 dx = ddx( virtCoords.xy );
float2 dy = ddy( virtCoords.xy );
float px = dot2( dx, dx );
float py = dot2( dy, dy );
float maxLod = 0.5 * log2( max( px, py ) ); // log2(sqrt()) = 0.5*log2()
float minLod = 0.5 * log2( min( px, py ) );
return maxLod - min( maxAnisoLog2, maxLod - minLod );
}
static float4 ComputeVirtualLOD( float4 filterParms, float4 feedbackFloat, float4 virtMapping, float2 virtCoords ) {
// Used for the land generation tool path.
float drawBias = filterParms.x;
float maxAnisoLog2 = filterParms.z;
float widthInPages = feedbackFloat.y;
// take just the fractional part of the original texture coordinate to give texture wrapping
// scale and bias it by the source to virtual texture mapping
float4 virtualTexCoord;
virtualTexCoord.zw = _float2( 0.0 );
virtualTexCoord.xy = frac( virtCoords );
virtualTexCoord.xy = virtualTexCoord.xy * virtMapping.xy + virtMapping.zw;
// look up the proper LOD in the dedicated LOD texture, based on the original, non-wrapped,
// non-paged texture coordinates to avoid discontinuities. Still need to multiply by virtualMapping.xy
// to account for the dimensions of the original texture.
virtualTexCoord.w = ComputeAnisoLOD( virtCoords * virtMapping.xy * widthInPages * PAYLOAD_SIZE, maxAnisoLog2 );
// adjust for the LOD bias already applied in the virtToPhysPage sampler (log2TexelSizeRatio)
virtualTexCoord.w -= PAYLOAD_SIZE_LOG2 + drawBias;
return virtualTexCoord;
}
#if defined( XBOX ) || ( defined( ATI ) && !defined( ATI_CLAMPED_ANISO ) )
// use the virtual texture coordinate instead of the physical texture coordinate for the anisotropic texture lookup
#define USE_VIRTUAL_ANISO_FOOTPRINT
#endif
// bias the page table lookup anticipating an anisotropic texture lookup
// this is expensive but may be a nice quality improvement for high end PCs
//#define USE_ANISO_PAGE_TABLE_LOOKUP
static float4 PageTableBiasForAniso( float2 virtCoords ) {
const float minAnisoBias = -2; // -log2( maxAniso )
// calculate a bias for the page table lookup based on the size of the anisotropic footprint
float2 dx = ddx( virtCoords.xy );
float2 dy = ddy( virtCoords.xy );
float px = dot2( dx, dx );
float py = dot2( dy, dy );
float maxLod = 0.5 * log2( max( px, py ) ); // log2(sqrt()) = 0.5*log2()
float minLod = 0.5 * log2( min( px, py ) );
float anisoBias = max( minLod - maxLod, minAnisoBias );
return float4( virtCoords.x, virtCoords.y, 0, anisoBias );
}
#ifdef USE_ANISO_PAGE_TABLE_LOOKUP
#define tex2DPageTable( sampler, coords ) tex2Dbias( sampler, PageTableBiasForAniso( coords ) )
#else
#define tex2DPageTable( sampler, coords ) tex2D( sampler, coords )
#endif
//#define PAGE_TABLE_ONLY_8888
#if defined( PS3 ) || defined( XBOX )
#define PAGE_TABLE_ONLY_565
#endif
//#define MAPPING_IMAGE_3X_FLOAT32
//#define MAPPING_IMAGE_2X_FIXED16
#if defined( PAGE_TABLE_ONLY_8888 )
// using only the page table in 8-bit per component RGBA format
#define UniqueVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define UniqueDiffuseOnlyVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define UniqueDiffuseOnly2VirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define VmtrVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 16 )
#define VmtrVirtualLODToPhysical( virtMapping, coords ) VirtualToPhysical2( $vmtrPageTableMap, coords, 16 ).xy
static float3 VirtualToPhysical2( sampler2D virtToPhysPage, float2 virtCoords, float physPagesWide ) {
// constants
const float pageWidth = 128;
const float pageBorder = 4;
//const float physPagesWide = 32;
#if defined( PS3 ) || defined( XBOX )
const float floatToByte = 255.0 + 1.0 / 256;
#else
const float floatToByte = 255.0;
#endif
// derived constants
const float pageFracScale = ( pageWidth - 2 * pageBorder ) / pageWidth / physPagesWide;
const float borderOffset = pageBorder / pageWidth / physPagesWide;
const float4 texScale = {
floatToByte / physPagesWide,
floatToByte / physPagesWide,
floatToByte * 1.0 / 16.0,
floatToByte * 256.0 / 16.0
};
const float4 texBias = { borderOffset, borderOffset, 0, 0 };
// translation
float4 physPage = tex2DPageTable( virtToPhysPage, virtCoords ) * texScale + texBias;
float2 pageFrac = frac( virtCoords * ( physPage.z + physPage.w ) );
float3 physCoord;
physCoord.xy = pageFrac * pageFracScale + physPage.xy;
physCoord.z = ( physPage.z + physPage.w ) * pageFracScale;
return physCoord;
}
#elif defined( PAGE_TABLE_ONLY_565 )
// using only the page table in 565 RGB format
#define UniqueVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define UniqueDiffuseOnlyVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define UniqueDiffuseOnly2VirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 32 )
#define VmtrVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, coords, 16 )
#define VmtrVirtualLODToPhysical( virtMapping, coords ) VirtualToPhysical2( $vmtrPageTableMap, coords, 16 ).xy
static float3 VirtualToPhysical2( sampler2D virtToPhysPage, float2 virtCoords, float physPagesWide ) {
// constants
const float pageWidth = 128;
const float pageBorder = 4;
//const float physPagesWide = 32;
#if defined( PS3 )
const float floatToPagesWide = ( 255.0 + 1.0 / 256 ) / 256.0 * physPagesWide;
const float floatToMip = ( 255.0 + 1.0 / 256 ) / 256.0 * 64.0;
#elif defined( XBOX )
const float floatToPagesWide = ( 31.0 + 1.0 / 33.0 ) / 32.0 * physPagesWide;
const float floatToMip = ( 63.0 + 1.0 / 65.0 );
#else
const float floatToPagesWide = 255.0 / 256.0 * physPagesWide;
const float floatToMip = 255.0 / 256.0 * 64.0;
#endif
// derived constants
const float pageFracScale = ( pageWidth - 2 * pageBorder ) / pageWidth / physPagesWide;
const float borderOffset = pageBorder / pageWidth / physPagesWide;
const float4 texScale = {
floatToPagesWide,
floatToMip,
floatToPagesWide,
0
};
float4 texBias = { 0, 1.0 / 4096.0, 0, 0 };
// translation
half4 physPage = tex2DPageTable( virtToPhysPage, virtCoords ) * texScale + texBias; // NOTE: must be half4 for PS3 ?
physPage.y = exp2( physPage.y );
physPage = floor( physPage );
float2 pageFrac = frac( virtCoords * physPage.y );
float3 physCoord;
physCoord.xy = pageFrac * pageFracScale + physPage.xz / physPagesWide + borderOffset;
physCoord.z = physPage.y * pageFracScale;
return physCoord;
}
#elif defined( MAPPING_IMAGE_2X_FIXED16 )
// using two unsigned fixed point 16-bit mapping textures, one with a single channel and one with two channels
#define UniqueVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueMappingsMap0, $physicalUniqueMappingsMap1, coords )
#define UniqueDiffuseOnlyVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnlyMappingsMap0, $physicalUniqueDiffuseOnlyMappingsMap1, coords )
#define UniqueDiffuseOnly2VirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnly2MappingsMap0, $physicalUniqueDiffuseOnly2MappingsMap1, coords )
#define VmtrVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalVmtrMappingsMap0, $physicalVmtrMappingsMap1, coords )
#define VmtrVirtualLODToPhysical( virtMapping, coords ) VirtualToPhysical2( $vmtrPageTableMap, $physicalVmtrMappingsMap0, $physicalVmtrMappingsMap1, coords ).xy
static float3 VirtualToPhysical2( sampler2D virtToPhysPage, sampler2D physPageToXform0, sampler2D physPageToXform1, float2 virtCoords ) {
half2 physPage = tex2DPageTable( virtToPhysPage, virtCoords ).xy;
float4 xform0 = tex2D( physPageToXform0, physPage ) * 32.0;
float4 xform1 = tex2D( physPageToXform1, physPage ) * 32.0;
float3 physCoord;
physCoord.xy = virtCoords * xform0.y + xform1.xw - 30.0;
physCoord.z = 0.0f;
return physCoord;
}
#elif defined( MAPPING_IMAGE_3X_FLOAT32 )
// using three single channel float 32 mapping textures, one for each component
#define UniqueVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueMappingsMap0, $physicalUniqueMappingsMap1, $physicalUniqueMappingsMap2, coords )
#define UniqueDiffuseOnlyVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnlyMappingsMap0, $physicalUniqueDiffuseOnlyMappingsMap1, $physicalUniqueDiffuseOnlyMappingsMap2, coords )
#define UniqueDiffuseOnly2VirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnly2MappingsMap0, $physicalUniqueDiffuseOnly2MappingsMap1, $physicalUniqueDiffuseOnly2MappingsMap2, coords )
#define VmtrVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalVmtrMappingsMap0, $physicalVmtrMappingsMap1, $physicalVmtrMappingsMap2, coords )
#define VmtrVirtualLODToPhysical( virtMapping, coords ) VirtualToPhysical2( $vmtrPageTableMap, $physicalVmtrMappingsMap0, $physicalVmtrMappingsMap1, $physicalVmtrMappingsMap2, coords ).xy
static float3 VirtualToPhysical2( sampler2D virtToPhysPage, sampler2D physPageToXform0, sampler2D physPageToXform1, sampler2D physPageToXform2, float2 virtCoords ) {
half2 physPage = tex2DPageTable( virtToPhysPage, virtCoords ).xy;
float xform0 = tex2D( physPageToXform0, physPage ).x;
float xform1 = tex2D( physPageToXform1, physPage ).x;
float xform2 = tex2D( physPageToXform2, physPage ).x;
float3 physCoord;
physCoord.xy = virtCoords * xform0 + float2( xform1, xform2 );
physCoord.z = 0.0f;
return physCoord;
}
#else
// using a single 4 channel float 32 mapping texture
#define UniqueVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueMappingsMap0, coords )
#define UniqueDiffuseOnlyVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnlyMappingsMap0, coords )
#define UniqueDiffuseOnly2VirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalUniqueDiffuseOnly2MappingsMap0, coords )
#define VmtrVirtualToPhysical( coords ) VirtualToPhysical2( $pageTableMap, $physicalVmtrMappingsMap0, coords )
#define VmtrVirtualLODToPhysical( virtMapping, coords ) VirtualLODToPhysical2( $vmtrPageTableMap, $physicalVmtrMappingsMap0, ComputeVirtualLOD( $physicalVmtrFilterParms, $virtualTextureFeedbackFloat, virtMapping, coords ) )
static float3 VirtualToPhysical2( sampler2D virtToPhysPage, sampler2D physPageToXform0, float2 virtCoords ) {
half2 physPage = tex2DPageTable( virtToPhysPage, virtCoords ).xy;
float4 xform = tex2D( physPageToXform0, physPage );
float3 physCoord;
physCoord.xy = virtCoords * xform.x + xform.zw;
physCoord.z = xform.y;
return physCoord;
}
static float2 VirtualLODToPhysical2( sampler2D virtToPhysPage, sampler2D physPageToXform0, float4 virtCoords ) {
half2 physPage = tex2Dlod( virtToPhysPage, virtCoords ).xy;
float4 xform = tex2D( physPageToXform0, physPage );
return virtCoords.xy * xform.x + xform.zw;
}
#endif
static float ComputeSoftParticleScale( sampler2D image, float2 tc, float interpolatedZOverW, float softness ) {
// This instruction handles the 1.0 - depth calc automatically when using an inverted depth buffer
float depth = tex2Ddepth( image, tc );
// Approximate a linear depth difference
float r1 = 1.0 / ( 1.0 - depth );
float r2 = 1.0 / ( 1.0 - interpolatedZOverW );
return saturate( ( r1 - r2 ) * softness );
}
static half4 ComputeAnimCrossFadeColor( sampler2D image, float2 tc0, float2 tc1, float frameFrac ) {
// For strip animations, we need to cross-fade
half4 result0 = tex2D( image, tc0 ) * ( 1.0 - frameFrac );
half4 result1 = tex2D( image, tc1 ) * ( frameFrac ); // when frameFrac is 0, no contribution
return ( result0 + result1 );
}
// the 'distortVec' is in the range [-1.0, 1.0] for each component where 1.0 is the
// full screen width or height respectively
// the 'blur' value is in the range [0.0, 1.0] where 1.0 offsets the mip level by 8
static float4 ComputeDistortion( float2 distortVec, float blur ) {
// The distortion vector is usually very small so store a close to normalized vector
// in 'xy' and store a scale value in 'z'.
// The blur value is moved in the range [0.5, 1.0] which allows multiple distortions
// to be blended with GL_ONE_MINUS_DST_ALPHA GL_DST_ALPHA. The 'blur' (alpha channel) in
// the distortion map is initialized to zero such that the first distortion fully contributes
// and then consecutive distortions will blend in with a value in the range [0.0, 0.5].
// Blending based on the blur value is of course wrong but it works if no blurring is applied.
// Also, as the blur value goes up, additional distortions contribute less which is
// fine because the distortions won't be noticeable when there is a lot of blurring.
// A linear blend of the two vectors with separate scale values does not result in the
// same vector as a linear blend of the original vectors. However, the resulting vector
// is still nicely bounded between the original vectors and representative of accumulated
// distortions.
// To decode the distortion vector and blur value in the post process we use:
// half4 distortion = h4tex2D( $postDistortionMap, texcoord.xy ) - ( 127.0 / 255.0 );
// perturb += distortion.xy * distortion.z;
// blur += saturate( distortion.w ) * 16;
float4 final;
final.z = 0.125 + sqrt( dot( distortVec, distortVec ) );
final.xy = distortVec / final.z;
final.w = blur * 0.5;
return final + ( 127.0 / 255.0 );
}
static half2 ComputeTransAtlasCoord( half2 tc, half4 scaleBias ) {
// Figure out half texel, pick fraction from texture coordinates and clamp it inside [ 0+halfTexel, 1-halfTexel ]
half2 halfScale = scaleBias.xy * _half2( 0.5 );
half2 result = max( min( frac( tc ), _half2( 1.0 ) - halfScale ), halfScale );
// Scale and bias clamped texture coordinates
return result * scaleBias.xy + scaleBias.zw;
}
static float4 ComputeDistortionMV( float2 distortVec, float blur ) {
float4 final;
final.xy = saturate( distortVec * 0.5 + 0.5 );
final.z = blur * 0.5 + 0.5;
final.w = 1.0;
return final;
}
static float3 CoCgScYToRGB( float4 CoCgScY ) {
float3 rgb;
CoCgScY.z = ( CoCgScY.z * 31.875 ) + 1.0; //z = z * 255.0/8.0 + 1.0
CoCgScY.z = 1.0 / CoCgScY.z;
CoCgScY.xy *= CoCgScY.z;
rgb.x = dot4( CoCgScY, matrixCoCg1YtoRGB1X );
rgb.y = dot4( CoCgScY, matrixCoCg1YtoRGB1Y );
rgb.z = dot4( CoCgScY, matrixCoCg1YtoRGB1Z );
return rgb;
}
static float4 CoCgScYToRGB1( float4 CoCgScY ) {
float4 rgba;
rgba.xyz = CoCgScYToRGB( CoCgScY );
rgba.w = 1;
return rgba;
}
static float3 ScaleSpecular( float3 unscaled, float factor ) {
return ( unscaled * 8.0 ) / ( factor * 255.0 + 8.0 );
}
//#define FEEDBACK_FORMAT_FLOAT32
static float4 CalculateFeedback( float2 texCoords, float4 feedbackParms, float4 filterParms ) {
float4 feedback;
float bias = filterParms.y;
float maxAnisoLog2 = filterParms.z;
float widthInPages = feedbackParms.y;
// xy is the integral page coordinates
feedback.xy = texCoords * widthInPages;
// compute the desired LOD for anisotropic filtering
float desiredLod = ComputeAnisoLOD( feedback.xy * PAYLOAD_SIZE, maxAnisoLog2 ) + bias;
// z is the lod level, never adjust below 0
feedback.z = max( 0.0, desiredLod );
// w holds the virtual texture index
feedback.w = feedbackParms.x;
return feedback;
}
/*
pageX = ( data[0] & 0xFF ) + ( data[2] & 0x0F ) << 8 );
pageY = ( data[1] & 0xFF ) + ( data[2] & 0xF0 ) << 4 );
pageLOD = ( data[3] & 0x0F );
pageSource = ( data[3] & 0xF0 ) >> 4;
*/
static float4 PackFeedback( float4 feedback ) {
#ifdef FEEDBACK_FORMAT_FLOAT32
return feedback;
#else
feedback = floor( feedback ) / 256.0;
float2 xy_low = frac( feedback.xy + 0.5 / 256.0 );
float2 xy_high = floor( feedback.xy ) / 256.0;
float4 color;
color.xy = xy_low;
color.z = xy_high.y * 16.0 + xy_high.x;
color.w = feedback.w * 16.0 + feedback.z;
#if defined( XBOX )
return color.zyxw; // stored as B-G-R-A
#elif defined( PS3 )
return color.yzwx; // stored as A-R-G-B
#else
return color;
#endif
#endif
}