// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 "cobalt/renderer/rasterizer/egl/draw_poly_color.h"

#include <GLES2/gl2.h>
#include <algorithm>

#include "base/logging.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/math/transform_2d.h"
#include "cobalt/renderer/backend/egl/utils.h"
#include "egl/generated_shader_impl.h"
#include "starboard/memory.h"

namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace egl {

DrawPolyColor::DrawPolyColor(GraphicsState* graphics_state,
    const BaseState& base_state, const math::RectF& rect,
    const render_tree::ColorRGBA& color)
    : DrawObject(base_state),
      allow_simple_clip_(true),
      index_buffer_(nullptr),
      vertex_buffer_(nullptr) {
  merge_type_ = base::GetTypeId<DrawPolyColor>();

  attributes_.reserve(4);
  AddRectVertices(rect, GetGLRGBA(GetDrawColor(color) * base_state_.opacity));
  indices_.reserve(6);
  AddRectIndices(0, 1, 2, 3);

  graphics_state->ReserveVertexData(
      attributes_.size() * sizeof(attributes_[0]));
  graphics_state->ReserveVertexIndices(indices_.size());
}

DrawPolyColor::DrawPolyColor(const BaseState& base_state)
    : DrawObject(base_state),
      allow_simple_clip_(false),
      index_buffer_(nullptr),
      vertex_buffer_(nullptr) {
  merge_type_ = base::GetTypeId<DrawPolyColor>();
}

bool DrawPolyColor::TryMerge(DrawObject* other) {
  if (merge_type_ != other->GetMergeTypeId()) {
    return false;
  }

  // If the merge types match, then the objects should use the same shaders.
  // Otherwise, ensure the merge types are different.
  DCHECK(GetTypeId() == other->GetTypeId());

  DrawPolyColor* merge = base::polymorphic_downcast<DrawPolyColor*>(other);
  if (!PrepareForMerge() || !merge->PrepareForMerge()) {
    return false;
  }

  // Since the draws for these objects already use indexed triangles, just
  // concatenate the vertex attributes and indices. Keep in mind the indices
  // for the |other| object need to be fixed up.
  uint16_t index_offset = static_cast<uint16_t>(attributes_.size());
  attributes_.insert(attributes_.end(),
                     merge->attributes_.begin(), merge->attributes_.end());
  for (uint16_t index : merge->indices_) {
    indices_.emplace_back(index + index_offset);
  }

  base_state_.scissor.Union(merge->base_state_.scissor);
  return true;
}

void DrawPolyColor::ExecuteUpdateVertexBuffer(
    GraphicsState* graphics_state,
    ShaderProgramManager* program_manager) {
  if (attributes_.size() > 0) {
    vertex_buffer_ = graphics_state->AllocateVertexData(
        attributes_.size() * sizeof(attributes_[0]));
    SbMemoryCopy(vertex_buffer_, &attributes_[0],
                 attributes_.size() * sizeof(attributes_[0]));
    index_buffer_ = graphics_state->AllocateVertexIndices(indices_.size());
    SbMemoryCopy(index_buffer_, &indices_[0],
                 indices_.size() * sizeof(indices_[0]));
  }
}

void DrawPolyColor::ExecuteRasterize(
    GraphicsState* graphics_state,
    ShaderProgramManager* program_manager) {
  if (attributes_.size() > 0) {
    SetupShader(graphics_state, program_manager);
    GL_CALL(glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_SHORT,
        graphics_state->GetVertexIndexPointer(index_buffer_)));
  }
}

base::TypeId DrawPolyColor::GetTypeId() const {
  return ShaderProgram<ShaderVertexColor,
                       ShaderFragmentColor>::GetTypeId();
}

void DrawPolyColor::SetupShader(GraphicsState* graphics_state,
    ShaderProgramManager* program_manager) {
  ShaderProgram<ShaderVertexColor,
                ShaderFragmentColor>* program;
  program_manager->GetProgram(&program);
  graphics_state->UseProgram(program->GetHandle());
  graphics_state->UpdateClipAdjustment(
      program->GetVertexShader().u_clip_adjustment());
  graphics_state->UpdateTransformMatrix(
      program->GetVertexShader().u_view_matrix(),
      base_state_.transform);
  graphics_state->Scissor(base_state_.scissor.x(), base_state_.scissor.y(),
      base_state_.scissor.width(), base_state_.scissor.height());
  graphics_state->VertexAttribPointer(
      program->GetVertexShader().a_position(), 2, GL_FLOAT, GL_FALSE,
      sizeof(VertexAttributes), vertex_buffer_ +
      offsetof(VertexAttributes, position));
  graphics_state->VertexAttribPointer(
      program->GetVertexShader().a_color(), 4, GL_UNSIGNED_BYTE, GL_TRUE,
      sizeof(VertexAttributes), vertex_buffer_ +
      offsetof(VertexAttributes, color));
  graphics_state->VertexAttribFinish();
}

void DrawPolyColor::AddRectVertices(const math::RectF& rect, uint32_t color) {
  // Beware that child classes may depend on the order in which these vertices
  // are added.
  attributes_.emplace_back(rect.x(), rect.y(), color);
  attributes_.emplace_back(rect.right(), rect.y(), color);
  attributes_.emplace_back(rect.x(), rect.bottom(), color);
  attributes_.emplace_back(rect.right(), rect.bottom(), color);
}

void DrawPolyColor::AddRectIndices(uint16_t top_left, uint16_t top_right,
    uint16_t bottom_left, uint16_t bottom_right) {
  indices_.emplace_back(top_left);
  indices_.emplace_back(top_right);
  indices_.emplace_back(bottom_left);
  indices_.emplace_back(top_right);
  indices_.emplace_back(bottom_left);
  indices_.emplace_back(bottom_right);
}

bool DrawPolyColor::PrepareForMerge() {
  if (can_merge_) {
    return *can_merge_;
  }

  // Since a single draw can only have one transform and one scissor, draws
  // can be merged only if they use the same transform and the vertices are
  // in their respective scissors.

  // Rounded scissors are too expensive to check for containment.
  if (base_state_.rounded_scissor_corners) {
    can_merge_ = false;
    return *can_merge_;
  }

  float x_min = base_state_.scissor.x();
  float x_max = base_state_.scissor.right();
  float y_min = base_state_.scissor.y();
  float y_max = base_state_.scissor.bottom();
  bool in_scissor = true;

  if (allow_simple_clip_ &&
      cobalt::math::IsOnlyScaleAndTranslate(base_state_.transform)) {
    // Transform the vertices and clamp them to be within the scissor.
    float x_scale = base_state_.transform(0, 0);
    float y_scale = base_state_.transform(1, 1);
    float x_translate = base_state_.transform(0, 2);
    float y_translate = base_state_.transform(1, 2);
    for (auto& vert : attributes_) {
      math::PointF pos(vert.position[0] * x_scale + x_translate,
                       vert.position[1] * y_scale + y_translate);
      vert.position[0] = std::min(std::max(x_min, pos.x()), x_max);
      vert.position[1] = std::min(std::max(y_min, pos.y()), y_max);
    }
  } else {
    // Transform the vertices and check that they are within the scissor.
    for (auto& vert : attributes_) {
      math::PointF pos = base_state_.transform *
          math::PointF(vert.position[0], vert.position[1]);
      vert.position[0] = pos.x();
      vert.position[1] = pos.y();
      in_scissor = in_scissor &&
                   pos.x() >= x_min && pos.x() <= x_max &&
                   pos.y() >= y_min && pos.y() <= y_max;
    }
  }

  base_state_.transform = math::Matrix3F::Identity();
  can_merge_ = in_scissor;
  return *can_merge_;
}

}  // namespace egl
}  // namespace rasterizer
}  // namespace renderer
}  // namespace cobalt
