blob: ebf8c4da46b613bbfc6f9d4d8d9e35e589eb677a [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/vr/elements/controller.h"
#include "base/trace_event/trace_event.h"
#include "chrome/browser/vr/controller_mesh.h"
#include "chrome/browser/vr/ui_element_renderer.h"
#include "chrome/browser/vr/vr_gl_util.h"
namespace vr {
namespace {
// clang-format off
static constexpr char const* kVertexShader = SHADER(
precision mediump float;
uniform mat4 u_ModelViewProjMatrix;
attribute vec4 a_Position;
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoordinate;
void main() {
v_TexCoordinate = a_TexCoordinate;
gl_Position = u_ModelViewProjMatrix * a_Position;
}
);
static constexpr char const* kFragmentShader = SHADER(
precision mediump float;
uniform sampler2D u_texture;
varying vec2 v_TexCoordinate;
uniform mediump float u_Opacity;
void main() {
lowp vec4 texture_color = texture2D(u_texture, v_TexCoordinate);
gl_FragColor = texture_color * u_Opacity;
}
);
// clang-format on
} // namespace
Controller::Controller() {
SetName(kController);
set_hit_testable(false);
SetVisible(true);
}
Controller::~Controller() = default;
void Controller::Render(UiElementRenderer* renderer,
const CameraModel& model) const {
ControllerMesh::State state;
if (touchpad_button_pressed_) {
state = ControllerMesh::TOUCHPAD;
} else if (app_button_pressed_) {
state = ControllerMesh::APP;
} else if (home_button_pressed_) {
state = ControllerMesh::SYSTEM;
} else {
state = ControllerMesh::IDLE;
}
renderer->DrawController(state, computed_opacity(),
model.view_proj_matrix * world_space_transform());
}
gfx::Transform Controller::LocalTransform() const {
return local_transform_;
}
Controller::Renderer::Renderer()
: BaseRenderer(kVertexShader, kFragmentShader),
texture_handles_(ControllerMesh::STATE_COUNT) {
model_view_proj_matrix_handle_ =
glGetUniformLocation(program_handle_, "u_ModelViewProjMatrix");
tex_coord_handle_ = glGetAttribLocation(program_handle_, "a_TexCoordinate");
texture_handle_ = glGetUniformLocation(program_handle_, "u_Texture");
opacity_handle_ = glGetUniformLocation(program_handle_, "u_Opacity");
}
Controller::Renderer::~Renderer() = default;
void Controller::Renderer::SetUp(std::unique_ptr<ControllerMesh> model) {
TRACE_EVENT0("gpu", "ControllerRenderer::SetUp");
glGenBuffersARB(1, &indices_buffer_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->IndicesBufferSize(),
model->IndicesBuffer(), GL_STATIC_DRAW);
glGenBuffersARB(1, &vertex_buffer_);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBufferData(GL_ARRAY_BUFFER, model->ElementsBufferSize(),
model->ElementsBuffer(), GL_STATIC_DRAW);
glGenTextures(ControllerMesh::STATE_COUNT, texture_handles_.data());
for (int i = 0; i < ControllerMesh::STATE_COUNT; i++) {
sk_sp<SkImage> texture = model->GetTexture(i);
SkPixmap pixmap;
if (!texture->peekPixels(&pixmap)) {
LOG(ERROR) << "Failed to read controller texture pixels";
continue;
}
glBindTexture(GL_TEXTURE_2D, texture_handles_[i]);
SetTexParameters(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixmap.width(), pixmap.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixmap.addr());
}
const vr::gltf::Accessor* accessor = model->PositionAccessor();
position_components_ = vr::gltf::GetTypeComponents(accessor->type);
position_type_ = accessor->component_type;
position_stride_ = accessor->byte_stride;
position_offset_ = VOID_OFFSET(accessor->byte_offset);
accessor = model->TextureCoordinateAccessor();
tex_coord_components_ = vr::gltf::GetTypeComponents(accessor->type);
tex_coord_type_ = accessor->component_type;
tex_coord_stride_ = accessor->byte_stride;
tex_coord_offset_ = VOID_OFFSET(accessor->byte_offset);
draw_mode_ = model->DrawMode();
accessor = model->IndicesAccessor();
indices_count_ = accessor->count;
indices_type_ = accessor->component_type;
indices_offset_ = VOID_OFFSET(accessor->byte_offset);
setup_ = true;
}
void Controller::Renderer::Draw(ControllerMesh::State state,
float opacity,
const gfx::Transform& model_view_proj_matrix) {
glUseProgram(program_handle_);
glUniform1f(opacity_handle_, opacity);
glUniformMatrix4fv(model_view_proj_matrix_handle_, 1, false,
MatrixToGLArray(model_view_proj_matrix).data());
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glVertexAttribPointer(position_handle_, position_components_, position_type_,
GL_FALSE, position_stride_, position_offset_);
glEnableVertexAttribArray(position_handle_);
glVertexAttribPointer(tex_coord_handle_, tex_coord_components_,
tex_coord_type_, GL_FALSE, tex_coord_stride_,
tex_coord_offset_);
glEnableVertexAttribArray(tex_coord_handle_);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_handles_[state]);
glUniform1i(texture_handle_, 0);
glDrawElements(draw_mode_, indices_count_, indices_type_, indices_offset_);
}
} // namespace vr