<!--

/*
** Copyright (c) 2012 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/

-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<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 id="vshader" type="x-shader/x-vertex">
attribute vec3 pos;
attribute vec4 colorIn;
uniform float pointSize;
varying vec4 color;

void main()
{
    gl_PointSize = pointSize;
    color = colorIn;
    gl_Position = vec4(pos, 1.0);
}
</script>

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

void main()
{
    gl_FragColor = color;
}
</script>
</head>
<body>
<canvas id="testbed" width="2" height="2"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description('Verify GL_VERTEX_PROGRAM_POINT_SIZE is enabled in WebGL');

var wtu = WebGLTestUtils;
var gl = wtu.create3DContext('testbed', { antialias: false });
shouldBeNonNull("gl");

gl.disable(gl.BLEND);

// The choice of (0.4, 0.4) ensures that the centers of the surrounding
// pixels are not contained within the point when it is of size 1, but
// that they definitely are when it is of size 2.
var vertices = new Float32Array([
    0.4, 0.4, 0.0]);
var colors = new Uint8Array([
    255, 0, 0, 255]);

var colorOffset = vertices.byteLength;

var buf = new Uint8Array(2 * 2 * 4);
var index = 0;

var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, colorOffset + colors.byteLength, gl.STATIC_DRAW);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertices);
gl.bufferSubData(gl.ARRAY_BUFFER, colorOffset, colors);

function test(program) {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(0);
    gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, colorOffset);
    gl.enableVertexAttribArray(1);

    var locPointSize = gl.getUniformLocation(program, 'pointSize');

    shouldBe('gl.getError()', 'gl.NO_ERROR');

    debug('Draw a point of size 1 and verify it does not touch any other pixels.');

    gl.uniform1f(locPointSize, 1.0);
    gl.drawArrays(gl.POINTS, 0, vertices.length / 3);

    shouldBe('gl.getError()', 'gl.NO_ERROR');

    for (var y = 0; y < 2; ++y) {
        for (var x = 0; x < 2; ++x) {
            var correctColor = (x == 1 && y == 1) ? [255, 0, 0] : [0, 0, 0];
            wtu.checkCanvasRect(gl, x, y, 1, 1, correctColor);
        }
    }
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    debug('Draw a point of size 2 and verify it fills the appropriate region.');

    var pointSizeRange = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
    if (pointSizeRange[1] >= 2.0) {
        gl.uniform1f(locPointSize, 2.0);
        gl.drawArrays(gl.POINTS, 0, vertices.length / 3);
        shouldBe('gl.getError()', 'gl.NO_ERROR');
        wtu.checkCanvasRect(gl, 0, 0, 2, 2, [255, 0, 0]);
    }
}

debug('');
debug('Pass 1');
var program1 = wtu.setupProgram(gl, ['vshader', 'fshader'], ['pos', 'colorIn']);
shouldBe('gl.getError()', 'gl.NO_ERROR');
test(program1);

// Under some versions of ANGLE point sprite shader programs were
// incorrectly reloaded from cache. Rebuilding the shader program and
// repeating the test simulates the conditions that caused it to fail
debug('');
debug('Pass 2');
var program2 = wtu.setupProgram(gl, ['vshader', 'fshader'], ['pos', 'colorIn']);
shouldBe('gl.getError()', 'gl.NO_ERROR');
test(program2);

var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>

</body>
</html>
