/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "renderstate/MeshState.h"

#include "Program.h"

#include "ShadowTessellator.h"

namespace android {
namespace uirenderer {

MeshState::MeshState()
        : mCurrentIndicesBuffer(0)
        , mCurrentPixelBuffer(0)
        , mCurrentPositionPointer(this)
        , mCurrentPositionStride(0)
        , mCurrentTexCoordsPointer(this)
        , mCurrentTexCoordsStride(0)
        , mTexCoordsArrayEnabled(false)
        , mQuadListIndices(0) {
    glGenBuffers(1, &mUnitQuadBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
    mCurrentBuffer = mUnitQuadBuffer;

    uint16_t regionIndices[kMaxNumberOfQuads * 6];
    for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
        uint16_t quad = i * 4;
        int index = i * 6;
        regionIndices[index    ] = quad;       // top-left
        regionIndices[index + 1] = quad + 1;   // top-right
        regionIndices[index + 2] = quad + 2;   // bottom-left
        regionIndices[index + 3] = quad + 2;   // bottom-left
        regionIndices[index + 4] = quad + 1;   // top-right
        regionIndices[index + 5] = quad + 3;   // bottom-right
    }
    glGenBuffers(1, &mQuadListIndices);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW);
    mCurrentIndicesBuffer = mQuadListIndices;

    // position attribute always enabled
    glEnableVertexAttribArray(Program::kBindingPosition);
}

MeshState::~MeshState() {
    glDeleteBuffers(1, &mUnitQuadBuffer);
    mCurrentBuffer = 0;

    glDeleteBuffers(1, &mQuadListIndices);
    mQuadListIndices = 0;
}

void MeshState::dump() {
    ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
    ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
    ALOGD("MeshState vertices: vertex data %p, stride %d",
            mCurrentPositionPointer, mCurrentPositionStride);
    ALOGD("MeshState texCoord: data %p, stride %d",
            mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
}

///////////////////////////////////////////////////////////////////////////////
// Buffer Objects
///////////////////////////////////////////////////////////////////////////////

void MeshState::bindMeshBuffer(GLuint buffer) {
    if (mCurrentBuffer != buffer) {
        glBindBuffer(GL_ARRAY_BUFFER, buffer);
        mCurrentBuffer = buffer;

        // buffer has changed, so invalidate cached vertex pos/texcoord pointers
        resetVertexPointers();
    }
}

void MeshState::unbindMeshBuffer() {
    return bindMeshBuffer(0);
}

void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
        const void* data, GLenum usage) {
    if (!*buffer) {
        glGenBuffers(1, buffer);
    }
    bindMeshBuffer(*buffer);
    glBufferData(GL_ARRAY_BUFFER, size, data, usage);
}

void MeshState::deleteMeshBuffer(GLuint buffer) {
    if (buffer == mCurrentBuffer) {
        // GL defines that deleting the currently bound VBO rebinds to 0 (no VBO).
        // Reflect this in our cached value.
        mCurrentBuffer = 0;
    }
    glDeleteBuffers(1, &buffer);
}

///////////////////////////////////////////////////////////////////////////////
// Vertices
///////////////////////////////////////////////////////////////////////////////

void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
    // update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
    if (mCurrentBuffer == 0
            || vertices != mCurrentPositionPointer
            || stride != mCurrentPositionStride) {
        glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
        mCurrentPositionPointer = vertices;
        mCurrentPositionStride = stride;
    }
}

void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
    // update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
    if (mCurrentBuffer == 0
            || vertices != mCurrentTexCoordsPointer
            || stride != mCurrentTexCoordsStride) {
        glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
        mCurrentTexCoordsPointer = vertices;
        mCurrentTexCoordsStride = stride;
    }
}

void MeshState::resetVertexPointers() {
    mCurrentPositionPointer = this;
    mCurrentTexCoordsPointer = this;
}

void MeshState::enableTexCoordsVertexArray() {
    if (!mTexCoordsArrayEnabled) {
        glEnableVertexAttribArray(Program::kBindingTexCoords);
        mCurrentTexCoordsPointer = this;
        mTexCoordsArrayEnabled = true;
    }
}

void MeshState::disableTexCoordsVertexArray() {
    if (mTexCoordsArrayEnabled) {
        glDisableVertexAttribArray(Program::kBindingTexCoords);
        mTexCoordsArrayEnabled = false;
    }
}

///////////////////////////////////////////////////////////////////////////////
// Indices
///////////////////////////////////////////////////////////////////////////////

void MeshState::bindIndicesBuffer(const GLuint buffer) {
    if (mCurrentIndicesBuffer != buffer) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
        mCurrentIndicesBuffer = buffer;
    }
}

void MeshState::unbindIndicesBuffer() {
    if (mCurrentIndicesBuffer) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        mCurrentIndicesBuffer = 0;
    }
}

} /* namespace uirenderer */
} /* namespace android */

