[General]
language=HLSL
filePath=
compiler=DXC
entryPoint=EmitDepthOnlyPS
shaderType=Compute
shaderModel=6_6
outputType=DXIL
extraOptionsEnabled=false
extraOptions=
encoding=UTF-8
includePaths=D:/ygame/products/EditorDX11/EngineAsset/data/material/Shader_DX11_HD/Base, D:/ygame/products/EditorDX11/EngineAsset/data/material/Shader_DX11_HD
includePathsVisible=true
macros=@Invalid()
macrosVisible=false
lastHLSLCompiler=DXC
lastGLSLCompiler=FXC
lastOpenDir=F:/Workspace/ShaderCross/build/Release
inputContent="#include \"VG/VG_Common.hlsli\"\n#include \"VG/VG_DataType.hlsli\"\n#include \"VG/VG_AttributeDataType.hlsli\"\n\nstruct VG_PAGE_INSTALL_INFO\n{\n\tuint SrcPageOffset;\n\tuint DstPageOffset;\n\tuint PageDependenciesStart;\n\tuint PageDependenciesNum;\n};\n\ncbuffer TRANSCODE_CBUFFER\n{\n\tuint StartPageIndex;\n\tuint MaxPages;\n\tuint2 Padding1;\n};\n\nStructuredBuffer<VG_PAGE_INSTALL_INFO> InstallInfoBuffer;\nStructuredBuffer<uint> PageDependenciesBuffer;\nByteAddressBuffer SrcPageBuffer;\nRWByteAddressBuffer DstPageBuffer;\n\nstruct VG_PAGE_DISK_HEADER // KGVG_PageDiskHeader\n{\n\tuint GpuSize;\n\tuint NumClusters;\n\tuint NumRawFloat4s;\n\tuint NumTexCoords;\n\tbool HasSkinBones;\n\tbool HasSpeedTree;\n\tbool HasFlexData;\n\tuint NumVertexRefs;\n\tuint DecodeInfoOffset;\n\tuint StripBitmaskOffset;\n\tuint VertexRefBitmaskOffset;\n};\n\nVG_PAGE_DISK_HEADER GetPageDiskHeader(uint PageBaseOffset)\n{\n\tuint4 Data[2];\n\tData[0] = SrcPageBuffer.Load4(PageBaseOffset + 0);\n\tData[1] = SrcPageBuffer.Load4(PageBaseOffset + 16);\n\n\tVG_PAGE_DISK_HEADER DiskHeader;\n\tDiskHeader.GpuSize = Data[0].x;\n\tDiskHeader.NumClusters = Data[0].y;\n\tDiskHeader.NumRawFloat4s = Data[0].z;\n\tDiskHeader.NumTexCoords = Data[0].w >> 4;\n\tDiskHeader.HasSkinBones = (Data[0].w & 1) != 0 ? true : false;\n\tDiskHeader.HasSpeedTree = (Data[0].w & (1 << 1)) != 0 ? true : false;\n\tDiskHeader.HasFlexData = (Data[0].w & (1 << 2)) != 0 ? true : false;\n\tDiskHeader.NumVertexRefs = Data[1].x;\n\tDiskHeader.DecodeInfoOffset = Data[1].y;\n\tDiskHeader.StripBitmaskOffset = Data[1].z;\n\tDiskHeader.VertexRefBitmaskOffset = Data[1].w;\n\treturn DiskHeader;\n}\n\nstruct VG_CLUSTER_DISK_HEADER\n{\n\tuint IndexDataOffset;\n\tuint PageClusterMapOffset;\n\tuint VertexRefDataOffset;\n\tuint PositionDataOffset;\n\tuint AttributeDataOffset;\n\tuint SkinOrSrtDataOffset;\n\tuint FlexDataOffset;\n\tuint NumVertexRefs;\n\tuint NumPrevRefVerticesBeforeDwords;\n\tuint NumPrevNewVerticesBeforeDwords;\n};\n\nVG_CLUSTER_DISK_HEADER GetClusterDiskHeader(uint PageBaseOffset, uint ClusterIndex)\n{\n\tuint ByteOffset = PageBaseOffset + VG_PAGE_DISK_HEADER_SIZE + ClusterIndex * VG_CLUSTER_DISK_HEADER_SIZE;\n\tuint4 DataUint4[2];\n\tDataUint4[0] = SrcPageBuffer.Load4(ByteOffset);\n\tDataUint4[1] = SrcPageBuffer.Load4(ByteOffset + 16);\n\tuint2 DataUint2 = SrcPageBuffer.Load2(ByteOffset + 32);\n\t\n\tVG_CLUSTER_DISK_HEADER Header;\n\tHeader.IndexDataOffset = DataUint4[0].x;\n\tHeader.PageClusterMapOffset = DataUint4[0].y;\n\tHeader.VertexRefDataOffset = DataUint4[0].z;\n\tHeader.PositionDataOffset = DataUint4[0].w;\n\tHeader.AttributeDataOffset = DataUint4[1].x;\n\tHeader.SkinOrSrtDataOffset = DataUint4[1].y;\n\tHeader.FlexDataOffset = DataUint4[1].z;\n\tHeader.NumVertexRefs = DataUint4[1].w;\n\tHeader.NumPrevRefVerticesBeforeDwords = DataUint2.x;\n\tHeader.NumPrevNewVerticesBeforeDwords = DataUint2.y;\n\treturn Header;\n}\n\nuint ReadUnalignedDword(ByteAddressBuffer InputBuffer, uint BaseAddressInBytes, int BitOffset)\n{\n\tuint ByteAddress = BaseAddressInBytes + (BitOffset >> 3);\n\tuint AlignedByteAddress = ByteAddress & ~3;\n\tBitOffset = ((ByteAddress - AlignedByteAddress) << 3) | (BitOffset & 7);\n\n\tuint2 Data = InputBuffer.Load2(AlignedByteAddress);\n\treturn BitAlignU32(Data.y, Data.x, BitOffset);\n}\n\n\nuint ReadByte(ByteAddressBuffer InputBuffer, uint Address)\n{\n\treturn (InputBuffer.Load(Address & ~3u) >> ((Address & 3u) * 8)) & 0xFFu; //TODO: use bytealign intrinsic?\n}\n\nuint ReadUnalignedDwordFromAlignedBase(ByteAddressBuffer SrcBuffer, uint AlignedBaseAddress, uint BitOffset)\n{\n\tuint2 Data = SrcBuffer.Load2(AlignedBaseAddress);\n\treturn BitAlignU32(Data.y, Data.x, BitOffset);\n}\n\nvoid CopyBits(RWByteAddressBuffer DstBuffer, uint DstBaseAddress, uint DstBitOffset, ByteAddressBuffer SrcBuffer, uint SrcBaseAddress, uint SrcBitOffset, uint NumBits)\n{\n\tif (NumBits == 0)\n\t\treturn;\n\n\t// TODO: optimize me\n\tuint DstDword = (DstBaseAddress + (DstBitOffset >> 3)) >> 2;\n\tDstBitOffset = (((DstBaseAddress & 3u) << 3) + DstBitOffset) & 31u;\n\tuint SrcDword = (SrcBaseAddress + (SrcBitOffset >> 3)) >> 2;\n\tSrcBitOffset = (((SrcBaseAddress & 3u) << 3) + SrcBitOffset) & 31u;\n\n\tuint DstNumDwords = (DstBitOffset + NumBits + 31u) >> 5;\n\tuint DstLastBitOffset = (DstBitOffset + NumBits) & 31u;\n\t\n\tconst uint FirstMask = 0xFFFFFFFFu << DstBitOffset;\n\tconst uint LastMask = DstLastBitOffset ? BitFieldMaskU32(DstLastBitOffset, 0) : 0xFFFFFFFFu;\n\tconst uint Mask = FirstMask & (DstNumDwords == 1 ? LastMask : 0xFFFFFFFFu);\n\n\t{\n\t\tuint Data = ReadUnalignedDwordFromAlignedBase(SrcBuffer, SrcDword * 4, SrcBitOffset);\n\t\tDstBuffer.InterlockedAnd(DstDword * 4, ~Mask);\n\t\tDstBuffer.InterlockedOr(DstDword * 4, (Data << DstBitOffset) & Mask);\n\t\tDstDword++;\n\t\tDstNumDwords--;\n\t}\n\n\tif (DstNumDwords > 0)\n\t{\n\t\tSrcBitOffset += 32 - DstBitOffset;\n\t\tSrcDword += SrcBitOffset >> 5;\n\t\tSrcBitOffset &= 31u;\n\n\t\twhile (DstNumDwords > 1)\n\t\t{\n\t\t\tuint Data = ReadUnalignedDwordFromAlignedBase(SrcBuffer, SrcDword * 4, SrcBitOffset);\n\t\t\tDstBuffer.Store(DstDword * 4, Data);\n\t\t\tDstDword++;\n\t\t\tSrcDword++;\n\t\t\tDstNumDwords--;\n\t\t}\n\t\t\n\t\tuint Data = ReadUnalignedDwordFromAlignedBase(SrcBuffer, SrcDword * 4, SrcBitOffset);\n\t\tDstBuffer.InterlockedAnd(DstDword * 4, ~LastMask);\n\t\tDstBuffer.InterlockedOr(DstDword * 4, Data & LastMask);\n\t}\n}\n\n// Debug only. Performance doesn't matter.\nvoid CopyDwords(RWByteAddressBuffer DstBuffer, uint DstAddress, ByteAddressBuffer SrcBuffer, uint SrcAddress, uint NumDwords)\n{\n\tfor (uint i = 0; i < NumDwords; i++)\n\t{\n\t\tDstBuffer.Store(DstAddress + i * 4, SrcBuffer.Load(SrcAddress + i * 4));\n\t}\n}\n\nuint3 UnpackStripIndices(uint SrcPageBaseOffset, VG_PAGE_DISK_HEADER PageDiskHeader, VG_CLUSTER_DISK_HEADER ClusterDiskHeader, uint LocalClusterIndex, uint TriIndex)\n{\n\tconst uint DwordIndex = TriIndex >> 5;\n\tconst uint BitIndex = TriIndex & 31u;\n\n\t//Bitmask.x: bIsStart, Bitmask.y: bIsLeft, Bitmask.z: bIsNewVertex\n\tconst uint3 StripBitmasks = SrcPageBuffer.Load3(SrcPageBaseOffset + PageDiskHeader.StripBitmaskOffset + (LocalClusterIndex * (VG_MAX_CLUSTER_TRIANGLES / 32) + DwordIndex) * 12);\n\n\tconst uint SMask = StripBitmasks.x;\n\tconst uint LMask = StripBitmasks.y;\n\tconst uint WMask = StripBitmasks.z;\n\tconst uint SLMask = SMask & LMask;\n\n\t//const uint HeadRefVertexMask = ( SMask & LMask & WMask ) | ( ~SMask & WMask );\n\tconst uint HeadRefVertexMask = (SLMask | ~SMask) & WMask; // 1 if head of triangle is ref. S case with 3 refs or L/R case with 1 ref.\n\n\tconst uint PrevBitsMask = (1u << BitIndex) - 1u;\n\t\n\tconst uint NumPrevRefVerticesBeforeDword = DwordIndex ? BitFieldExtractU32(ClusterDiskHeader.NumPrevRefVerticesBeforeDwords, 10u, DwordIndex * 10u - 10u) : 0u;\n\tconst uint NumPrevNewVerticesBeforeDword = DwordIndex ? BitFieldExtractU32(ClusterDiskHeader.NumPrevNewVerticesBeforeDwords, 10u, DwordIndex * 10u - 10u) : 0u;\n\n\tint CurrentDwordNumPrevRefVertices = (countbits(SLMask & PrevBitsMask) << 1) + countbits(WMask & PrevBitsMask);\n\tint CurrentDwordNumPrevNewVertices = (countbits(SMask & PrevBitsMask) << 1) + BitIndex - CurrentDwordNumPrevRefVertices;\n\n\tint NumPrevRefVertices = NumPrevRefVerticesBeforeDword + CurrentDwordNumPrevRefVertices;\n\tint NumPrevNewVertices = NumPrevNewVerticesBeforeDword + CurrentDwordNumPrevNewVertices;\n\n\tconst int IsStart = BitFieldExtractI32(SMask, 1, BitIndex); // -1: true, 0: false\n\tconst int IsLeft = BitFieldExtractI32(LMask, 1, BitIndex); // -1: true, 0: false\n\tconst int IsRef = BitFieldExtractI32(WMask, 1, BitIndex); // -1: true, 0: false\n\n\tconst uint BaseVertex = NumPrevNewVertices - 1u;\n\n\tuint3 OutIndices;\n\tuint ReadBaseAddress = SrcPageBaseOffset + ClusterDiskHeader.IndexDataOffset;\n\tuint IndexData = ReadUnalignedDword(SrcPageBuffer, ReadBaseAddress, (NumPrevRefVertices + ~IsStart) * 5); // -1 if not Start\n\n\tif (IsStart)\n\t{\n\t\tconst int MinusNumRefVertices = (IsLeft << 1) + IsRef;\n\t\tuint NextVertex = NumPrevNewVertices;\n\n\t\tif (MinusNumRefVertices <= -1)\n\t\t{\n\t\t\tOutIndices.x = BaseVertex - (IndexData & 31u);\n\t\t\tIndexData >>= 5;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tOutIndices[0] = NextVertex++;\n\t\t}\n\t\tif (MinusNumRefVertices <= -2)\n\t\t{\n\t\t\tOutIndices.y = BaseVertex - (IndexData & 31u);\n\t\t\tIndexData >>= 5;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tOutIndices[1] = NextVertex++;\n\t\t}\n\t\tif (MinusNumRefVertices <= -3)\n\t\t{\n\t\t\tOutIndices.z = BaseVertex - (IndexData & 31u);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tOutIndices[2] = NextVertex++;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Handle two first vertices\n\t\tconst uint PrevBitIndex = BitIndex - 1u;\n\t\tconst int IsPrevStart = BitFieldExtractI32(SMask, 1, PrevBitIndex);\n\t\tconst int IsPrevHeadRef = BitFieldExtractI32(HeadRefVertexMask, 1, PrevBitIndex);\n\t\tconst int NumPrevNewVerticesInTriangle = IsPrevStart & (3u - ((BitFieldExtractU32( /*SLMask*/LMask, 1, PrevBitIndex) << 1) | BitFieldExtractU32( /*SMask &*/WMask, 1, PrevBitIndex)));\n\n\t\t//OutIndices[ 1 ] = IsPrevRefVertex ? ( BaseVertex - ( IndexData & 31u ) + NumPrevNewVerticesInTriangle ) : BaseVertex;\t// BaseVertex = ( NumPrevNewVertices - 1 );\n\t\tOutIndices.y = BaseVertex + (IsPrevHeadRef & (NumPrevNewVerticesInTriangle - (IndexData & 31u)));\n\t\t//OutIndices[ 2 ] = IsRefVertex ? ( BaseVertex - bfe_u32( IndexData, 5, 5 ) ) : NumPrevNewVertices;\n\t\tOutIndices.z = NumPrevNewVertices + (IsRef & (-1 - BitFieldExtractU32(IndexData, 5, 5)));\n\n\t\t// We have to search for the third vertex. \n\t\t// Left triangles search for previous Right/Start. Right triangles search for previous Left/Start.\n\t\tconst uint SearchMask = SMask | (LMask ^ IsLeft); // SMask | ( IsRight ? LMask : RMask );\n\t\tconst uint FoundBitIndex = firstbithigh(SearchMask & PrevBitsMask);\n\t\tconst int IsFoundCaseS = BitFieldExtractI32(SMask, 1, FoundBitIndex); // -1: true, 0: false\n\n\t\tconst uint FoundPrevBitsMask = (1u << FoundBitIndex) - 1u;\n\t\tint FoundCurrentDwordNumPrevRefVertices = (countbits(SLMask & FoundPrevBitsMask) << 1) + countbits(WMask & FoundPrevBitsMask);\n\t\tint FoundCurrentDwordNumPrevNewVertices = (countbits(SMask & FoundPrevBitsMask) << 1) + FoundBitIndex - FoundCurrentDwordNumPrevRefVertices;\n\n\t\tint FoundNumPrevNewVertices = NumPrevNewVerticesBeforeDword + FoundCurrentDwordNumPrevNewVertices;\n\t\tint FoundNumPrevRefVertices = NumPrevRefVerticesBeforeDword + FoundCurrentDwordNumPrevRefVertices;\n\n\t\tconst uint FoundNumRefVertices = (BitFieldExtractU32(LMask, 1, FoundBitIndex) << 1) + BitFieldExtractU32(WMask, 1, FoundBitIndex);\n\t\tconst uint IsBeforeFoundRefVertex = BitFieldExtractU32(HeadRefVertexMask, 1, FoundBitIndex - 1);\n\n\t\t// ReadOffset: Where is the vertex relative to triangle we searched for?\n\t\tconst int ReadOffset = IsFoundCaseS ? IsLeft : 1;\n\t\tconst uint FoundIndexData = ReadUnalignedDword(SrcPageBuffer, ReadBaseAddress, (FoundNumPrevRefVertices - ReadOffset) * 5);\n\t\tconst uint FoundIndex = (FoundNumPrevNewVertices - 1u) - BitFieldExtractU32(FoundIndexData, 5, 0);\n\n\t\tbool bCondition = IsFoundCaseS ? ((int) FoundNumRefVertices >= 1 - IsLeft) : IsBeforeFoundRefVertex;\n\t\tint FoundNewVertex = FoundNumPrevNewVertices + (IsFoundCaseS ? (IsLeft & (FoundNumRefVertices == 0)) : -1);\n\t\tOutIndices.x = bCondition ? FoundIndex : FoundNewVertex;\n\n\t\t// Would it be better to code New verts instead of Ref verts?\n\t\t// HeadRefVertexMask would just be WMask?\n\n\t\tif (IsLeft)\n\t\t{\n\t\t\tOutIndices.yz = OutIndices.zy;\n\t\t}\n\t}\n\n\treturn OutIndices;\n}\n\n#define TRANSCODE_THREADS_PER_GROUP_BITS\t7\n#define TRANSCODE_THREADS_PER_GROUP\t\t\t(1 << TRANSCODE_THREADS_PER_GROUP_BITS)\n#define TRANSCODE_THREADS_PER_PAGE\t\t\t(VG_MAX_TRANSCODE_GROUPS_PER_PAGE << TRANSCODE_THREADS_PER_GROUP_BITS)\n\nvoid TranscodeVertexAttributes(VG_PAGE_DISK_HEADER PageDiskHeader, VG_CLUSTER Cluster, uint DstPageBaseOffset, uint LocalClusterIndex, uint VertexIndex,\n\t\t\t\t\t\t\t\tVG_CLUSTER SrcCluster, VG_CLUSTER_DISK_HEADER SrcClusterDiskHeader, uint SrcPageBaseOffset, uint SrcLocalClusterIndex, uint SrcCodedVertexIndex,\n\t\t\t\t\t\t\t\tbool bIsParentRef, uint ParentGPUPageIndex,\n\t\t\t\t\t\t\t\tuint CompileTimeNumTexCoords\n)\n{\n\tconst uint CompileTimeMaxVertexBits = \n\t\t2 * VG_NORMAL_QUANTIZATION_BITS + \n\t\t4 * VG_MAX_COLOR_QUANTIZATION_BITS + \n\t\t(CompileTimeNumTexCoords * 2 * VG_MAX_TEXCOORD_QUANTIZATION_BITS);\n\n\tconst uint BaseAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages);\n\n\tconst uint BitsPerAttribute = bIsParentRef ? SrcCluster.BitsPerAttribute : ((SrcCluster.BitsPerAttribute + 7) & ~7u);\n\tconst uint Address = bIsParentRef ? (BaseAddress + SrcCluster.AttributeOffset) : (SrcPageBaseOffset + SrcClusterDiskHeader.AttributeDataOffset);\n\n\tFBitStreamWriterState OutputStream = BitStreamWriter_Create_Aligned(DstPageBaseOffset + Cluster.AttributeOffset, VertexIndex * Cluster.BitsPerAttribute);\n\tFBitStreamReaderState InputStream = BitStreamReader_Create(Address, SrcCodedVertexIndex * BitsPerAttribute, CompileTimeMaxVertexBits);\n\n\t// Normal\n\tuint PackedNormal = BitStreamReader_Read_RORW(SrcPageBuffer, DstPageBuffer, bIsParentRef, InputStream, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, PackedNormal, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\n\t// Color\n\t{\n\t\tuint4 SrcComponentBits = UnpackToUint4(SrcCluster.ColorBits, 4);\n\t\tuint4 SrcColorDelta = BitStreamReader_Read4_RORW(SrcPageBuffer, DstPageBuffer, bIsParentRef, InputStream, SrcComponentBits, 8);\n\n\t\tif (Cluster.ColorMode == VG_VERTEX_COLOR_MODE_VARIABLE)\n\t\t{\n\t\t\tuint SrcPackedColorDelta = SrcColorDelta.x | (SrcColorDelta.y << 8) | (SrcColorDelta.z << 16) | (SrcColorDelta.w << 24);\n\t\t\tuint PackedColor = SrcCluster.ColorMin + SrcPackedColorDelta;\n\n\t\t\tuint4 DstComponentBits = UnpackToUint4(Cluster.ColorBits, 4);\n\t\t\tuint DstPackedColorDelta = PackedColor - Cluster.ColorMin;\n\n\t\t\tuint PackedDeltaColor = BitFieldExtractU32(DstPackedColorDelta, 8, 0 ) |\n\t\t\t\t\t\t\t\t   (BitFieldExtractU32(DstPackedColorDelta, 8, 8 ) << (DstComponentBits.x)) |\n\t\t\t\t\t\t\t\t   (BitFieldExtractU32(DstPackedColorDelta, 8, 16) << (DstComponentBits.x + DstComponentBits.y)) |\n\t\t\t\t\t\t\t\t   (BitFieldExtractU32(DstPackedColorDelta, 8, 24) << (DstComponentBits.x + DstComponentBits.y + DstComponentBits.z));\n\n\t\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, PackedDeltaColor, DstComponentBits.x + DstComponentBits.y + DstComponentBits.z + DstComponentBits.w, 4 * VG_MAX_COLOR_QUANTIZATION_BITS);\n\t\t}\n\t}\n\n\t// UVs\n\t[unroll(VG_MAX_UVS)]\n\tfor (uint TexCoordIndex = 0; TexCoordIndex < CompileTimeNumTexCoords; TexCoordIndex++)\n\t{\n\t\tconst uint SrcU_NumBits = BitFieldExtractU32(SrcCluster.UV_Prec, 4, TexCoordIndex * 8 + 0);\n\t\tconst uint SrcV_NumBits = BitFieldExtractU32(SrcCluster.UV_Prec, 4, TexCoordIndex * 8 + 4);\n\n\t\tconst uint DstU_NumBits = BitFieldExtractU32(Cluster.UV_Prec, 4, TexCoordIndex * 8 + 0);\n\t\tconst uint DstV_NumBits = BitFieldExtractU32(Cluster.UV_Prec, 4, TexCoordIndex * 8 + 4);\n\n\t\tconst int2 SrcPackedUV = BitStreamReader_Read2_RORW(SrcPageBuffer, DstPageBuffer, bIsParentRef, InputStream, int2(SrcU_NumBits, SrcV_NumBits), VG_MAX_TEXCOORD_QUANTIZATION_BITS);\n\t\t\n\t\tVG_UV_RANGE SrcUVRange;\n\t\tif (bIsParentRef)\n\t\t\tSrcUVRange = GetUVRange(DstPageBuffer, BaseAddress + SrcCluster.DecodeInfoOffset, TexCoordIndex);\n\t\telse\n\t\t\tSrcUVRange = GetUVRange(SrcPageBuffer, SrcPageBaseOffset + PageDiskHeader.DecodeInfoOffset + SrcLocalClusterIndex * CompileTimeNumTexCoords * 32, TexCoordIndex);\n\n\t\tconst VG_UV_RANGE UVRange = GetUVRange(SrcPageBuffer, SrcPageBaseOffset + PageDiskHeader.DecodeInfoOffset + LocalClusterIndex * CompileTimeNumTexCoords * 32, TexCoordIndex);\n\t\t\n\t\tconst float Scale = asfloat(asint(1.0f) + ((UVRange.Precision - SrcUVRange.Precision) << 23));\n\t\tconst int2 SrcUV = SrcPackedUV + select((SrcPackedUV > (int2)SrcUVRange.GapStart), SrcUVRange.GapLength, 0u) + SrcUVRange.Min;\n\t\tint2 DstUV = int2(round(SrcUV * Scale));\n\t\tuint2 DstPackedUV = (uint2) max(DstUV - UVRange.Min, 0);\n\n\t\tconst uint2 GapMid = UVRange.GapStart + (UVRange.GapLength >> 1);\n\t\tconst bool2 bOverMid = DstPackedUV > GapMid;\n\t\t\n\t\tconst uint2 RangeMin = select(bOverMid, (UVRange.GapStart + 1u), 0u);\n\t\tconst uint2 RangeMax = select(bOverMid, uint2(BitFieldMaskU32(DstU_NumBits, 0), BitFieldMaskU32(DstV_NumBits, 0)), UVRange.GapStart);\n\t\tDstPackedUV = select(bOverMid, (DstPackedUV - UVRange.GapLength), DstPackedUV);\n\t\tDstPackedUV = clamp(DstPackedUV, RangeMin, RangeMax);\n\t\t\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, (DstPackedUV.y << DstU_NumBits) | DstPackedUV.x, DstU_NumBits + DstV_NumBits, 2 * VG_MAX_TEXCOORD_QUANTIZATION_BITS);\n\t}\n\n\tBitStreamWriter_Flush(DstPageBuffer, OutputStream);\n}\n\nvoid TranscodeVertexSkinData(VG_PAGE_DISK_HEADER PageDiskHeader, VG_CLUSTER Cluster, uint DstPageBaseOffset, uint LocalClusterIndex, uint VertexIndex,\n\t\t\t\t\t\t\t\tVG_CLUSTER SrcCluster, VG_CLUSTER_DISK_HEADER SrcClusterDiskHeader, uint SrcPageBaseOffset, uint SrcLocalClusterIndex, uint SrcCodedVertexIndex,\n\t\t\t\t\t\t\t\tbool bIsParentRef, uint ParentGPUPageIndex\n)\n{\n    const uint CompileTimeMaxVertexBits = GetSkinCompileTimeMatrixRemainingBits();\n    const uint BaseAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages);\n    const uint BitsPerVertex = bIsParentRef ? CompileTimeMaxVertexBits : ((CompileTimeMaxVertexBits + 7) & ~7u);\n    const uint Address = bIsParentRef ? (BaseAddress + SrcCluster.SkinOrSrtOffset) : (SrcPageBaseOffset + SrcClusterDiskHeader.SkinOrSrtDataOffset);\n\n    FBitStreamWriterState OutputStream = BitStreamWriter_Create_Aligned(DstPageBaseOffset + Cluster.SkinOrSrtOffset, VertexIndex * CompileTimeMaxVertexBits);\n    FBitStreamReaderState InputStream = BitStreamReader_Create(Address, SrcCodedVertexIndex * BitsPerVertex, CompileTimeMaxVertexBits);\n\n    uint4 BoneIndex = BitStreamReader_Read4_RORW(SrcPageBuffer, DstPageBuffer, bIsParentRef, InputStream, VG_MAX_BONE_INDEX_QUANTIZATION_BITS, VG_MAX_BONE_INDEX_QUANTIZATION_BITS);\n    uint3 BoneWeight = BitStreamReader_Read3_RORW(SrcPageBuffer, DstPageBuffer, bIsParentRef, InputStream, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS);\n\n    // Bone index\n    {\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneIndex.x, VG_MAX_BONE_INDEX_QUANTIZATION_BITS, VG_MAX_BONE_INDEX_QUANTIZATION_BITS);\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneIndex.y, VG_MAX_BONE_INDEX_QUANTIZATION_BITS, VG_MAX_BONE_INDEX_QUANTIZATION_BITS);\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneIndex.z, VG_MAX_BONE_INDEX_QUANTIZATION_BITS, VG_MAX_BONE_INDEX_QUANTIZATION_BITS);\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneIndex.w, VG_MAX_BONE_INDEX_QUANTIZATION_BITS, VG_MAX_BONE_INDEX_QUANTIZATION_BITS);\n    }\n\n    // Bone weight\n    {\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneWeight.x, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS);\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneWeight.y, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS);\n        BitStreamWriter_Writer(DstPageBuffer, OutputStream, BoneWeight.z, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS, VG_MAX_BONE_WEIGHT_QUANTIZATION_BITS);\n    }\n\n    BitStreamWriter_Flush(DstPageBuffer, OutputStream);\n}\n\nvoid TranscodeVertexSrtData(VG_PAGE_DISK_HEADER PageDiskHeader, VG_CLUSTER Cluster, uint DstPageBaseOffset, uint LocalClusterIndex, uint VertexIndex,\n\t\t\t\t\t\t\t\tVG_CLUSTER SrcCluster, VG_CLUSTER_DISK_HEADER SrcClusterDiskHeader, uint SrcPageBaseOffset, uint SrcLocalClusterIndex, uint SrcCodedVertexIndex,\n\t\t\t\t\t\t\t\tbool bIsParentRef, uint ParentGPUPageIndex\n)\n{\n\tconst uint CompileTimeMaxVertexBits =\n\t\t\t\t\tVG_MAX_SRT_BRANCH_WEIGHT_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_BRANCH_OFFSET_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_FROND_WEIGHT_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_LEAF_SCALE_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_LEAF_GROWTH_DIR_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_LEAF_RIPPLE_DIR_QUANTIZATION_BITS +\n\t\t\t\t\tVG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS * 2 +\n\t\t\t\t\tVG_MAX_SRT_LEAF_ANCHORY_QUANTIZATION_BITS;\n\t\t\t\t\n\tconst uint DstSrtVertBitsPerVertex =\n\t\t\t\t\tCluster.QuantizedSrtBranchWeightBits +\n\t\t\t\t\tCluster.QuantizedSrtBranchOffsetBits +\n\t\t\t\t\tCluster.QuantizedSrtFrondWeightBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafScaleBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafGrowthDirBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafRippleDirBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafAnchorBits.x + Cluster.QuantizedSrtLeafAnchorBits.y + Cluster.QuantizedSrtLeafAnchorBits.z;\n\n\tconst uint SrcSrtVertBitsPerVertex =\n\t\t\t\t\tSrcCluster.QuantizedSrtBranchWeightBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtBranchOffsetBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtFrondWeightBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtLeafScaleBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtLeafGrowthDirBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtLeafRippleDirBits +\n\t\t\t\t\tSrcCluster.QuantizedSrtLeafAnchorBits.x + SrcCluster.QuantizedSrtLeafAnchorBits.y + SrcCluster.QuantizedSrtLeafAnchorBits.z;\n\t  \n\t\n\tint SrcBranchWeight = 0;\n\tint SrcBranchOffset = 0;\n\tint SrcFrondWeight = 0;\n\tint SrcLeafScale = 0;\n\tint SrcLeafGrowthDir = 0;\n\tint SrcLeafRippleDir = 0;\n\tint3 SrcAnchorPosition = 0;\n\n\tif (bIsParentRef)\n\t{\n\t\tuint BaseAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages) + SrcCluster.SkinOrSrtOffset;\n\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * SrcSrtVertBitsPerVertex, CompileTimeMaxVertexBits);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtBranchWeightBits > 0)\n\t\t\tSrcBranchWeight = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtBranchWeightBits, VG_MAX_SRT_BRANCH_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtBranchOffsetBits > 0)\n\t\t\tSrcBranchOffset = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtBranchOffsetBits, VG_MAX_SRT_BRANCH_OFFSET_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtFrondWeightBits > 0)\n\t\t\tSrcFrondWeight = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtFrondWeightBits, VG_MAX_SRT_FROND_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafScaleBits > 0)\n\t\t\tSrcLeafScale = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafScaleBits, VG_MAX_SRT_LEAF_SCALE_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafGrowthDirBits > 0)\n\t\t\tSrcLeafGrowthDir = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafGrowthDirBits, VG_MAX_SRT_LEAF_GROWTH_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafRippleDirBits > 0)\n\t\t\tSrcLeafRippleDir = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafRippleDirBits, VG_MAX_SRT_LEAF_RIPPLE_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.x > 0)\n\t\t\tSrcAnchorPosition.x = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.x, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.y > 0)\n\t\t\tSrcAnchorPosition.y = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.y, VG_MAX_SRT_LEAF_ANCHORY_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.z > 0)\n\t\t\tSrcAnchorPosition.z = BitStreamReader_Read_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.z, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t}\n\telse\n\t{\n\t\tuint BaseAddress = SrcPageBaseOffset + SrcClusterDiskHeader.SkinOrSrtDataOffset;\n\t\tuint BitsPerVertex = (SrcSrtVertBitsPerVertex + 7) & ~7u;\n\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * BitsPerVertex, CompileTimeMaxVertexBits);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtBranchWeightBits > 0)\n\t\t\tSrcBranchWeight = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtBranchWeightBits, VG_MAX_SRT_BRANCH_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtBranchOffsetBits > 0)\n\t\t\tSrcBranchOffset = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtBranchOffsetBits, VG_MAX_SRT_BRANCH_OFFSET_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtFrondWeightBits > 0)\n\t\t\tSrcFrondWeight = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtFrondWeightBits, VG_MAX_SRT_FROND_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafScaleBits > 0)\n\t\t\tSrcLeafScale = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafScaleBits, VG_MAX_SRT_LEAF_SCALE_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafGrowthDirBits > 0)\n\t\t\tSrcLeafGrowthDir = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafGrowthDirBits, VG_MAX_SRT_LEAF_GROWTH_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafRippleDirBits > 0)\n\t\t\tSrcLeafRippleDir = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafRippleDirBits, VG_MAX_SRT_LEAF_RIPPLE_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.x > 0)\n\t\t\tSrcAnchorPosition.x = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.x, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.y > 0)\n\t\t\tSrcAnchorPosition.y = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.y, VG_MAX_SRT_LEAF_ANCHORY_QUANTIZATION_BITS);\n\t\t\t\t\t\n\t\tif (SrcCluster.QuantizedSrtLeafAnchorBits.z > 0)\n\t\t\tSrcAnchorPosition.z = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedSrtLeafAnchorBits.z, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t}\n\t\n\tint  DstBranchWeight    = SrcBranchWeight   + SrcCluster.QuantizedSrtBranchWeightStart  - Cluster.QuantizedSrtBranchWeightStart;\n\tint  DstBranchOffset    = SrcBranchOffset   + SrcCluster.QuantizedSrtBranchOffsetStart  - Cluster.QuantizedSrtBranchOffsetStart;\n\tint  DstFrondWeight     = SrcFrondWeight    + SrcCluster.QuantizedSrtFrondWeightStart   - Cluster.QuantizedSrtFrondWeightStart;\n\tint  DstLeafScale       = SrcLeafScale      + SrcCluster.QuantizedSrtLeafScaleStart     - Cluster.QuantizedSrtLeafScaleStart;\n\tint  DstLeafGrowthDir   = SrcLeafGrowthDir  + SrcCluster.QuantizedSrtLeafGrowthDirStart - Cluster.QuantizedSrtLeafGrowthDirStart;\n\tint  DstLeafRippleDir   = SrcLeafRippleDir  + SrcCluster.QuantizedSrtLeafRippleDirStart - Cluster.QuantizedSrtLeafRippleDirStart;\n\tint3 DstAnchorPosition  = SrcAnchorPosition + SrcCluster.QuantizedSrtLeafAnchorStart    - Cluster.QuantizedSrtLeafAnchorStart;\n\t\t\t\n\tFBitStreamWriterState OutputStream = BitStreamWriter_Create_Aligned(DstPageBaseOffset + Cluster.SkinOrSrtOffset, VertexIndex * DstSrtVertBitsPerVertex);\n\n\tif (Cluster.QuantizedSrtBranchWeightBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstBranchWeight, Cluster.QuantizedSrtBranchWeightBits, VG_MAX_SRT_BRANCH_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\n\tif (Cluster.QuantizedSrtBranchOffsetBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstBranchOffset, Cluster.QuantizedSrtBranchOffsetBits, VG_MAX_SRT_BRANCH_OFFSET_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtFrondWeightBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstFrondWeight, Cluster.QuantizedSrtFrondWeightBits, VG_MAX_SRT_FROND_WEIGHT_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafScaleBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstLeafScale, Cluster.QuantizedSrtLeafScaleBits, VG_MAX_SRT_LEAF_SCALE_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafGrowthDirBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstLeafGrowthDir, Cluster.QuantizedSrtLeafGrowthDirBits, VG_MAX_SRT_LEAF_GROWTH_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafRippleDirBits > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstLeafRippleDir, Cluster.QuantizedSrtLeafRippleDirBits, VG_MAX_SRT_LEAF_RIPPLE_DIR_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafAnchorBits.x > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstAnchorPosition.x, Cluster.QuantizedSrtLeafAnchorBits.x, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafAnchorBits.y > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstAnchorPosition.y, Cluster.QuantizedSrtLeafAnchorBits.y, VG_MAX_SRT_LEAF_ANCHORY_QUANTIZATION_BITS);\n\t\t\t\t\t\n\tif (Cluster.QuantizedSrtLeafAnchorBits.z > 0)\n\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstAnchorPosition.z, Cluster.QuantizedSrtLeafAnchorBits.z, VG_MAX_SRT_LEAF_ANCHORXZ_QUANTIZATION_BITS);\n\t\n\tBitStreamWriter_Flush(DstPageBuffer, OutputStream);\n}\n\nvoid TranscodeVertexFlexData(VG_PAGE_DISK_HEADER PageDiskHeader, VG_CLUSTER Cluster, uint DstPageBaseOffset, uint LocalClusterIndex, uint VertexIndex,\n\t\t\t\t\t\t\t\tVG_CLUSTER SrcCluster, VG_CLUSTER_DISK_HEADER SrcClusterDiskHeader, uint SrcPageBaseOffset, uint SrcLocalClusterIndex, uint SrcCodedVertexIndex,\n\t\t\t\t\t\t\t\tbool bIsParentRef, uint ParentGPUPageIndex\n)\n{\n\tconst uint CompileTimeMaxVertexBits = GetFlexCompileTimeMaxRemainingBits();\n\t\n\tconst uint DstVertBitsPerVertex = Cluster.BitsPerFlexData;\n\tconst uint SrcVertBitsPerVertex = SrcCluster.BitsPerFlexData;\n\t\n\tuint DriFaceIndexAndInvMass;\n\tuint2 DstDriBaryCoordDelta;\n\tint3 SrcRelativePositionDelta;\n\tuint NormalBits;\n\tuint TangentBits;\n\tuint TangentWBits;\n\n\tif (bIsParentRef)\n\t{\n\t\tuint BaseAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages) + SrcCluster.FlexDataOffset;\n\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * SrcVertBitsPerVertex, CompileTimeMaxVertexBits);\n\t\t\n\t\tDriFaceIndexAndInvMass = BitStreamReader_Read_RW(DstPageBuffer, InputStream, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS);\n\t\tDstDriBaryCoordDelta = BitStreamReader_Read2_RW(DstPageBuffer, InputStream, VG_FLEX_DRI_BARY_COORD_BITS, VG_FLEX_DRI_BARY_COORD_BITS);\n\n\t\tSrcRelativePositionDelta = BitStreamReader_Read3_RW(DstPageBuffer, InputStream, SrcCluster.QuantizedFlexRelativePosBits, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\n\t\tNormalBits = BitStreamReader_Read_RW(DstPageBuffer, InputStream, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\t\tTangentBits = BitStreamReader_Read_RW(DstPageBuffer, InputStream, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\t\tTangentWBits = BitStreamReader_Read_RW(DstPageBuffer, InputStream, 1, 1);\n\t}\n\telse\n\t{\n\t\tuint BaseAddress = SrcPageBaseOffset + SrcClusterDiskHeader.FlexDataOffset;\n\t\tuint BitsPerVertex = (SrcVertBitsPerVertex + 7) & ~7u;\n\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * BitsPerVertex, CompileTimeMaxVertexBits);\n\t\t\t\t\t\n\t\tDriFaceIndexAndInvMass = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS);\n\t\tDstDriBaryCoordDelta = BitStreamReader_Read2_RO(SrcPageBuffer, InputStream, VG_FLEX_DRI_BARY_COORD_BITS, VG_FLEX_DRI_BARY_COORD_BITS);\n\n\t\tSrcRelativePositionDelta = BitStreamReader_Read3_RO(SrcPageBuffer, InputStream, SrcCluster.QuantizedFlexRelativePosBits, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\n\t\tNormalBits = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\t\tTangentBits = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\t\tTangentWBits = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, 1, 1);\n\t}\n\n\tFBitStreamWriterState OutputStream = BitStreamWriter_Create_Aligned(DstPageBaseOffset + Cluster.FlexDataOffset, VertexIndex * DstVertBitsPerVertex);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DriFaceIndexAndInvMass, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS, VG_FLEX_DRI_FACE_INDEX_AND_INVMASS_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstDriBaryCoordDelta.x, VG_FLEX_DRI_BARY_COORD_BITS, VG_FLEX_DRI_BARY_COORD_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstDriBaryCoordDelta.y, VG_FLEX_DRI_BARY_COORD_BITS, VG_FLEX_DRI_BARY_COORD_BITS);\n\t\n\tint3 DstRelativePositionDelta = SrcRelativePositionDelta + SrcCluster.QuantizedFlexRelativePosStart - Cluster.QuantizedFlexRelativePosStart;\n\t\t\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstRelativePositionDelta.x, Cluster.QuantizedFlexRelativePosBits.x, VG_MAX_POSITION_QUANTIZATION_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstRelativePositionDelta.y, Cluster.QuantizedFlexRelativePosBits.y, VG_MAX_POSITION_QUANTIZATION_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstRelativePositionDelta.z, Cluster.QuantizedFlexRelativePosBits.z, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, NormalBits, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, TangentBits, 2 * VG_NORMAL_QUANTIZATION_BITS, 2 * VG_NORMAL_QUANTIZATION_BITS);\n\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, TangentWBits, 1, 1);\n\n\tBitStreamWriter_Flush(DstPageBuffer, OutputStream);\n}\n\n\ngroupshared uint GroupNumRefsInPrevDwords8888[2]; // Packed byte counts: 8:8:8:8\ngroupshared uint GroupRefToVertex[VG_MAX_CLUSTER_VERTICES];\ngroupshared uint GroupNonRefToVertex[VG_MAX_CLUSTER_VERTICES];\n\n\n[numthreads(TRANSCODE_THREADS_PER_GROUP, 1, 1)]\nvoid TranscodePageToGPU(uint2 GroupID : SV_GroupID,\n\t\t\t\t\t\tuint GroupIndex : SV_GroupIndex)\n{\n\tuint LocalPageIndex = StartPageIndex + GroupID.y;\n\n\tVG_PAGE_INSTALL_INFO InstallInfo = InstallInfoBuffer[LocalPageIndex];\n\tuint SrcPageBaseOffset = InstallInfo.SrcPageOffset;\n\tuint DstPageBaseOffset = InstallInfo.DstPageOffset;\n\t\n\tVG_PAGE_DISK_HEADER PageDiskHeader = GetPageDiskHeader(SrcPageBaseOffset);\n\n\tconst uint NumTexCoords = PageDiskHeader.NumTexCoords;\n\tconst bool bHasSkinData = PageDiskHeader.HasSkinBones;\n\tconst bool bHasSpeedTree = PageDiskHeader.HasSpeedTree;\n\tconst bool bHasFlexData = PageDiskHeader.HasFlexData;\n\tuint SrcPackedClusterOffset = SrcPageBaseOffset + VG_PAGE_DISK_HEADER_SIZE + PageDiskHeader.NumClusters * VG_CLUSTER_DISK_HEADER_SIZE;\n\tuint DstPackedClusterOffset = DstPageBaseOffset;\n\n\tuint NumRawFloat4s = PageDiskHeader.NumRawFloat4s;\n\tuint PageThread = (GroupID.x << TRANSCODE_THREADS_PER_GROUP_BITS) | GroupIndex;\n\n\t// Raw copy: FPackedClusters, Material Dwords and DecodeInfo.\n\tfor (uint i = PageThread; i < NumRawFloat4s; i += TRANSCODE_THREADS_PER_PAGE)\n\t{\n\t\tuint4 Data = SrcPageBuffer.Load4(SrcPackedClusterOffset + i * 16);\n\t\tDstPageBuffer.Store4(DstPackedClusterOffset + i * 16, Data);\n\t}\n\n\tfor (uint LocalClusterIndex = GroupID.x; LocalClusterIndex < PageDiskHeader.NumClusters; LocalClusterIndex += VG_MAX_TRANSCODE_GROUPS_PER_PAGE)\n\t{\n\t\tVG_CLUSTER_DISK_HEADER ClusterDiskHeader = GetClusterDiskHeader(SrcPageBaseOffset, LocalClusterIndex);\n\t\tVG_CLUSTER Cluster = GetCluster(SrcPageBuffer, SrcPackedClusterOffset, LocalClusterIndex, PageDiskHeader.NumClusters);\n\t\t\n\t\t// Decode indices\n\t\tif (GroupIndex < Cluster.NumTris)\n\t\t{\n\t\t\tuint TriangleIndex = GroupIndex;\n#if VG_USE_STRIP_INDICES\n\t\t\tuint3 Indices = UnpackStripIndices(SrcPageBaseOffset, PageDiskHeader, ClusterDiskHeader, LocalClusterIndex, TriangleIndex);\n#else\n\t\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(SrcPageBaseOffset + ClusterDiskHeader.IndexDataOffset, TriangleIndex * 24, 24);\n\t\t\tuint Indices24 = BitStreamReader_Read_RO(SrcPageBuffer, InputStream, 24, 24);\n\t\t\tuint3 Indices = uint3(Indices24 & 0xFF, (Indices24 >> 8) & 0xFF, (Indices24 >> 16) & 0xFF);\n#endif\n\t\t\t// Rotate triangle so first vertex has the lowest index\n\t\t\tif (Indices.y < min(Indices.x, Indices.z))\n\t\t\t\tIndices = Indices.yzx;\n\t\t\telse if (Indices.z < min(Indices.x, Indices.y))\n\t\t\t\tIndices = Indices.zxy;\n\n\t\t\t// Store triangle as one base index and two 5-bit offsets. Cluster constraints guarantee that the offsets are never larger than 5 bits.\n\t\t\tuint BaseIndex = Indices.x;\n\t\t\tuint Delta0 = Indices.y - BaseIndex;\n\t\t\tuint Delta1 = Indices.z - BaseIndex;\n\n\t\t\tuint PackedIndices = BaseIndex | (Delta0 << Cluster.BitsPerIndex) | (Delta1 << (Cluster.BitsPerIndex + 5));\n\t\t\tconst uint BitsPerTriangle = Cluster.BitsPerIndex + 2 * 5;\n\n\t\t\tPutBits(DstPageBuffer, DstPageBaseOffset + Cluster.IndexOffset, TriangleIndex * BitsPerTriangle, PackedIndices, BitsPerTriangle);\n\t\t}\n\n\t\t// Calculate dword-based prefix sum of ref bitmask\n\t\t// TODO: optimize me\n\t\tconst uint AlignedBitmaskOffset = SrcPageBaseOffset + PageDiskHeader.VertexRefBitmaskOffset + LocalClusterIndex * (VG_MAX_CLUSTER_VERTICES / 8);\n\t\tGroupMemoryBarrierWithGroupSync();\n\t\tif (GroupIndex < 2)\n\t\t\tGroupNumRefsInPrevDwords8888[GroupIndex] = 0;\n\t\tGroupMemoryBarrierWithGroupSync();\n\t\tif (GroupIndex < 7)\n\t\t{\n\t\t\tconst uint Count = countbits(SrcPageBuffer.Load(AlignedBitmaskOffset + GroupIndex * 4));\n\t\t\tconst uint Count8888 = Count * 0x01010101u; // Broadcast count to all bytes\n\t\t\tconst uint Index = GroupIndex + 1;\n\t\t\tInterlockedAdd(GroupNumRefsInPrevDwords8888[Index >> 2], Count8888 << ((Index & 3) << 3)); // Add to bytes above\n\t\t\tif (Cluster.NumVerts > 128 && Index < 4)\n\t\t\t{\n\t\t\t\t// Add low dword byte counts to all bytes in high dword when there are more than 128 vertices.\n\t\t\t\tInterlockedAdd(GroupNumRefsInPrevDwords8888[1], Count8888);\n\t\t\t}\n\t\t}\n\t\tGroupMemoryBarrierWithGroupSync();\n\n\t\tfor (uint VertexIndex = GroupIndex; VertexIndex < Cluster.NumVerts; VertexIndex += TRANSCODE_THREADS_PER_GROUP)\n\t\t{\n\t\t\tconst uint DwordIndex = VertexIndex >> 5;\n\t\t\tconst uint BitIndex = VertexIndex & 31u;\n\t\t\t\n\t\t\tconst uint Shift = ((DwordIndex & 3) << 3);\n\t\t\tconst uint NumRefsInPrevDwords = (GroupNumRefsInPrevDwords8888[DwordIndex >> 2] >> Shift) & 0xFF;\n\n\t\t\tconst uint DwordMask = SrcPageBuffer.Load(AlignedBitmaskOffset + DwordIndex * 4);\n\t\t\tconst uint NumPrevRefVertices = countbits(BitFieldExtractU32(DwordMask, BitIndex, 0)) + NumRefsInPrevDwords;\n\n\t\t\tconst bool bIsRef = (DwordMask & (1u << BitIndex)) != 0u;\n\t\t\tif (bIsRef)\n\t\t\t{\n\t\t\t\tGroupRefToVertex[NumPrevRefVertices] = VertexIndex;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst uint NumPrevNonRefVertices = VertexIndex - NumPrevRefVertices;\n\t\t\t\tGroupNonRefToVertex[NumPrevNonRefVertices] = VertexIndex;\n\t\t\t}\n\t\t}\n\t\tGroupMemoryBarrierWithGroupSync();\n\n\t\t// Non-Ref vertices\n\t\tconst uint NumNonRefVertices = Cluster.NumVerts - ClusterDiskHeader.NumVertexRefs;\n\t\tfor (uint NonRefVertexIndex = GroupIndex; NonRefVertexIndex < NumNonRefVertices; NonRefVertexIndex += TRANSCODE_THREADS_PER_GROUP)\n\t\t{\n\t\t\tconst uint VertexIndex = GroupNonRefToVertex[NonRefVertexIndex];\n\n\t\t\t// Position\n\t\t\tconst uint PositionBitsPerVertex = Cluster.PosBits.x + Cluster.PosBits.y + Cluster.PosBits.z;\n\t\t\tconst uint SrcPositionBitsPerVertex = (PositionBitsPerVertex + 7) & ~7u;\n\t\t\tCopyBits(DstPageBuffer, DstPageBaseOffset + Cluster.PositionOffset, VertexIndex * PositionBitsPerVertex,\n\t\t\t\t\t\tSrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.PositionDataOffset, NonRefVertexIndex * SrcPositionBitsPerVertex, PositionBitsPerVertex);\n\t\t\t\n\t\t\t// Attributes\n\t\t\tconst uint SrcBitsPerAttribute = ((Cluster.BitsPerAttribute + 7) & ~7u);\n\t\t\tCopyBits(DstPageBuffer, DstPageBaseOffset + Cluster.AttributeOffset, VertexIndex * Cluster.BitsPerAttribute,\n\t\t\t\t\t\tSrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.AttributeDataOffset, NonRefVertexIndex * SrcBitsPerAttribute, Cluster.BitsPerAttribute);\n\n\t\t\t\n\t\t\tif (bHasSpeedTree && Cluster.SkinOrSrtOffset != 0)\n\t\t\t{\n\t\t\t\tconst uint SrtVertBitsPerVertex =\n\t\t\t\t\tCluster.QuantizedSrtBranchWeightBits +\n\t\t\t\t\tCluster.QuantizedSrtBranchOffsetBits +\n\t\t\t\t\tCluster.QuantizedSrtFrondWeightBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafScaleBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafGrowthDirBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafRippleDirBits +\n\t\t\t\t\tCluster.QuantizedSrtLeafAnchorBits.x + Cluster.QuantizedSrtLeafAnchorBits.y + Cluster.QuantizedSrtLeafAnchorBits.z;\n\n\t\t\t\tconst uint SrcSrtVertBitsPerVertex = (SrtVertBitsPerVertex + 7) & ~7u;\n\t\t\t\tCopyBits(DstPageBuffer, DstPageBaseOffset + Cluster.SkinOrSrtOffset, VertexIndex * SrtVertBitsPerVertex,\n\t\t\t\t\t\tSrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.SkinOrSrtDataOffset, NonRefVertexIndex * SrcSrtVertBitsPerVertex, SrtVertBitsPerVertex);\n\t\t\t}\n\t\t\t\n\t\t\tif (bHasSkinData && Cluster.SkinOrSrtOffset != 0)\n            {\n                const uint SkinVertBitsPerVertex = GetSkinCompileTimeMatrixRemainingBits();\n\t\t\t\tconst uint SrcSkinVertBitsPerVertex = (SkinVertBitsPerVertex + 7) & ~7u;\n\t\t\t\t\n\t\t\t\tCopyBits(DstPageBuffer, DstPageBaseOffset + Cluster.SkinOrSrtOffset, VertexIndex * SkinVertBitsPerVertex,\n\t\t\t\t\t\tSrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.SkinOrSrtDataOffset, NonRefVertexIndex * SrcSkinVertBitsPerVertex, SkinVertBitsPerVertex);\n\t\t\t}\n\n\t\t\tif (bHasFlexData && Cluster.FlexDataOffset != 0)\n\t\t\t{\n\t\t\t\tconst uint SrcFlexVertBitsPerVertex = (Cluster.BitsPerFlexData + 7) & ~7u;\n\t\t\t\t\n\t\t\t\tCopyBits(DstPageBuffer, DstPageBaseOffset + Cluster.FlexDataOffset, VertexIndex * Cluster.BitsPerFlexData,\n\t\t\t\t\t\tSrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.FlexDataOffset, NonRefVertexIndex * SrcFlexVertBitsPerVertex, Cluster.BitsPerFlexData);\n\t\t\t}\n\t\t}\n\t\n\t\t// Ref vertices\n\t\tfor (uint RefVertexIndex = GroupIndex; RefVertexIndex < ClusterDiskHeader.NumVertexRefs; RefVertexIndex += TRANSCODE_THREADS_PER_GROUP)\n\t\t{\n\t\t\tconst uint VertexIndex = GroupRefToVertex[RefVertexIndex];\n\t\t\tconst uint PageClusterIndex = ReadByte(SrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.VertexRefDataOffset + RefVertexIndex);\n\t\t\tconst uint PageClusterData = SrcPageBuffer.Load(SrcPageBaseOffset + ClusterDiskHeader.PageClusterMapOffset + PageClusterIndex * 4);\n\n\t\t\tuint ParentPageIndex = PageClusterData >> VG_MAX_CLUSTERS_PER_PAGE_BITS;\n\t\t\tuint SrcLocalClusterIndex = BitFieldExtractU32(PageClusterData, VG_MAX_CLUSTERS_PER_PAGE_BITS, 0);\n\t\t\tuint SrcCodedVertexIndex = ReadByte(SrcPageBuffer, SrcPageBaseOffset + ClusterDiskHeader.VertexRefDataOffset + RefVertexIndex + PageDiskHeader.NumVertexRefs);\n\n\t\t\tVG_CLUSTER_DISK_HEADER SrcClusterDiskHeader = GetClusterDiskHeader(SrcPageBaseOffset, SrcLocalClusterIndex);\n\t\t\tVG_CLUSTER SrcCluster;\n\t\t\tuint ParentGPUPageIndex = 0;\n\t\t\t\n\t\t\tconst bool bIsParentRef = (ParentPageIndex != 0);\n\t\t\tif (bIsParentRef)\n\t\t\t{\n\t\t\t\tParentGPUPageIndex = PageDependenciesBuffer[InstallInfo.PageDependenciesStart + (ParentPageIndex - 1)];\n\t\t\t\tuint ParentPageAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages);\n\t\t\t\tVG_PAGE_HEADER ParentPageHeader = GetPageHeader(DstPageBuffer, ParentPageAddress);\n\t\t\t\tSrcCluster = GetCluster(DstPageBuffer, ParentPageAddress, SrcLocalClusterIndex, ParentPageHeader.NumClusters);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSrcCluster = GetCluster(SrcPageBuffer, SrcPackedClusterOffset, SrcLocalClusterIndex, PageDiskHeader.NumClusters);\n\t\t\t}\n\t\t\t\n\t\t\t// Transcode position \n\t\t\t{\n\t\t\t\tint3 SrcPosition;\n\t\t\t\tif (bIsParentRef)\n\t\t\t\t{\n\t\t\t\t\tuint BaseAddress = GPUPageIndexToGPUOffset(ParentGPUPageIndex, MaxPages) + SrcCluster.PositionOffset;\n\t\t\t\t\tuint SrcPositionBitsPerVertex = SrcCluster.PosBits.x + SrcCluster.PosBits.y + SrcCluster.PosBits.z;\n\t\t\t\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * SrcPositionBitsPerVertex, 3 * VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\t\tSrcPosition = BitStreamReader_Read3_RW(DstPageBuffer, InputStream, SrcCluster.PosBits, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuint BaseAddress = SrcPageBaseOffset + SrcClusterDiskHeader.PositionDataOffset;\n\t\t\t\t\tuint SrcPositionBitsPerVertex = (SrcCluster.PosBits.x + SrcCluster.PosBits.y + SrcCluster.PosBits.z + 7) & ~7u;\n\t\t\t\t\tFBitStreamReaderState InputStream = BitStreamReader_Create(BaseAddress, SrcCodedVertexIndex * SrcPositionBitsPerVertex, 3 * VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\t\tSrcPosition = BitStreamReader_Read3_RO(SrcPageBuffer, InputStream, SrcCluster.PosBits, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\t}\n\n\t\t\t\tint3 DstPosition = SrcPosition + SrcCluster.PosStart - Cluster.PosStart;\n\t\t\t\tconst uint PositionBitsPerVertex = Cluster.PosBits.x + Cluster.PosBits.y + Cluster.PosBits.z;\n\t\t\t\t\n\t\t\t\tFBitStreamWriterState OutputStream = BitStreamWriter_Create_Aligned(DstPageBaseOffset + Cluster.PositionOffset, VertexIndex * PositionBitsPerVertex);\n\t\t\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstPosition.x, Cluster.PosBits.x, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstPosition.y, Cluster.PosBits.y, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\tBitStreamWriter_Writer(DstPageBuffer, OutputStream, DstPosition.z, Cluster.PosBits.z, VG_MAX_POSITION_QUANTIZATION_BITS);\n\t\t\t\tBitStreamWriter_Flush(DstPageBuffer, OutputStream);\n\t\t\t}\n\n\t\t\t// Specialize vertex transcoding codegen for each of the possible values for NumTexCoords\n\t\t\tif (NumTexCoords == 0)\n\t\t\t{\n\t\t\t\tTranscodeVertexAttributes(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex, 0);\n\t\t\t}\n\t\t\telse if (NumTexCoords == 1)\n\t\t\t{\n\t\t\t\tTranscodeVertexAttributes(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex, 1);\n\t\t\t}\n\t\t\telse if (NumTexCoords == 2)\n\t\t\t{\n\t\t\t\tTranscodeVertexAttributes(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex, 2);\n\t\t\t}\n\t\t\telse if (NumTexCoords == 3)\n\t\t\t{\n\t\t\t\tTranscodeVertexAttributes(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex, 3);\n\t\t\t}\n\t\t\telse if (NumTexCoords == 4)\n\t\t\t{\n\t\t\t\tTranscodeVertexAttributes(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex, 4);\n\t\t\t}\n\t\t\t\n\t\t\t// Transcode srt data\n\t\t\tif (bHasSpeedTree && Cluster.SkinOrSrtOffset != 0)\n\t\t\t{\n\t\t\t\tTranscodeVertexSrtData(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex);\n\t\t\t}\n\t\t\t\n\t\t\t// Transcode skin data\n\t\t\tif (bHasSkinData && Cluster.SkinOrSrtOffset != 0)\n\t\t\t{\n\t\t\t\tTranscodeVertexSkinData(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex);\n\t\t\t}\n\t\t\t\n\t\t\t// Transcode flex data\n\t\t\tif (bHasFlexData && Cluster.FlexDataOffset != 0)\n\t\t\t{\n\t\t\t\tTranscodeVertexFlexData(PageDiskHeader, Cluster, DstPageBaseOffset, LocalClusterIndex, VertexIndex,\n\t\t\t\t\tSrcCluster, SrcClusterDiskHeader, SrcPageBaseOffset, SrcLocalClusterIndex, SrcCodedVertexIndex, bIsParentRef, ParentGPUPageIndex);\n\t\t\t}\n\t\t}\n\t}\n}\n"
