/* 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 }