Commit c76599f4 authored by acondor's avatar acondor Committed by Commit bot

VRShell: Composing Daydream controller textures from patches

This change implements the creation of textures from a base texture and a patch, in order to reduce the size of assets necessary for rendering the controller in VRShell.

BUG=644562

Review-Url: https://codereview.chromium.org/2837973002
Cr-Commit-Position: refs/heads/master@{#468121}
parent caaa5c77
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "chrome/browser/android/vr_shell/gltf_parser.h" #include "chrome/browser/android/vr_shell/gltf_parser.h"
#include "components/component_updater/component_updater_paths.h" #include "components/component_updater/component_updater_paths.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/gfx/codec/png_codec.h" #include "ui/gfx/codec/png_codec.h"
namespace vr_shell { namespace vr_shell {
...@@ -24,20 +27,40 @@ enum { ...@@ -24,20 +27,40 @@ enum {
constexpr char kPosition[] = "POSITION"; constexpr char kPosition[] = "POSITION";
constexpr char kTexCoord[] = "TEXCOORD_0"; constexpr char kTexCoord[] = "TEXCOORD_0";
} // namespace // TODO(acondor): Remove these hardcoded paths once VrShell resources
// are delivered through component updater.
constexpr char const kComponentName[] = "VrShell";
constexpr char const kDefaultVersion[] = "0";
constexpr char const kModelsDirectory[] = "models";
constexpr char const kModelFilename[] = "controller.gltf";
constexpr char const kTexturesDirectory[] = "tex";
constexpr char const kBaseTextureFilename[] = "ddcontroller_idle.png";
constexpr char const* kTexturePatchesFilenames[] = {
"", "ddcontroller_touchpad.png", "ddcontroller_app.png",
"ddcontroller_system.png",
};
const gfx::Point kPatchesLocations[] = {{}, {5, 5}, {47, 165}, {47, 234}};
sk_sp<SkImage> LoadPng(const base::FilePath& path) {
std::string data;
SkBitmap bitmap;
if (!base::ReadFileToString(path, &data) ||
!gfx::PNGCodec::Decode(
reinterpret_cast<const unsigned char*>(data.data()), data.size(),
&bitmap) ||
bitmap.colorType() != kRGBA_8888_SkColorType) {
return nullptr;
}
return SkImage::MakeFromBitmap(bitmap);
}
constexpr char const VrControllerModel::kComponentName[]; } // namespace
constexpr char const VrControllerModel::kDefaultVersion[];
constexpr char const VrControllerModel::kModelsDirectory[];
constexpr char const VrControllerModel::kModelFilename[];
constexpr char const VrControllerModel::kTexturesDirectory[];
constexpr char const* VrControllerModel::kTextureFilenames[];
VrControllerModel::VrControllerModel( VrControllerModel::VrControllerModel(
std::unique_ptr<gltf::Asset> gltf_asset, std::unique_ptr<gltf::Asset> gltf_asset,
std::vector<std::unique_ptr<gltf::Buffer>> buffers) std::vector<std::unique_ptr<gltf::Buffer>> buffers)
: gltf_asset_(std::move(gltf_asset)), : gltf_asset_(std::move(gltf_asset)),
texture_bitmaps_(State::STATE_COUNT),
buffers_(std::move(buffers)) {} buffers_(std::move(buffers)) {}
VrControllerModel::~VrControllerModel() = default; VrControllerModel::~VrControllerModel() = default;
...@@ -92,15 +115,27 @@ const gltf::Accessor* VrControllerModel::TextureCoordinateAccessor() const { ...@@ -92,15 +115,27 @@ const gltf::Accessor* VrControllerModel::TextureCoordinateAccessor() const {
return Accessor(kTexCoord); return Accessor(kTexCoord);
} }
void VrControllerModel::SetTexture(int state, void VrControllerModel::SetBaseTexture(sk_sp<SkImage> image) {
std::unique_ptr<SkBitmap> bitmap) { base_texture_ = image;
DCHECK(state >= 0 && state < STATE_COUNT);
texture_bitmaps_[state] = std::move(bitmap);
} }
const SkBitmap* VrControllerModel::GetTexture(int state) const { void VrControllerModel::SetTexturePatch(int state, sk_sp<SkImage> image) {
DCHECK(state >= 0 && state < STATE_COUNT); DCHECK(state >= 0 && state < STATE_COUNT);
return texture_bitmaps_[state].get(); 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 { const char* VrControllerModel::Buffer() const {
...@@ -121,10 +156,10 @@ const gltf::Accessor* VrControllerModel::Accessor( ...@@ -121,10 +156,10 @@ const gltf::Accessor* VrControllerModel::Accessor(
std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() { std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() {
base::FilePath models_path; base::FilePath models_path;
PathService::Get(component_updater::DIR_COMPONENT_USER, &models_path); PathService::Get(component_updater::DIR_COMPONENT_USER, &models_path);
models_path = models_path.Append(VrControllerModel::kComponentName) models_path = models_path.Append(kComponentName)
.Append(VrControllerModel::kDefaultVersion) .Append(kDefaultVersion)
.Append(VrControllerModel::kModelsDirectory); .Append(kModelsDirectory);
auto model_path = models_path.Append(VrControllerModel::kModelFilename); auto model_path = models_path.Append(kModelFilename);
// No further action if model file is not present // No further action if model file is not present
if (!base::PathExists(model_path)) { if (!base::PathExists(model_path)) {
...@@ -143,23 +178,25 @@ std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() { ...@@ -143,23 +178,25 @@ std::unique_ptr<VrControllerModel> VrControllerModel::LoadFromComponent() {
auto controller_model = auto controller_model =
base::MakeUnique<VrControllerModel>(std::move(asset), std::move(buffers)); base::MakeUnique<VrControllerModel>(std::move(asset), std::move(buffers));
auto textures_path = auto textures_path = models_path.Append(kTexturesDirectory);
models_path.Append(VrControllerModel::kTexturesDirectory);
auto base_texture = LoadPng(textures_path.Append(kBaseTextureFilename));
if (!base_texture) {
LOG(ERROR) << "Failed to read controller base texture";
return nullptr;
}
controller_model->SetBaseTexture(std::move(base_texture));
for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) { for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) {
auto texture_path = if (!kTexturePatchesFilenames[i][0])
textures_path.Append(VrControllerModel::kTextureFilenames[i]); continue;
std::string data; auto patch_image =
auto bitmap = base::MakeUnique<SkBitmap>(); LoadPng(textures_path.Append(kTexturePatchesFilenames[i]));
if (!base::ReadFileToString(texture_path, &data) || if (!patch_image) {
!gfx::PNGCodec::Decode( LOG(ERROR) << "Failed to read controller texture patch";
reinterpret_cast<const unsigned char*>(data.data()), data.size(), continue;
bitmap.get()) ||
bitmap->colorType() != kRGBA_8888_SkColorType) {
LOG(ERROR) << "Failed to read controller texture";
return nullptr;
} }
controller_model->SetTexture(i, std::move(bitmap)); controller_model->SetTexturePatch(i, patch_image);
} }
return controller_model; return controller_model;
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
#include <memory> #include <memory>
#include "chrome/browser/android/vr_shell/gltf_asset.h" #include "chrome/browser/android/vr_shell/gltf_asset.h"
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
namespace vr_shell { namespace vr_shell {
...@@ -24,19 +25,6 @@ class VrControllerModel { ...@@ -24,19 +25,6 @@ class VrControllerModel {
STATE_COUNT, STATE_COUNT,
}; };
// TODO(acondor): Remove these hardcoded paths once VrShell resources
// are delivered through component updater.
static constexpr char const kComponentName[] = "VrShell";
static constexpr char const kDefaultVersion[] = "0";
static constexpr char const kModelsDirectory[] = "models";
static constexpr char const kModelFilename[] = "controller.gltf";
static constexpr char const kTexturesDirectory[] = "tex";
static constexpr char const* kTextureFilenames[] = {
"ddcontroller_idle.png", "ddcontroller_touchpad.png",
"ddcontroller_app.png", "ddcontroller_system.png",
};
explicit VrControllerModel( explicit VrControllerModel(
std::unique_ptr<gltf::Asset> gltf_asset, std::unique_ptr<gltf::Asset> gltf_asset,
std::vector<std::unique_ptr<gltf::Buffer>> buffers); std::vector<std::unique_ptr<gltf::Buffer>> buffers);
...@@ -50,14 +38,16 @@ class VrControllerModel { ...@@ -50,14 +38,16 @@ class VrControllerModel {
const gltf::Accessor* IndicesAccessor() const; const gltf::Accessor* IndicesAccessor() const;
const gltf::Accessor* PositionAccessor() const; const gltf::Accessor* PositionAccessor() const;
const gltf::Accessor* TextureCoordinateAccessor() const; const gltf::Accessor* TextureCoordinateAccessor() const;
void SetTexture(int state, std::unique_ptr<SkBitmap> bitmap); void SetBaseTexture(sk_sp<SkImage> image);
const SkBitmap* GetTexture(int state) const; void SetTexturePatch(int state, sk_sp<SkImage> image);
sk_sp<SkImage> GetTexture(int state) const;
static std::unique_ptr<VrControllerModel> LoadFromComponent(); static std::unique_ptr<VrControllerModel> LoadFromComponent();
private: private:
std::unique_ptr<gltf::Asset> gltf_asset_; std::unique_ptr<gltf::Asset> gltf_asset_;
std::vector<std::unique_ptr<SkBitmap>> texture_bitmaps_; sk_sp<SkImage> base_texture_;
sk_sp<SkImage> patches_[STATE_COUNT];
std::vector<std::unique_ptr<gltf::Buffer>> buffers_; std::vector<std::unique_ptr<gltf::Buffer>> buffers_;
const char* Buffer() const; const char* Buffer() const;
......
...@@ -608,14 +608,19 @@ void ControllerRenderer::SetUp(std::unique_ptr<VrControllerModel> model) { ...@@ -608,14 +608,19 @@ void ControllerRenderer::SetUp(std::unique_ptr<VrControllerModel> model) {
glGenTextures(VrControllerModel::STATE_COUNT, texture_handles_.data()); glGenTextures(VrControllerModel::STATE_COUNT, texture_handles_.data());
for (int i = 0; i < VrControllerModel::STATE_COUNT; i++) { for (int i = 0; i < VrControllerModel::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]); glBindTexture(GL_TEXTURE_2D, texture_handles_[i]);
const SkBitmap* bitmap = model->GetTexture(i);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->width(), bitmap->height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 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_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixmap.width(), pixmap.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixmap.addr());
} }
const gltf::Accessor* accessor = model->PositionAccessor(); const gltf::Accessor* accessor = model->PositionAccessor();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment