#version 330

layout(std140) uniform VirtualTextureMappingData
{
    ivec4 mipOffsets;
    uvec2 virtualTextureSize;
    uvec2 physicalTextureSize;
    uint logTileSize;
    uint tileSize;
    uint tileBorder;
    float rcpTileSize;
    vec2 physicalPixelTexCoordSize;
    vec2 physicalTileTexCoordSize;
    vec2 physicalInnerTileTexCoordSize;
    vec2 tileBorderTexCoordSize;
} _95;

uniform sampler2D tex;
uniform usamplerBuffer TexturePageTable;

layout(location = 0) out vec4 fragColor;
in vec2 vUV;
in vec4 vTint;

int derpMipMapLevel(vec2 uv)
{
    vec2 dx_vtc = dFdx(uv);
    vec2 dy_vtc = dFdy(uv);
    float scaleSqr = min(dx_vtc.x * dx_vtc.x, dy_vtc.y * dy_vtc.y);
    return int(scaleSqr);
}

float rcp_power_of_two(uint p)
{
    return uintBitsToFloat((127u - p) << uint(23));
}

vec4 virtualTexture(sampler2D physicalTexture, usamplerBuffer pageTable, vec2 texCoord)
{
    vec2 param = texCoord;
    int derpMip = derpMipMapLevel(param);
    int _76;
    if (derpMip < 4)
    {
        _76 = 0;
    }
    else
    {
        _76 = (derpMip < 16) ? 1 : 2;
    }
    uint mipLevel = uint(_76);
    vec2 uv = texCoord * _95.rcpTileSize;
    int pageMipLevelOffset = _95.mipOffsets[mipLevel];
    float virtualTextureRowLenght = float(_95.virtualTextureSize.x >> (_95.logTileSize + mipLevel));
    uint param_1 = mipLevel;
    vec2 virtualPage = floor(uv * rcp_power_of_two(param_1));
    int pageID = pageMipLevelOffset + int(virtualPage.x + (virtualPage.y * virtualTextureRowLenght));
    uvec4 physicalTilePageData = texelFetch(pageTable, pageID);
    uvec2 physicalPage = physicalTilePageData.xy;
    mipLevel = physicalTilePageData.w;
    uint param_2 = mipLevel;
    vec2 offset = (fract(uv * rcp_power_of_two(param_2)) * _95.physicalInnerTileTexCoordSize) + _95.tileBorderTexCoordSize;
    vec2 physicalUV = (vec2(physicalPage) * _95.physicalTileTexCoordSize) + offset;
    return texture(physicalTexture, physicalUV);
}

void main()
{
    vec2 param = vUV;
    fragColor = virtualTexture(tex, TexturePageTable, param) * vTint;
}

