//
// Copyright 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 Simple_Texture2D.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 "texture_utils.h"
#include "util/shader_utils.h"
#include "util/test_utils.h"

#include <cstring>
#include <iostream>

class MultipleDrawBuffersSample : public SampleApplication
{
  public:
    MultipleDrawBuffersSample(int argc, char **argv)
        : SampleApplication("MultipleDrawBuffers", argc, argv)
    {}

    virtual bool initialize()
    {
        // Check EXT_draw_buffers is supported
        char *extensionString = (char *)glGetString(GL_EXTENSIONS);
        if (strstr(extensionString, "GL_EXT_draw_buffers") != nullptr)
        {
            // Retrieve the address of glDrawBuffersEXT from EGL
            mDrawBuffers = (PFNGLDRAWBUFFERSEXTPROC)eglGetProcAddress("glDrawBuffersEXT");
        }
        else
        {
            mDrawBuffers = glDrawBuffers;
        }

        if (!mDrawBuffers)
        {
            std::cerr << "Unable to load glDrawBuffers[EXT] entry point.";
            return false;
        }

        std::stringstream vsStream;
        vsStream << angle::GetExecutableDirectory() << "/multiple_draw_buffers_vs.glsl";

        std::stringstream fsStream;
        fsStream << angle::GetExecutableDirectory() << "/multiple_draw_buffers_fs.glsl";

        std::stringstream copyFsStream;
        fsStream << angle::GetExecutableDirectory() << "/multiple_draw_buffers_copy_fs.glsl";

        mMRTProgram = CompileProgramFromFiles(vsStream.str(), fsStream.str());
        if (!mMRTProgram)
        {
            return false;
        }

        mCopyProgram = CompileProgramFromFiles(vsStream.str(), copyFsStream.str());
        if (!mCopyProgram)
        {
            return false;
        }

        // Get the attribute locations
        mPositionLoc = glGetAttribLocation(mCopyProgram, "a_position");
        mTexCoordLoc = glGetAttribLocation(mCopyProgram, "a_texCoord");

        // Get the sampler location
        mSamplerLoc = glGetUniformLocation(mCopyProgram, "s_texture");

        // Load the texture
        mTexture = CreateSimpleTexture2D();

        // Initialize the user framebuffer
        glGenFramebuffers(1, &mFramebuffer);
        glGenTextures(mFramebufferAttachmentCount, mFramebufferTextures);

        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
        for (size_t i = 0; i < mFramebufferAttachmentCount; i++)
        {
            // Create textures for the four color attachments
            glBindTexture(GL_TEXTURE_2D, mFramebufferTextures[i]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindow()->getWidth(),
                         getWindow()->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glFramebufferTexture2D(GL_FRAMEBUFFER,
                                   static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT + i), GL_TEXTURE_2D,
                                   mFramebufferTextures[i], 0);
        }

        glBindTexture(GL_TEXTURE_2D, 0);

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

        return true;
    }

    virtual void destroy()
    {
        glDeleteProgram(mCopyProgram);
        glDeleteProgram(mMRTProgram);
        glDeleteTextures(1, &mTexture);
        glDeleteTextures(mFramebufferAttachmentCount, mFramebufferTextures);
        glDeleteFramebuffers(1, &mFramebuffer);
    }

    virtual void draw()
    {
        GLfloat vertices[] = {
            -0.8f, 0.8f,  0.0f,  // Position 0
            0.0f,  0.0f,         // TexCoord 0
            -0.8f, -0.8f, 0.0f,  // Position 1
            0.0f,  1.0f,         // TexCoord 1
            0.8f,  -0.8f, 0.0f,  // Position 2
            1.0f,  1.0f,         // TexCoord 2
            0.8f,  0.8f,  0.0f,  // Position 3
            1.0f,  0.0f          // TexCoord 3
        };
        GLushort indices[]                              = {0, 1, 2, 0, 2, 3};
        GLenum drawBuffers[mFramebufferAttachmentCount] = {
            GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT,
            GL_COLOR_ATTACHMENT3_EXT};

        // Enable drawing to the four color attachments of the user framebuffer
        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
        mDrawBuffers(mFramebufferAttachmentCount, drawBuffers);

        // Set the viewport
        GLint width  = static_cast<GLint>(getWindow()->getWidth());
        GLint height = static_cast<GLint>(getWindow()->getHeight());
        glViewport(0, 0, width, height);

        // Clear the color buffer
        glClear(GL_COLOR_BUFFER_BIT);

        // Use the program object
        glUseProgram(mMRTProgram);

        // Load the vertex position
        glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
        glEnableVertexAttribArray(mPositionLoc);

        // Load the texture coordinate
        glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
                              vertices + 3);
        glEnableVertexAttribArray(mTexCoordLoc);

        // Bind the texture
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mTexture);

        // Set the sampler texture unit to 0
        glUniform1i(mSamplerLoc, 0);

        // Draw the textured quad to the four render targets
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

        // Enable the default framebuffer and single textured drawing
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glUseProgram(mCopyProgram);

        // Draw the four textured quads to a separate region in the viewport
        glBindTexture(GL_TEXTURE_2D, mFramebufferTextures[0]);
        glViewport(0, 0, width / 2, height / 2);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

        glBindTexture(GL_TEXTURE_2D, mFramebufferTextures[1]);
        glViewport(width / 2, 0, width / 2, height / 2);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

        glBindTexture(GL_TEXTURE_2D, mFramebufferTextures[2]);
        glViewport(0, height / 2, width / 2, height / 2);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

        glBindTexture(GL_TEXTURE_2D, mFramebufferTextures[3]);
        glViewport(width / 2, height / 2, width / 2, height / 2);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
    }

  private:
    // Handle to a program object
    GLuint mMRTProgram;
    GLuint mCopyProgram;

    // Attribute locations
    GLint mPositionLoc;
    GLint mTexCoordLoc;

    // Sampler location
    GLint mSamplerLoc;

    // Texture handle
    GLuint mTexture;

    // Framebuffer object handle
    GLuint mFramebuffer;

    // Framebuffer color attachments
    static const size_t mFramebufferAttachmentCount = 4;
    GLuint mFramebufferTextures[mFramebufferAttachmentCount];

    // Loaded draw buffer entry points
    PFNGLDRAWBUFFERSEXTPROC mDrawBuffers;
};

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