<!--
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>gl-fragcoord Test</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>
</head>
<body>
<canvas id="canvas" width="32" height="32">
</canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
// Inputs
attribute vec4 aPosInfo;

// Outputs
varying vec2 vTargetPixelCoord;

void main()
{
  vTargetPixelCoord = aPosInfo.zw;

  gl_PointSize = 1.0;
  gl_Position  = vec4(aPosInfo.xy, 0.0, 1.0);
}
</script>

<script id="fshader" type="x-shader/x-fragment">
precision mediump float;

// Inputs
varying vec2 vTargetPixelCoord;

// Colors used to signal correctness
const vec4 red   = vec4(1.0, 0.0, 0.0, 1.0);
const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);

void main()
{
  // Check pixel index
  bool pixelIxValid = (floor(gl_FragCoord.xy) == vTargetPixelCoord);

  // Check fractional part of coordinates
  bool fracCoordValid = all(lessThan(abs(fract(gl_FragCoord.xy) - vec2(0.5)), vec2(0.0001)));

  gl_FragColor = (pixelIxValid && fracCoordValid) ? green : red;
}
</script>

<script id="test_fshader" type="x-shader/x-fragment">
// Shader to test if the frame buffer positions within the output pixel are different for the five render passes
// Pass on frame buffer position in varying, change in vertex shader : vTargetPixelCoord = aPosInfo.xy;
// Set test_fshader in setupProgram()

precision mediump float;

// Inputs
varying vec2 vTargetPixelCoord;

const vec2 pixSize = vec2(2.0/32.0, 2.0/32.0);

void main()
{
  // Coordinates within a framebuffer pixel [0, 1>
  vec2 inPixelCoord = fract(vTargetPixelCoord / pixSize);

  // Create different color dependent on the position inside the framebuffer pixel
  float r = (inPixelCoord.x < 0.4) ? 0.2 : (inPixelCoord.x > 0.6) ? 0.8 : 0.5;
  float g = (inPixelCoord.y < 0.4) ? 0.2 : (inPixelCoord.y > 0.6) ? 0.8 : 0.5;

  gl_FragColor = vec4(r, g, 0.0, 1.0);
}
</script>

<script>
"use strict";

// Test if gl_FragCoord.xy values are always of the form :
// (first framebuffer pixel index + 0.5, second framebuffer pixel index + 0.5)
// (if no multisampling)

// This is done by rendering a set of points which targets either the center of the
// output pixel or the center of one of the quadrants

// Constants
var floatsPerAttribute = 4;

// Globals
var wtu;
var gl;
var program;
var vxBuffer;

// Set data for one attribute (framebuffer.xy, pixel_index.xy)
function setPixelData(data, dIx, xx, yy, xSize, ySize, xOffset, yOffset)
{
  // Frame buffer first coordinate [-1, 1]
  data[dIx++] = (xx + 0.5) * xSize + xOffset - 1;

  // Frame buffer second coordinate [-1, 1]
  data[dIx++] = (yy + 0.5) * ySize + yOffset - 1;

  // Frame buffer pixel first index
  data[dIx++] = xx;

  // Frame buffer pixel second index
  data[dIx++] = yy;

  return dIx;
}

// Create attribute data
function createAttributeData(xOffset, yOffset)
{
  // Retrieve realised dimensions of viewport
  var widthPx    = gl.drawingBufferWidth;
  var heightPx   = gl.drawingBufferHeight;
  var pixelCount = widthPx * heightPx;

  // Pixel size in framebuffer coordinates
  var pWidth  = 2 / widthPx;
  var pHeight = 2 / heightPx;
  var data = new Float32Array(pixelCount * floatsPerAttribute);
  var dIx = 0;
  for (var yy = 0; yy < heightPx; ++yy)
    for (var xx = 0; xx < widthPx; ++xx)
      dIx = setPixelData(data, dIx, xx, yy, pWidth, pHeight,  xOffset * pWidth,  yOffset * pHeight);

  if (dIx !== data.length)
    wtu.error("gl-fragcoord-xy-values.html, createAttributeData(), index not correct at end");

  return data;
}

// Initialize test
function init()
{
  description("tests gl_FragCoord.xy values");

  wtu = WebGLTestUtils;
  gl = wtu.create3DContext("canvas", { antialias: false });
  program = wtu.setupProgram(gl, ["vshader", "fshader"], ["aPosInfo"]);
  vxBuffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, vxBuffer);
  gl.enableVertexAttribArray(0);
  gl.vertexAttribPointer(0, floatsPerAttribute, gl.FLOAT, false, 0, 0);
}

// Render data
function render(xOffset, yOffset, passMsg)
{
  // Set attribute data
  var data = createAttributeData(xOffset, yOffset);
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);

  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.POINTS, 0, data.length / floatsPerAttribute);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
  var green = [0, 255, 0, 255];
  wtu.checkCanvas(gl, green, passMsg);
}

// Run tests
init();
render(0, 0, "green : sampling at center of output pixel is correct");
render(0.25, 0.25, "green : sampling in top right quadrant of output pixel is correct");
render(-0.25, 0.25, "green : sampling in top left quadrant of output pixel is correct");
render( 0.25, -0.25, "green : sampling in bottom right quadrant of output pixel is correct");
render(-0.25, -0.25, "green : sampling in bottom left quadrant of output pixel is correct");
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>

</body>
</html>
