// Copyright 2017 The Fuchsia 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 "lib/ui/scenic/cpp/resources.h"
#include <algorithm>
#include "lib/images/cpp/images.h"
#include "lib/ui/scenic/cpp/commands.h"
namespace scenic {
namespace {
template <class T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return (v < lo) ? lo : (hi < v) ? hi : v;
}
} // namespace
Resource::Resource(Session* session)
: session_(session), id_(session->AllocResourceId()) {}
Resource::Resource(Resource&& moved)
: session_(moved.session_), id_(moved.id_) {
auto& moved_session = *const_cast<Session**>(&moved.session_);
auto& moved_id = *const_cast<uint32_t*>(&moved.id_);
moved_session = nullptr;
moved_id = 0;
}
Resource::~Resource() {
// If this resource was moved, it is not responsible for releasing the ID.
if (session_)
session_->ReleaseResource(id_);
}
void Resource::Export(zx::eventpair export_token) {
session_->Enqueue(NewExportResourceCmd(id(), std::move(export_token)));
}
void Resource::ExportAsRequest(zx::eventpair* out_import_token) {
session_->Enqueue(NewExportResourceCmdAsRequest(id(), out_import_token));
}
void Resource::SetEventMask(uint32_t event_mask) {
session_->Enqueue(NewSetEventMaskCmd(id(), event_mask));
}
void Resource::SetLabel(const std::string& label) {
session_->Enqueue(NewSetLabelCmd(id(), label));
}
Shape::Shape(Session* session) : Resource(session) {}
Shape::Shape(Shape&& moved) : Resource(std::move(moved)) {}
Shape::~Shape() = default;
Circle::Circle(Session* session, float radius) : Shape(session) {
session->Enqueue(NewCreateCircleCmd(id(), radius));
}
Circle::Circle(Circle&& moved) : Shape(std::move(moved)) {}
Circle::~Circle() = default;
Rectangle::Rectangle(Session* session, float width, float height)
: Shape(session) {
session->Enqueue(NewCreateRectangleCmd(id(), width, height));
}
Rectangle::Rectangle(Rectangle&& moved) : Shape(std::move(moved)) {}
Rectangle::~Rectangle() = default;
RoundedRectangle::RoundedRectangle(Session* session, float width, float height,
float top_left_radius,
float top_right_radius,
float bottom_right_radius,
float bottom_left_radius)
: Shape(session) {
session->Enqueue(NewCreateRoundedRectangleCmd(
id(), width, height, top_left_radius, top_right_radius,
bottom_right_radius, bottom_left_radius));
}
RoundedRectangle::RoundedRectangle(RoundedRectangle&& moved)
: Shape(std::move(moved)) {}
RoundedRectangle::~RoundedRectangle() = default;
Image::Image(const Memory& memory, off_t memory_offset,
fuchsia::images::ImageInfo info)
: Image(memory.session(), memory.id(), memory_offset, std::move(info)) {}
Image::Image(Session* session, uint32_t memory_id, off_t memory_offset,
fuchsia::images::ImageInfo info)
: Resource(session), memory_offset_(memory_offset), info_(info) {
session->Enqueue(
NewCreateImageCmd(id(), memory_id, memory_offset_, std::move(info)));
}
Image::Image(Image&& moved)
: Resource(std::move(moved)),
memory_offset_(moved.memory_offset_),
info_(moved.info_) {}
Image::~Image() = default;
size_t Image::ComputeSize(const fuchsia::images::ImageInfo& image_info) {
return images::ImageSize(image_info);
}
Buffer::Buffer(const Memory& memory, off_t memory_offset, size_t num_bytes)
: Buffer(memory.session(), memory.id(), memory_offset, num_bytes) {}
Buffer::Buffer(Session* session, uint32_t memory_id, off_t memory_offset,
size_t num_bytes)
: Resource(session) {
session->Enqueue(
NewCreateBufferCmd(id(), memory_id, memory_offset, num_bytes));
}
Buffer::Buffer(Buffer&& moved) : Resource(std::move(moved)) {}
Buffer::~Buffer() = default;
Memory::Memory(Session* session, zx::vmo vmo, uint64_t allocation_size,
fuchsia::images::MemoryType memory_type)
: Resource(session), memory_type_(memory_type) {
session->Enqueue(
NewCreateMemoryCmd(id(), std::move(vmo), allocation_size, memory_type));
}
Memory::Memory(Memory&& moved)
: Resource(std::move(moved)), memory_type_(moved.memory_type_) {}
Memory::~Memory() = default;
Mesh::Mesh(Session* session) : Shape(session) {
session->Enqueue(NewCreateMeshCmd(id()));
}
Mesh::Mesh(Mesh&& moved) : Shape(std::move(moved)) {}
Mesh::~Mesh() = default;
void Mesh::BindBuffers(const Buffer& index_buffer,
fuchsia::ui::gfx::MeshIndexFormat index_format,
uint64_t index_offset, uint32_t index_count,
const Buffer& vertex_buffer,
fuchsia::ui::gfx::MeshVertexFormat vertex_format,
uint64_t vertex_offset, uint32_t vertex_count,
const float bounding_box_min[3],
const float bounding_box_max[3]) {
ZX_DEBUG_ASSERT(session() == index_buffer.session() &&
session() == vertex_buffer.session());
session()->Enqueue(NewBindMeshBuffersCmd(
id(), index_buffer.id(), index_format, index_offset, index_count,
vertex_buffer.id(), std::move(vertex_format), vertex_offset, vertex_count,
bounding_box_min, bounding_box_max));
}
Material::Material(Session* session) : Resource(session) {
session->Enqueue(NewCreateMaterialCmd(id()));
}
Material::Material(Material&& moved) : Resource(std::move(moved)) {}
Material::~Material() = default;
void Material::SetTexture(uint32_t image_id) {
session()->Enqueue(NewSetTextureCmd(id(), image_id));
}
void Material::SetColor(uint8_t red, uint8_t green, uint8_t blue,
uint8_t alpha) {
session()->Enqueue(NewSetColorCmd(id(), red, green, blue, alpha));
}
Node::Node(Session* session) : Resource(session) {}
Node::Node(Node&& moved) : Resource(std::move(moved)) {}
Node::~Node() = default;
void Node::SetTranslation(const float translation[3]) {
session()->Enqueue(NewSetTranslationCmd(id(), translation));
}
void Node::SetTranslation(uint32_t variable_id) {
session()->Enqueue(NewSetTranslationCmd(id(), variable_id));
}
void Node::SetScale(const float scale[3]) {
session()->Enqueue(NewSetScaleCmd(id(), scale));
}
void Node::SetScale(uint32_t variable_id) {
session()->Enqueue(NewSetScaleCmd(id(), variable_id));
}
void Node::SetRotation(const float quaternion[4]) {
session()->Enqueue(NewSetRotationCmd(id(), quaternion));
}
void Node::SetRotation(uint32_t variable_id) {
session()->Enqueue(NewSetRotationCmd(id(), variable_id));
}
void Node::SetAnchor(const float anchor[3]) {
session()->Enqueue(NewSetAnchorCmd(id(), anchor));
}
void Node::SetAnchor(uint32_t variable_id) {
session()->Enqueue(NewSetAnchorCmd(id(), variable_id));
}
void Node::SendSizeChangeHint(float width_change_factor,
float height_change_factor) {
session()->Enqueue(NewSendSizeChangeHintCmdHACK(id(), width_change_factor,
height_change_factor));
}
void Node::SetTag(uint32_t tag_value) {
session()->Enqueue(NewSetTagCmd(id(), tag_value));
}
void Node::SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior hit_test_behavior) {
session()->Enqueue(NewSetHitTestBehaviorCmd(id(), hit_test_behavior));
}
void Node::Detach() { session()->Enqueue(NewDetachCmd(id())); }
ShapeNode::ShapeNode(Session* session) : Node(session) {
session->Enqueue(NewCreateShapeNodeCmd(id()));
}
ShapeNode::ShapeNode(ShapeNode&& moved) : Node(std::move(moved)) {}
ShapeNode::~ShapeNode() = default;
void ShapeNode::SetShape(uint32_t shape_id) {
session()->Enqueue(NewSetShapeCmd(id(), shape_id));
}
void ShapeNode::SetMaterial(uint32_t material_id) {
session()->Enqueue(NewSetMaterialCmd(id(), material_id));
}
ContainerNode::ContainerNode(Session* session) : Node(session) {}
ContainerNode::ContainerNode(ContainerNode&& moved) : Node(std::move(moved)) {}
ContainerNode::~ContainerNode() = default;
void ContainerNode::AddChild(uint32_t child_node_id) {
session()->Enqueue(NewAddChildCmd(id(), child_node_id));
}
void ContainerNode::AddPart(uint32_t part_node_id) {
session()->Enqueue(NewAddPartCmd(id(), part_node_id));
}
void ContainerNode::DetachChildren() {
session()->Enqueue(NewDetachChildrenCmd(id()));
}
EntityNode::EntityNode(Session* session) : ContainerNode(session) {
session->Enqueue(NewCreateEntityNodeCmd(id()));
}
void EntityNode::Attach(const ViewHolder& view_holder) {
session()->Enqueue(NewAddChildCmd(id(), view_holder.id()));
}
void EntityNode::Snapshot(fuchsia::ui::gfx::SnapshotCallbackHACKPtr callback) {
session()->Enqueue(NewTakeSnapshotCmdHACK(id(), std::move(callback)));
}
EntityNode::~EntityNode() = default;
void EntityNode::SetClip(uint32_t clip_id, bool clip_to_self) {
session()->Enqueue(NewSetClipCmd(id(), clip_id, clip_to_self));
}
ImportNode::ImportNode(Session* session) : ContainerNode(session) {}
ImportNode::ImportNode(ImportNode&& moved) : ContainerNode(std::move(moved)) {}
ImportNode::~ImportNode() {
ZX_DEBUG_ASSERT_MSG(is_bound_, "Import was never bound.");
}
void ImportNode::Bind(zx::eventpair import_token) {
ZX_DEBUG_ASSERT(!is_bound_);
session()->Enqueue(NewImportResourceCmd(
id(), fuchsia::ui::gfx::ImportSpec::NODE, std::move(import_token)));
is_bound_ = true;
}
void ImportNode::BindAsRequest(zx::eventpair* out_export_token) {
ZX_DEBUG_ASSERT(!is_bound_);
session()->Enqueue(NewImportResourceCmdAsRequest(
id(), fuchsia::ui::gfx::ImportSpec::NODE, out_export_token));
is_bound_ = true;
}
ViewHolder::ViewHolder(Session* session, zx::eventpair token,
const std::string& debug_name)
: Resource(session) {
session->Enqueue(NewCreateViewHolderCmd(id(), std::move(token), debug_name));
}
ViewHolder::~ViewHolder() = default;
void ViewHolder::SetViewProperties(const float bounding_box_min[3],
const float bounding_box_max[3],
const float inset_from_min[3],
const float inset_from_max[3]) {
session()->Enqueue(NewSetViewPropertiesCmd(id(), bounding_box_min,
bounding_box_max, inset_from_min,
inset_from_max));
}
void ViewHolder::SetViewProperties(
const fuchsia::ui::gfx::ViewProperties& props) {
session()->Enqueue(NewSetViewPropertiesCmd(id(), props));
}
View::View(Session* session, zx::eventpair token, const std::string& debug_name)
: Resource(session) {
session->Enqueue(NewCreateViewCmd(id(), std::move(token), debug_name));
}
View::~View() = default;
void View::AddChild(const Node& child) const {
ZX_DEBUG_ASSERT(session() == child.session());
session()->Enqueue(NewAddChildCmd(id(), child.id()));
}
void View::DetachChild(const Node& child) const {
ZX_DEBUG_ASSERT(session() == child.session());
session()->Enqueue(NewDetachCmd(child.id()));
}
ClipNode::ClipNode(Session* session) : ContainerNode(session) {
session->Enqueue(NewCreateClipNodeCmd(id()));
}
ClipNode::ClipNode(ClipNode&& moved) : ContainerNode(std::move(moved)) {}
ClipNode::~ClipNode() = default;
OpacityNode::OpacityNode(Session* session) : ContainerNode(session) {
session->Enqueue(NewCreateOpacityNodeCmd(id()));
}
OpacityNode::OpacityNode(OpacityNode&& moved)
: ContainerNode(std::move(moved)) {}
OpacityNode::~OpacityNode() = default;
void OpacityNode::SetOpacity(float opacity) {
opacity = clamp(opacity, 0.f, 1.f);
session()->Enqueue(NewSetOpacityCmd(id(), opacity));
}
Variable::Variable(Session* session, fuchsia::ui::gfx::Value initial_value)
: Resource(session) {
session->Enqueue(NewCreateVariableCmd(id(), std::move(initial_value)));
}
Variable::Variable(Variable&& moved) : Resource(std::move(moved)) {}
Variable::~Variable() = default;
Scene::Scene(Session* session) : ContainerNode(session) {
session->Enqueue(NewCreateSceneCmd(id()));
}
Scene::Scene(Scene&& moved) : ContainerNode(std::move(moved)) {}
Scene::~Scene() = default;
void Scene::AddLight(uint32_t light_id) {
session()->Enqueue(NewAddLightCmd(id(), light_id));
}
void Scene::DetachLights() { session()->Enqueue(NewDetachLightsCmd(id())); }
void CameraBase::SetTransform(const float eye_position[3],
const float eye_look_at[3],
const float eye_up[3]) {
session()->Enqueue(
NewSetCameraTransformCmd(id(), eye_position, eye_look_at, eye_up));
}
void CameraBase::SetPoseBuffer(const Buffer& buffer, uint32_t num_entries,
int64_t base_time, uint64_t time_interval) {
session()->Enqueue(NewSetCameraPoseBufferCmd(id(), buffer.id(), num_entries,
base_time, time_interval));
}
Camera::Camera(const Scene& scene) : Camera(scene.session(), scene.id()) {}
Camera::Camera(Session* session, uint32_t scene_id) : CameraBase(session) {
session->Enqueue(NewCreateCameraCmd(id(), scene_id));
}
Camera::Camera(Camera&& moved) : CameraBase(std::move(moved)) {}
Camera::~Camera() = default;
void Camera::SetProjection(const float fovy) {
session()->Enqueue(NewSetCameraProjectionCmd(id(), fovy));
}
StereoCamera::StereoCamera(const Scene& scene)
: StereoCamera(scene.session(), scene.id()) {}
StereoCamera::StereoCamera(Session* session, uint32_t scene_id)
: CameraBase(session) {
session->Enqueue(NewCreateStereoCameraCmd(id(), scene_id));
}
StereoCamera::StereoCamera(StereoCamera&& moved)
: CameraBase(std::move(moved)) {}
StereoCamera::~StereoCamera() = default;
void StereoCamera::SetStereoProjection(const float left_projection[16],
const float right_projection[16]) {
session()->Enqueue(
NewSetStereoCameraProjectionCmd(id(), left_projection, right_projection));
}
Renderer::Renderer(Session* session) : Resource(session) {
session->Enqueue(NewCreateRendererCmd(id()));
}
Renderer::Renderer(Renderer&& moved) : Resource(std::move(moved)) {}
Renderer::~Renderer() = default;
void Renderer::SetCamera(uint32_t camera_id) {
session()->Enqueue(NewSetCameraCmd(id(), camera_id));
}
void Renderer::SetParam(fuchsia::ui::gfx::RendererParam param) {
session()->Enqueue(NewSetRendererParamCmd(id(), std::move(param)));
}
void Renderer::SetShadowTechnique(fuchsia::ui::gfx::ShadowTechnique technique) {
auto param = fuchsia::ui::gfx::RendererParam();
param.set_shadow_technique(technique);
SetParam(std::move(param));
}
void Renderer::SetDisableClipping(bool disable_clipping) {
session()->Enqueue(NewSetDisableClippingCmd(id(), disable_clipping));
}
Layer::Layer(Session* session) : Resource(session) {
session->Enqueue(NewCreateLayerCmd(id()));
}
Layer::Layer(Layer&& moved) : Resource(std::move(moved)) {}
Layer::~Layer() = default;
void Layer::SetRenderer(uint32_t renderer_id) {
session()->Enqueue(NewSetRendererCmd(id(), renderer_id));
}
void Layer::SetSize(const float size[2]) {
session()->Enqueue(NewSetSizeCmd(id(), size));
}
LayerStack::LayerStack(Session* session) : Resource(session) {
session->Enqueue(NewCreateLayerStackCmd(id()));
}
LayerStack::LayerStack(LayerStack&& moved) : Resource(std::move(moved)) {}
LayerStack::~LayerStack() = default;
void LayerStack::AddLayer(uint32_t layer_id) {
session()->Enqueue(NewAddLayerCmd(id(), layer_id));
}
void LayerStack::RemoveLayer(uint32_t layer_id) {
session()->Enqueue(NewRemoveLayerCmd(id(), layer_id));
}
void LayerStack::RemoveAllLayers() {
session()->Enqueue(NewRemoveAllLayersCmd(id()));
}
DisplayCompositor::DisplayCompositor(Session* session) : Resource(session) {
session->Enqueue(NewCreateDisplayCompositorCmd(id()));
}
DisplayCompositor::DisplayCompositor(DisplayCompositor&& moved)
: Resource(std::move(moved)) {}
DisplayCompositor::~DisplayCompositor() = default;
void DisplayCompositor::SetLayerStack(uint32_t layer_stack_id) {
session()->Enqueue(NewSetLayerStackCmd(id(), layer_stack_id));
}
Compositor::Compositor(Session* session) : Resource(session) {
session->Enqueue(NewCreateCompositorCmd(id()));
}
Compositor::Compositor(Compositor&& moved) : Resource(std::move(moved)) {}
Compositor::~Compositor() = default;
void Compositor::SetLayerStack(uint32_t layer_stack_id) {
session()->Enqueue(NewSetLayerStackCmd(id(), layer_stack_id));
}
Light::Light(Session* session) : Resource(session) {}
Light::Light(Light&& moved) : Resource(std::move(moved)) {}
Light::~Light() = default;
void Light::SetColor(const float rgb[3]) {
session()->Enqueue(NewSetLightColorCmd(id(), rgb));
}
void Light::SetColor(uint32_t variable_id) {
session()->Enqueue(NewSetLightColorCmd(id(), variable_id));
}
void Light::Detach() { session()->Enqueue(NewDetachLightCmd(id())); }
AmbientLight::AmbientLight(Session* session) : Light(session) {
session->Enqueue(NewCreateAmbientLightCmd(id()));
}
AmbientLight::AmbientLight(AmbientLight&& moved) : Light(std::move(moved)) {}
AmbientLight::~AmbientLight() = default;
DirectionalLight::DirectionalLight(Session* session) : Light(session) {
session->Enqueue(NewCreateDirectionalLightCmd(id()));
}
DirectionalLight::DirectionalLight(DirectionalLight&& moved)
: Light(std::move(moved)) {}
DirectionalLight::~DirectionalLight() = default;
void DirectionalLight::SetDirection(const float direction[3]) {
session()->Enqueue(NewSetLightDirectionCmd(id(), direction));
}
void DirectionalLight::SetDirection(uint32_t variable_id) {
session()->Enqueue(NewSetLightDirectionCmd(id(), variable_id));
}
} // namespace scenic