blob: 9ef4f50ff5e3894ed72e25ed1468b6344eb1dcff [file] [log] [blame]
// 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.
#ifndef GARNET_LIB_UI_GFX_RESOURCES_NODES_NODE_H_
#define GARNET_LIB_UI_GFX_RESOURCES_NODES_NODE_H_
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "garnet/lib/ui/gfx/resources/nodes/variable_binding.h"
#include "garnet/lib/ui/gfx/resources/resource.h"
#include "garnet/lib/ui/gfx/resources/variable.h"
#include "src/lib/fxl/memory/ref_ptr.h"
#include "src/ui/lib/escher/geometry/bounding_box.h"
#include "src/ui/lib/escher/geometry/interval.h"
#include "src/ui/lib/escher/geometry/transform.h"
namespace scenic_impl {
namespace gfx {
class Node;
class Scene;
class View;
using NodePtr = fxl::RefPtr<Node>;
using ViewPtr = fxl::RefPtr<View>;
// Node is an abstract base class for all the concrete node types listed in
// scene/services/nodes.fidl.
class Node : public Resource {
public:
// Per-node intersection data for HitTester object.
struct IntersectionInfo {
// Maximum possible hit distance allowed.
static constexpr float kMaximumDistance = 1000000000.f;
// True if the ray intersects the given node.
bool did_hit = false;
// True if hit tester should traverse the node's descendants.
bool continue_with_children = true;
// Distance from ray origin to node hit point.
float distance = 0;
// Min and max extent of what can be hit.
escher::Interval interval = escher::Interval(0.f, kMaximumDistance);
};
static const ResourceTypeInfo kTypeInfo;
virtual ~Node() override;
bool AddChild(NodePtr child_node, ErrorReporter* error_reporter);
bool DetachChildren(ErrorReporter* error_reporter);
bool SetTagValue(uint32_t tag_value);
uint32_t tag_value() const { return tag_value_; }
bool SetTransform(const escher::Transform& transform, ErrorReporter* error_reporter);
bool SetTranslation(const escher::vec3& translation, ErrorReporter* error_reporter);
bool SetTranslation(Vector3VariablePtr translation, ErrorReporter* error_reporter);
bool SetScale(const escher::vec3& scale, ErrorReporter* error_reporter);
bool SetScale(Vector3VariablePtr scale, ErrorReporter* error_reporter);
bool SetRotation(const escher::quat& rotation, ErrorReporter* error_reporter);
bool SetRotation(QuaternionVariablePtr rotation, ErrorReporter* error_reporter);
bool SetAnchor(const escher::vec3& anchor, ErrorReporter* error_reporter);
bool SetAnchor(Vector3VariablePtr anchor, ErrorReporter* error_reporter);
bool SetClipToSelf(bool clip_to_self, ErrorReporter* error_reporter);
bool SetClipPlanes(std::vector<escher::plane3> clip_planes, ErrorReporter* error_reporter);
bool SetClipPlanesFromBBox(const escher::BoundingBox& box, ErrorReporter* error_reporter);
bool SetHitTestBehavior(::fuchsia::ui::gfx::HitTestBehavior behavior);
bool SendSizeChangeHint(float width_change_factor, float height_change_factor);
const escher::mat4& GetGlobalTransform() const;
const escher::Transform& transform() const { return transform_; }
const escher::vec3& translation() const { return transform_.translation; }
const escher::vec3& scale() const { return transform_.scale; }
const escher::quat& rotation() const { return transform_.rotation; }
const escher::vec3& anchor() const { return transform_.anchor; }
bool clip_to_self() const { return clip_to_self_; }
const std::vector<escher::plane3>& clip_planes() const { return clip_planes_; }
::fuchsia::ui::gfx::HitTestBehavior hit_test_behavior() const { return hit_test_behavior_; }
// The node's metrics as reported to the session listener.
::fuchsia::ui::gfx::Metrics reported_metrics() const { return reported_metrics_; }
void set_reported_metrics(::fuchsia::ui::gfx::Metrics metrics) { reported_metrics_ = metrics; }
// |Resource|, DetachCmd.
bool Detach(ErrorReporter* error_reporter) override;
Node* parent() const { return parent_; }
// Each Node caches its containing Scene. This is nullptr if the Node is not
// part of a Scene.
Scene* scene() const { return scene_; }
const std::vector<NodePtr>& children() const { return children_; }
bool SetEventMask(uint32_t event_mask) override;
void AddImport(Import* import, ErrorReporter* error_reporter) override;
void RemoveImport(Import* import) override;
// Computes the closest point of intersection between the ray's origin
// and the front side of the node's own content, excluding its descendants.
// Does not apply clipping.
//
// |out_distance| is set to the distance from the ray's origin to the
// closest point of intersection in multiples of the ray's direction vector.
//
// Returns true if there is an intersection, otherwise returns false and
// leaves |out_distance| unmodified.
virtual IntersectionInfo GetIntersection(const escher::ray4& ray,
const IntersectionInfo& parent_intersection) const;
// Walk up tree until we find the responsible View; otherwise return nullptr.
// N.B. Typically the view and node are in the same session, but it's possible
// to have them inhabit different sessions.
virtual ViewPtr FindOwningView() const;
protected:
Node(Session* session, ResourceId node_id, const ResourceTypeInfo& type_info);
// Returns whether or not this node can add the |child_node| as a child.
virtual bool CanAddChild(NodePtr child_node);
// Triggered on the node when the node's | scene_ | has changed, before its
// children are updated with the new scene.
virtual void OnSceneChanged() {}
// Protected so that Scene Node can set itself as a Scene.
Scene* scene_ = nullptr;
private:
// Describes the manner in which a node is related to its parent.
enum class ParentRelation { kNone, kChild, kImportDelegate };
// Identifies a specific spatial property.
enum NodeProperty { kTranslation, kScale, kRotation, kAnchor };
void InvalidateGlobalTransform();
void ComputeGlobalTransform() const;
void SetParent(Node* parent, ParentRelation relation);
void EraseChild(Node* part);
void ErasePart(Node* part);
// Reset the parent and any dependent properties like scene and global
// transform. This allows "detaching" from the parent without affecting the
// parent itself or firing the on_detached callback (which affects the
// containing View).
//
// Only called internally by the Node on its children, never externally.
void DetachInternal();
void RefreshScene(Scene* new_scene);
uint32_t tag_value_ = 0u;
Node* parent_ = nullptr;
ParentRelation parent_relation_ = ParentRelation::kNone;
// TODO(SCN-1299) Split out child behavior into ContainerNode class.
std::vector<NodePtr> children_;
std::unordered_map<NodeProperty, std::unique_ptr<VariableBinding>> bound_variables_;
escher::Transform transform_;
mutable escher::mat4 global_transform_;
mutable bool global_transform_dirty_ = true;
bool clip_to_self_ = false;
std::vector<escher::plane3> clip_planes_;
::fuchsia::ui::gfx::HitTestBehavior hit_test_behavior_ =
::fuchsia::ui::gfx::HitTestBehavior::kDefault;
::fuchsia::ui::gfx::Metrics reported_metrics_;
};
// Inline functions.
inline const escher::mat4& Node::GetGlobalTransform() const {
if (global_transform_dirty_) {
ComputeGlobalTransform();
global_transform_dirty_ = false;
}
return global_transform_;
}
} // namespace gfx
} // namespace scenic_impl
#endif // GARNET_LIB_UI_GFX_RESOURCES_NODES_NODE_H_