<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Float parsing corner cases</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
<script src="../../js/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fshaderParsedFloatOverflowToInfinity" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

void main()
{
    // Out-of-range floats should overflow to infinity
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "If the value of the floating point number is too large (small) to be stored as a single precision value, it is converted to positive (negative) infinity"
    float correct = isinf(1.0e40) ? 1.0 : 0.0;
    my_FragColor = vec4(0.0, correct, 0.0, 1.0);
}
</script>
<script id="fshaderParsedFloatUnderflowToZero" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

void main()
{
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "A value with a magnitude too small to be represented as a mantissa and exponent is converted to zero."
    // 1.0e-50 is small enough that it can't even be stored as subnormal.
    float correct = (1.0e-50 == 0.0) ? 1.0 : 0.0;
    my_FragColor = vec4(0.0, correct, 0.0, 1.0);
}
</script>
<script id="fshaderParsedFloatSmallMantissa" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

void main()
{
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "There is no limit on the number of digits in any digit-sequence."
    // The below float string has 100 zeros after the decimal point, but represents 1.0.
    float x = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e101;
    my_FragColor = vec4(0.0, x, 0.0, 1.0);
}
</script>
<script id="fshaderParsedFloatLargeMantissa" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

void main()
{
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "There is no limit on the number of digits in any digit-sequence."
    // The below float string has 100 zeros, but represents 1.0.
    float x = 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0e-100;
    my_FragColor = vec4(0.0, x, 0.0, 1.0);
}
</script>
<script id="fshaderParsedFloatExponentAboveMaxInt" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

void main()
{
    // Out-of-range floats should overflow to infinity
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "If the value of the floating point number is too large (small) to be stored as a single precision value, it is converted to positive (negative) infinity"
    float correct = isinf(1.0e2147483649) ? 1.0 : 0.0;
    my_FragColor = vec4(0.0, correct, 0.0, 1.0);
}
</script>
<script id="fshaderNonConstFloatIsInfinity" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

uniform float u; // Assumed to have the default value 0.0

void main()
{
    // Out-of-range floats should overflow to infinity
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "If the value of the floating point number is too large (small) to be stored as a single precision value, it is converted to positive (negative) infinity"
    float f = 1.0e2048 - u;
    float correct = (isinf(f) && f > 0.0) ? 1.0 : 0.0;
    my_FragColor = vec4(0.0, correct, 0.0, 1.0);
}
</script>
<script id="fshaderNonConstFloatIsNegativeInfinity" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;

uniform float u; // Assumed to have the default value 0.0

void main()
{
    // Out-of-range floats should overflow to infinity
    // GLSL ES 3.00.6 section 4.1.4 Floats:
    // "If the value of the floating point number is too large (small) to be stored as a single precision value, it is converted to positive (negative) infinity"
    float f = -1.0e2048 + u;
    float correct = (isinf(f) && f < 0.0) ? 1.0 : 0.0;
    my_FragColor = vec4(0.0, correct, 0.0, 1.0);
}
</script>
<script type="text/javascript">
"use strict";
description();

GLSLConformanceTester.runRenderTests([
{
  fShaderId: 'fshaderParsedFloatOverflowToInfinity',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Floats of too large magnitude should be converted infinity."
},
{
  fShaderId: 'fshaderParsedFloatUnderflowToZero',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Floats of too small magnitude should be converted to zero."
},
{
  fShaderId: 'fshaderParsedFloatSmallMantissa',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Number of digits in any digit-sequence is not limited - test with a small mantissa and large exponent."
},
{
  fShaderId: 'fshaderParsedFloatLargeMantissa',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Number of digits in any digit-sequence is not limited - test with a large mantissa and negative exponent."
},
{
  fShaderId: 'fshaderParsedFloatExponentAboveMaxInt',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Test that an exponent that slightly overflows signed 32-bit int range works."
},
{
  fShaderId: 'fshaderNonConstFloatIsInfinity',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Test that a non-constant float that has infinity as a value is processed correctly by isinf()."
},
{
  fShaderId: 'fshaderNonConstFloatIsNegativeInfinity',
  fShaderSuccess: true,
  linkSuccess: true,
  passMsg: "Test that a non-constant float that has negative infinity as a value is processed correctly by isinf()."
}
], 2);
</script>
</body>
</html>
