/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "geometryengine.h"

#include <QVector2D>
#include <QVector3D>
#include <QtMath>

const int sampleWidth = 16;
const int sampleHeight = 16;
#define PI 3.14159265

struct VertexData
{
    QVector3D position;
    QVector2D texCoord;
};

GeometryEngine::GeometryEngine()
{
}

GeometryEngine::~GeometryEngine()
{
    glDeleteBuffers(2, vboIds);
}

void GeometryEngine::init()
{
    initializeOpenGLFunctions();

    // Generate 2 VBOs
    glGenBuffers(2, vboIds);

    // Initializes cube geometry and transfers it to VBOs
    initCubeGeometry();
}

void GeometryEngine::initCubeGeometry()
{
    VertexData *vertices = new VertexData[sampleWidth * sampleHeight];
    float angleStep = 360.0f / float(sampleWidth - 1);
    float latitude;
    float latAngleStep = 180.0f / float(sampleHeight - 1);

    int p = 0;
    for (int i = 0; i < sampleHeight; i++) {
        float latAngle = float(i) * latAngleStep;
        latitude = qCos(latAngle * PI/180) * 1.0f;
        for (int j = -4; j < sampleWidth - 4; j++) {
            float radius = qSin(latAngle * PI/180) * 1.0f;
            float angle = float(j) * angleStep;
            float x = qCos(angle * PI/180) * radius;
            float z = qSin(angle * PI/180) * radius;

            vertices[p].position = QVector3D(x, latitude, z);
            p++;
        }
    }

    float yStep = 1.0f / float(sampleHeight - 1);
    float xStep = 1.0f / float(sampleWidth - 1);
    p = 0;
    for (int i = 0; i < sampleHeight; i++) {
        float y = i * yStep;
        for (int j = 0; j < sampleWidth; j++) {
            vertices[p].texCoord = QVector2D(1.0f - j * xStep, 1.0f - y);
            p++;
        }
    }

    p = 0;
    GLushort *indices = new GLushort[6 * (sampleWidth - 1) * (sampleHeight - 1)];
    for (int i = 0; i < (sampleHeight - 1); i++) {
        int row = i * sampleWidth;
        for (int j = 0; j < (sampleWidth - 1); j++) {
            // Left triangle
            indices[p++] = row + j + 1;
            indices[p++] = row + sampleWidth + j;
            indices[p++] = row + j;

            // Right triangle
            indices[p++] = row + sampleWidth + j + 1;
            indices[p++] = row + sampleWidth + j;
            indices[p++] = row + j + 1;
        }
    }

    // Transfer vertex data to VBO 0
    glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
    glBufferData(GL_ARRAY_BUFFER, sampleWidth * sampleHeight * sizeof(VertexData), vertices, GL_STATIC_DRAW);

    // Transfer index data to VBO 1
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * (sampleWidth - 1) * (sampleHeight - 1) * sizeof(GLushort), indices, GL_STATIC_DRAW);
}

void GeometryEngine::drawCubeGeometry(QGLShaderProgram *program)
{
    // Tell OpenGL which VBOs to use
    glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);

    // Offset for position
    quintptr offset = 0;

    // Tell OpenGL programmable pipeline how to locate vertex position data
    int vertexLocation = program->attributeLocation("a_position");
    program->enableAttributeArray(vertexLocation);
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *)offset);

    // Offset for texture coordinate
    offset += sizeof(QVector3D);

    // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
    int texcoordLocation = program->attributeLocation("a_texcoord");
    program->enableAttributeArray(texcoordLocation);
    glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *)offset);

    // Draw cube geometry using indices from VBO 1
    //glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0);
    glDrawElements(GL_TRIANGLES, 6 * (sampleWidth - 1) * (sampleHeight - 1), GL_UNSIGNED_SHORT, 0);
}
