//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

//            Based on Hello_Triangle.c from
// Book:      OpenGL(R) ES 2.0 Programming Guide
// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
// ISBN-10:   0321502795
// ISBN-13:   9780321502797
// Publisher: Addison-Wesley Professional
// URLs:      http://safari.informit.com/9780321563835
//            http://www.opengles-book.com

#include "SampleApplication.h"

#include "util/shader_utils.h"

#include <cstring>
#include <iostream>

// This small sample compares the per-frame render time for a series of
// squares drawn with TRIANGLE_FANS versus squares drawn with TRIANGLES.
// To exacerbate differences between the two, we use a large collection
// of short buffers with pre-translated vertex data.

class TriangleFanBenchSample : public SampleApplication
{
  public:
    TriangleFanBenchSample(int argc, char **argv)
        : SampleApplication("Microbench", argc, argv, 2, 0, 1280, 1280), mFrameCount(0)
    {}

    void createVertexBuffers()
    {
        const unsigned int slices         = 8;
        const unsigned int numFanVertices = slices + 2;
        const unsigned int fanFloats      = numFanVertices * 3;

        mNumFanVerts = numFanVertices;

        const GLfloat halfDim = 0.0625;
        GLfloat fanVertices[] = {
            0.0f,     0.0f,     0.0f,  // center
            -halfDim, -halfDim, 0.0f,  // LL
            -halfDim, 0.0f,     0.0f,  // CL
            -halfDim, halfDim,  0.0f,  // UL
            0.0f,     halfDim,  0.0f,  // UC
            halfDim,  halfDim,  0.0f,  // UR
            halfDim,  0.0f,     0.0f,  // CR
            halfDim,  -halfDim, 0.0f,  // LR
            0.0f,     -halfDim, 0.0f,  // LC
            -halfDim, -halfDim, 0.0f   // LL (closes the fan)
        };

        const GLfloat xMin = -1.0f;  // We leave viewport/worldview untransformed in this sample
        const GLfloat xMax = 1.0f;
        const GLfloat yMin = -1.0f;
        // const GLfloat yMax = 1.0f;

        glGenBuffers(mNumSquares, mFanBufId);

        GLfloat xOffset = xMin;
        GLfloat yOffset = yMin;
        for (unsigned int i = 0; i < mNumSquares; ++i)
        {
            GLfloat tempVerts[fanFloats] = {0};
            for (unsigned int j = 0; j < numFanVertices; ++j)
            {
                tempVerts[j * 3]     = fanVertices[j * 3] + xOffset;
                tempVerts[j * 3 + 1] = fanVertices[j * 3 + 1] + yOffset;
                tempVerts[j * 3 + 2] = 0.0f;
            }

            glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]);
            glBufferData(GL_ARRAY_BUFFER, fanFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW);

            xOffset += 2 * halfDim;
            if (xOffset > xMax)
            {
                xOffset = xMin;
                yOffset += 2 * halfDim;
            }
        }

        const unsigned int numTriVertices = slices * 3;
        const unsigned int triFloats      = numTriVertices * 3;
        GLfloat triVertices[triFloats];
        GLfloat *triPointer = triVertices;

        mNumTriVerts = numTriVertices;

        for (unsigned int i = 0; i < slices; ++i)
        {
            memcpy(triPointer, fanVertices,
                   3 * sizeof(GLfloat));  // copy center point as first vertex for this slice
            triPointer += 3;
            for (unsigned int j = 1; j < 3; ++j)
            {
                GLfloat *vertex =
                    &(fanVertices[(i + j) * 3]);  // copy two outer vertices for this point
                memcpy(triPointer, vertex, 3 * sizeof(GLfloat));
                triPointer += 3;
            }
        }

        // GLfloat triVertices2[triFloats];
        glGenBuffers(mNumSquares, mTriBufId);
        xOffset = xMin;
        yOffset = yMin;

        for (unsigned int i = 0; i < mNumSquares; ++i)
        {
            triPointer = triVertices;
            GLfloat tempVerts[triFloats];
            for (unsigned int j = 0; j < numTriVertices; ++j)
            {
                tempVerts[j * 3]     = triPointer[0] + xOffset;
                tempVerts[j * 3 + 1] = triPointer[1] + yOffset;
                tempVerts[j * 3 + 2] = 0.0f;
                triPointer += 3;
            }

            glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]);
            glBufferData(GL_ARRAY_BUFFER, triFloats * sizeof(GLfloat), tempVerts, GL_STATIC_DRAW);
            xOffset += 2 * halfDim;
            if (xOffset > xMax)
            {
                yOffset += 2 * halfDim;
                xOffset = xMin;
            }
        }
    }

    bool initialize() override
    {
        constexpr char kVS[] = R"(attribute vec4 vPosition;
void main()
{
    gl_Position = vPosition;
})";

        constexpr char kFS[] = R"(precision mediump float;
void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
})";

        mProgram = CompileProgram(kVS, kFS);
        if (!mProgram)
        {
            return false;
        }

        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        createVertexBuffers();

        mFanTimer     = CreateTimer();
        mTriTimer     = CreateTimer();
        mFanTotalTime = 0;
        mTriTotalTime = 0;

        return true;
    }

    void destroy() override
    {
        std::cout << "Total draw time using TRIANGLE_FAN: " << mFanTotalTime << "ms ("
                  << (float)mFanTotalTime / (float)mFrameCount << " average per frame)"
                  << std::endl;
        std::cout << "Total draw time using TRIANGLES: " << mTriTotalTime << "ms ("
                  << (float)mTriTotalTime / (float)mFrameCount << " average per frame)"
                  << std::endl;
        glDeleteProgram(mProgram);
    }

    void draw() override
    {
        // Set the viewport
        glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());

        // Clear the color buffer
        glClear(GL_COLOR_BUFFER_BIT);

        // Use the program object
        glUseProgram(mProgram);

        // Bind the vertex data
        glEnableVertexAttribArray(0);

        // Draw using triangle fans, stored in VBO
        mFanTimer->start();
        for (unsigned i = 0; i < mNumSquares; ++i)
        {
            glBindBuffer(GL_ARRAY_BUFFER, mFanBufId[i]);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
            glDrawArrays(GL_TRIANGLE_FAN, 0, mNumFanVerts);
        }
        mFanTimer->stop();

        mFanTotalTime += static_cast<unsigned int>(
            mFanTimer->getElapsedTime() * 1000);  // convert from usec to msec when accumulating

        // Clear to eliminate driver-side gains from occlusion
        glClear(GL_COLOR_BUFFER_BIT);

        // Draw using triangles, stored in VBO
        mTriTimer->start();
        for (unsigned i = 1; i < mNumSquares; ++i)
        {
            glBindBuffer(GL_ARRAY_BUFFER, mTriBufId[i]);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
            glDrawArrays(GL_TRIANGLES, 0, mNumTriVerts);
        }
        mTriTimer->stop();

        mTriTotalTime += static_cast<unsigned int>(
            mTriTimer->getElapsedTime() * 1000);  // convert from usec to msec when accumulating

        mFrameCount++;
    }

  private:
    static const unsigned int mNumSquares = 289;
    unsigned int mNumFanVerts;
    unsigned int mNumTriVerts;
    GLuint mProgram;
    GLuint mFanBufId[mNumSquares];
    GLuint mTriBufId[mNumSquares];

    Timer *mFanTimer;
    Timer *mTriTimer;
    unsigned int mFrameCount;
    unsigned int mTriTotalTime;
    unsigned int mFanTotalTime;
};

int main(int argc, char **argv)
{
    TriangleFanBenchSample app(argc, argv);
    return app.run();
}
