blob: 7dc30dbf098d25edaef19be3ab5f5827722d5e14 [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/android/vr_shell/vr_controller_model.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/android/vr_shell/gltf_parser.h"
#include "chrome/grit/browser_resources.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/codec/png_codec.h"
namespace vr_shell {
namespace {
enum {
ELEMENTS_BUFFER_ID = 0,
INDICES_BUFFER_ID = 1,
};
constexpr char kPosition[] = "POSITION";
constexpr char kTexCoord[] = "TEXCOORD_0";
const int kTexturePatchesResources[] = {
-1, IDR_VR_SHELL_DDCONTROLLER_TOUCHPAD_PATCH,
IDR_VR_SHELL_DDCONTROLLER_APP_PATCH, IDR_VR_SHELL_DDCONTROLLER_SYSTEM_PATCH,
};
const gfx::Point kPatchesLocations[] = {{}, {5, 5}, {47, 165}, {47, 234}};
sk_sp<SkImage> LoadPng(int resource_id) {
base::StringPiece data =
ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
SkBitmap bitmap;
bool decoded =
gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(data.data()),
data.size(), &bitmap);
DCHECK(decoded);
DCHECK(bitmap.colorType() == kRGBA_8888_SkColorType);
return SkImage::MakeFromBitmap(bitmap);
}
} // namespace
VrControllerModel::VrControllerModel(
std::unique_ptr<gltf::Asset> gltf_asset,
std::vector<std::unique_ptr<gltf::Buffer>> buffers)
: gltf_asset_(std::move(gltf_asset)),
buffers_(std::move(buffers)) {}
VrControllerModel::~VrControllerModel() = default;
const GLvoid* VrControllerModel::ElementsBuffer() const {
const gltf::BufferView* buffer_view =
gltf_asset_->GetBufferView(ELEMENTS_BUFFER_ID);
DCHECK(buffer_view && buffer_view->target == GL_ARRAY_BUFFER);
const char* buffer = Buffer();
return buffer ? buffer + buffer_view->byte_offset : nullptr;
}
GLsizeiptr VrControllerModel::ElementsBufferSize() const {
const gltf::BufferView* buffer_view =
gltf_asset_->GetBufferView(ELEMENTS_BUFFER_ID);
DCHECK(buffer_view && buffer_view->target == GL_ARRAY_BUFFER);
return buffer_view->byte_length;
}
const GLvoid* VrControllerModel::IndicesBuffer() const {
const gltf::BufferView* buffer_view =
gltf_asset_->GetBufferView(INDICES_BUFFER_ID);
DCHECK(buffer_view && buffer_view->target == GL_ELEMENT_ARRAY_BUFFER);
const char* buffer = Buffer();
return buffer ? buffer + buffer_view->byte_offset : nullptr;
}
GLsizeiptr VrControllerModel::IndicesBufferSize() const {
const gltf::BufferView* buffer_view =
gltf_asset_->GetBufferView(INDICES_BUFFER_ID);
DCHECK(buffer_view && buffer_view->target == GL_ELEMENT_ARRAY_BUFFER);
return buffer_view->byte_length;
}
GLenum VrControllerModel::DrawMode() const {
const gltf::Mesh* mesh = gltf_asset_->GetMesh(0);
DCHECK(mesh && mesh->primitives.size());
return mesh->primitives[0]->mode;
}
const gltf::Accessor* VrControllerModel::IndicesAccessor() const {
const gltf::Mesh* mesh = gltf_asset_->GetMesh(0);
DCHECK(mesh && mesh->primitives.size());
return mesh->primitives[0]->indices;
}
const gltf::Accessor* VrControllerModel::PositionAccessor() const {
return Accessor(kPosition);
}
const gltf::Accessor* VrControllerModel::TextureCoordinateAccessor() const {
return Accessor(kTexCoord);
}
void VrControllerModel::SetBaseTexture(sk_sp<SkImage> image) {
base_texture_ = image;
}
void VrControllerModel::SetTexturePatch(int state, sk_sp<SkImage> image) {
DCHECK(state >= 0 && state < STATE_COUNT);
patches_[state] = image;
}
sk_sp<SkImage> VrControllerModel::GetTexture(int state) const {
if (!patches_[state])
return base_texture_;
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
base_texture_->width(), base_texture_->height());
SkCanvas* canvas = surface->getCanvas();
canvas->drawImage(base_texture_, 0, 0);
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
canvas->drawImage(patches_[state], kPatchesLocations[state].x(),
kPatchesLocations[state].y(), &paint);
return sk_sp<SkImage>(surface->makeImageSnapshot());
}
const char* VrControllerModel::Buffer() const {
if (buffers_.empty())
return nullptr;
return buffers_[0]->data();
}
const gltf::Accessor* VrControllerModel::Accessor(
const std::string& key) const {
const gltf::Mesh* mesh = gltf_asset_->GetMesh(0);
DCHECK(mesh && mesh->primitives.size());
auto it = mesh->primitives[0]->attributes.find(key);
DCHECK(it != mesh->primitives[0]->attributes.begin());
return it->second;
}
std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() {
std::vector<std::unique_ptr<gltf::Buffer>> buffers;
auto model_data = ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_VR_SHELL_DDCONTROLLER_MODEL);
std::unique_ptr<gltf::Asset> asset =
BinaryGltfParser::Parse(model_data, &buffers);
DCHECK(asset);
auto controller_model =
base::MakeUnique<VrControllerModel>(std::move(asset), std::move(buffers));
sk_sp<SkImage> base_texture = LoadPng(IDR_VR_SHELL_DDCONTROLLER_IDLE_TEXTURE);
controller_model->SetBaseTexture(std::move(base_texture));
for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) {
if (kTexturePatchesResources[i] == -1)
continue;
auto patch_image = LoadPng(kTexturePatchesResources[i]);
controller_model->SetTexturePatch(i, patch_image);
}
return controller_model;
}
} // namespace vr_shell