blob: ebd5a8c3a3199cbc3b1397df3c859fe0b5674508 [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. 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.
#ifndef COBALT_RENDER_TREE_MAP_TO_MESH_FILTER_H_
#define COBALT_RENDER_TREE_MAP_TO_MESH_FILTER_H_
#include <map>
#include <utility>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "cobalt/math/size.h"
#include "cobalt/render_tree/mesh.h"
namespace cobalt {
namespace render_tree {
enum StereoMode {
kMono = 0,
// Stereoscopic modes where each half of the content represents the view of
// one eye, and where the texture coordinates of the meshes need to be
// scaled and offset to the appropriate half. The same mesh may be used for
// both eyes, or there may be one for each eye.
kLeftRight = 1,
kTopBottom = 2,
// Like kLeftRight, but where the texture coordinates already refer to the
// corresponding half of the content and need no adjustment. This can only
// happen when there are distinct meshes for each eye.
kLeftRightUnadjustedTextureCoords = 3
};
// The shape of the mesh that this filter applies.
enum MeshType {
// Rectangular content: some rasterizers render rectangular video separately
// from the rest of the document (for example, for stereo content). Does not
// specify a custom mesh, since a rectangle with the content's aspect ratio
// can be assumed (accounting for whether it needs to be halved in one
// dimension for stereo). Not enabled on all rasterizers/platforms.
kRectangular = 0,
// Mesh that is centered around the camera; examples include 360 and 180
// content. Needs to be specified, since the shape is arbitrary.
kCustomMesh = 1
};
// A MapToMeshFilter can be used to map source content onto a 3D mesh, within a
// specified well-defined viewport.
class MapToMeshFilter {
public:
struct Builder {
Builder() {}
bool operator==(const Builder& other) const {
return resolution_matched_meshes_ == other.resolution_matched_meshes_ &&
left_eye_default_mesh_ == other.left_eye_default_mesh_ &&
right_eye_default_mesh_ == other.right_eye_default_mesh_;
}
void SetDefaultMeshes(
const scoped_refptr<render_tree::Mesh>& left_eye_mesh,
const scoped_refptr<render_tree::Mesh>& right_eye_mesh) {
left_eye_default_mesh_ = left_eye_mesh;
right_eye_default_mesh_ = right_eye_mesh;
}
void AddResolutionMatchedMeshes(
math::Size resolution,
const scoped_refptr<render_tree::Mesh>& left_eye_mesh,
const scoped_refptr<render_tree::Mesh>& right_eye_mesh) {
DCHECK_GT(resolution.width(), 0);
DCHECK_GT(resolution.height(), 0);
DCHECK(left_eye_mesh);
resolution_matched_meshes_[resolution] =
std::make_pair(left_eye_mesh, right_eye_mesh);
}
const scoped_refptr<render_tree::Mesh>& left_eye_mesh(
math::Size resolution) const {
MeshMap::const_iterator match =
resolution_matched_meshes_.find(resolution);
if (match != resolution_matched_meshes_.end()) {
return match->second.first;
}
return left_eye_default_mesh_;
}
const scoped_refptr<render_tree::Mesh>& right_eye_mesh(
math::Size resolution) const {
MeshMap::const_iterator match =
resolution_matched_meshes_.find(resolution);
if (match != resolution_matched_meshes_.end()) {
return match->second.second;
}
return right_eye_default_mesh_;
}
private:
struct SizeLessThan {
bool operator()(const math::Size& a, const math::Size& b) const {
return a.width() < b.width() ||
(a.width() == b.width() && a.height() < b.height());
}
};
typedef std::pair<scoped_refptr<render_tree::Mesh>,
scoped_refptr<render_tree::Mesh> >
MeshPair;
typedef std::map<math::Size, MeshPair, SizeLessThan> MeshMap;
MeshMap resolution_matched_meshes_;
scoped_refptr<render_tree::Mesh> left_eye_default_mesh_;
scoped_refptr<render_tree::Mesh> right_eye_default_mesh_;
};
MapToMeshFilter(StereoMode stereo_mode, const Builder& builder)
: stereo_mode_(stereo_mode), mesh_type_(kCustomMesh), data_(builder) {
DCHECK(left_eye_mesh());
if (stereo_mode == kLeftRightUnadjustedTextureCoords) {
// This stereo mode implies there are two meshes.
DCHECK(right_eye_mesh());
}
}
// A filter without a an explicit mesh, to represent mesh-mapped content whose
// mesh will be supplied externally.
MapToMeshFilter(StereoMode stereo_mode, MeshType mesh_type)
: stereo_mode_(stereo_mode), mesh_type_(mesh_type), data_() {
DCHECK(mesh_type != kCustomMesh);
DCHECK(stereo_mode != kLeftRightUnadjustedTextureCoords);
}
bool operator==(const MapToMeshFilter& other) const {
return stereo_mode_ == other.stereo_mode_ && data_ == other.data_;
}
StereoMode stereo_mode() const { return stereo_mode_; }
MeshType mesh_type() const { return mesh_type_; }
// The omission of the |resolution| parameter will yield the default
// meshes in each of the following functions (by failing to match the
// invalid resolution).
const scoped_refptr<render_tree::Mesh>& mono_mesh(
math::Size resolution = InvalidSize()) const {
return data_.left_eye_mesh(resolution);
}
const scoped_refptr<render_tree::Mesh>& left_eye_mesh(
math::Size resolution = InvalidSize()) const {
return data_.left_eye_mesh(resolution);
}
const scoped_refptr<render_tree::Mesh>& right_eye_mesh(
math::Size resolution = InvalidSize()) const {
return data_.right_eye_mesh(resolution);
}
private:
static math::Size InvalidSize() { return math::Size(-1, -1); }
StereoMode stereo_mode_;
MeshType mesh_type_;
Builder data_;
};
} // namespace render_tree
} // namespace cobalt
#endif // COBALT_RENDER_TREE_MAP_TO_MESH_FILTER_H_