<!--

/*
** 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="../../resources/js-test-pre.js"></script>
<script src="../resources/webgl-test-utils.js"></script>
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 pos;
attribute vec4 colorIn;
varying vec4 color;

void main()
{
    color = colorIn;
    gl_Position = vec4(pos.xyz, 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="example" width="32" height="32"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";

// The below declarations need to be global for "shouldBe" to see them
var wtu = WebGLTestUtils;
var gl = null;
var array = null;
var pixel = [ 0, 0, 0, 0 ];
var expectedColor = [ 0, 0, 0, 0 ];

function calculatePixelBytes(format, type)
{
    var size = 0;
    switch (format) {
    case gl.ALPHA:
        size = 1;
        break;
    case gl.RGB:
        size = 3;
        break;
    case gl.RGBA:
        size = 4;
        break;
    default:
        return -1;
    }
    switch (type) {
    case gl.UNSIGNED_BYTE:
        break;
    case gl.UNSIGNED_SHORT_5_6_5:
        if (format != gl.RGB)
            return -1;
        size = 2;
        break;
    case gl.UNSIGNED_SHORT_4_4_4_4:
    case gl.UNSIGNED_SHORT_5_5_5_1:
        if (format != gl.RGBA)
            return -1;
        size = 2;
        break;
    default:
        return -1;
    }
    return size;
}

function calculatePaddingBytes(bytesPerPixel, packAlignment, width)
{
    var padding = 0;
    switch (packAlignment) {
    case 1:
    case 2:
    case 4:
    case 8:
        padding = (bytesPerPixel * width) % packAlignment;
        if (padding > 0)
            padding = packAlignment - padding;
        break;
    default:
        return -1;
    }
    return padding;
}

function packColor(format, type, r, g, b, a)
{
    // FIXME: not sure if the color packing is correct for UNSIGNED_SHORT_*.
    var color = [ 0, 0, 0, 0 ];
    switch (type) {
    case gl.UNSIGNED_BYTE:
        switch (format) {
        case gl.ALPHA:
            color[0] = a;
            break;
        case gl.RGB:
            color[0] = r;
            color[1] = g;
            color[2] = b;
            break;
        case gl.RGBA:
            color[0] = r;
            color[1] = g;
            color[2] = b;
            color[3] = a;
            break;
        default:
            return null;
        }
        break;
    case gl.UNSIGNED_SHORT_5_6_5:
        if (format != gl.RGB)
            return null;
        r >>= 3;
        g >>= 2;
        b >>= 3;
        color[0] = (r << 11) + (g << 5) + b;
        break;
    case gl.UNSIGNED_SHORT_4_4_4_4:
        if (format != gl.RGBA)
            return null;
        r >>= 4;
        g >>= 4;
        b >>= 4;
        a >>= 4;
        color[0] = (r << 12) + (g << 8) + (b << 4) + a;
        break;
    case gl.UNSIGNED_SHORT_5_5_5_1:
        if (format != gl.RGBA)
            return null;
        r >>= 3;
        g >>= 3;
        b >>= 3;
        a >>= 7;
        color[0] = (r << 11) + (g << 6) + (b << 1) + a;
        break;
    Default:
        return null;
    }
    return color;
}

function runTestIteration(format, type, packAlignment, width, height)
{
    debug("Testing PACK_ALIGNMENT = " + packAlignment + ", width = " + width + ", height = " + height);
    gl.clearColor(1, 0.4, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.pixelStorei(gl.PACK_ALIGNMENT, packAlignment);
    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    var bytesPerPixel = calculatePixelBytes(format, type);
    var padding = calculatePaddingBytes(bytesPerPixel, packAlignment, width);
    var size = bytesPerPixel * width * height + padding * (height - 1);
    if (type != gl.UNSIGNED_BYTE) {
        throw "test error: only UNSIGNED_BYTE is valid to ReadPixels";
    }
    if (size < 0)
        size = 0;
    array = new Uint8Array(size);
    gl.readPixels(0, 0, width, height, format, type, array);
    if (width < 0 || height < 0) {
        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
        return;
    }

    wtu.glErrorShouldBe(gl, gl.NO_ERROR);
    if (!array.length)
        return;

    // Check the last pixel of the last row.
    var bytesPerRow = width * bytesPerPixel + padding;
    var pos = bytesPerRow * (height - 1) + (width - 1) * bytesPerPixel;
    var numComponents = bytesPerPixel;
    for (var i = 0; i < numComponents; ++i)
        pixel[i] = array[pos + i];
    for (var i = numComponents; i < 4; ++i)
        pixel[i] = 0;
    expectedColor = packColor(format, type, 255, 102, 0, 255);
    shouldBeNonNull("expectedColor");
    shouldBe("pixel", "expectedColor");
}

description('Verify readPixels() works fine with various PACK_ALIGNMENT values.');

shouldBeNonNull("gl = wtu.create3DContext('example')")
shouldBeNonNull("program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['pos', 'colorIn'])");

var formats = [ gl.RGBA ];
var formatNames = [ "RGBA" ];

for (var i = 0; i < formats.length; ++i) {
    var format = formats[i];

    debug("Testing format = " + formatNames[i] + " and type = UNSIGNED_BYTE");
    runTestIteration(format, gl.UNSIGNED_BYTE, 1, 1, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 1, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 1, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 2, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 2, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 3, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 3, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 4, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 4, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 1);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 5, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 6, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 7, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 8, 2);
    runTestIteration(format, gl.UNSIGNED_BYTE, 1, 0, 0);
    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 0, 0);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, 0);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 0, 0);
    runTestIteration(format, gl.UNSIGNED_BYTE, 1, -1, 1);
    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, -1);
    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, -1);
    runTestIteration(format, gl.UNSIGNED_BYTE, 8, -1, -1);
}

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