blob: 0d0d4aad9cb58242f52a0d4e542a87f13444b26f [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.
#pragma once
#include <vector>
#include "garnet/bin/ui/scene_manager/engine/hit.h"
namespace scene_manager {
class Node;
class Session;
// Performs a hit test on the contents of a node.
class HitTester {
public:
HitTester();
~HitTester();
// Performs a hit test along the specified ray.
// Returns a list of hits sorted by increasing distance then by increasing
// tree depth. See the |Session.HitTest()| API for more information.
std::vector<Hit> HitTest(Node* node, const escher::ray4& ray);
private:
// Describes a possible hit within an enclosing tag node.
struct TagInfo {
static constexpr float kNoHit = std::numeric_limits<float>::infinity();
// The distance to the intersection as defined by |Hit.distance|.
float distance = kNoHit;
bool is_hit() const { return distance < kNoHit; }
void ReportIntersection(float d) {
if (d < distance)
distance = d;
}
};
// Describes a ray and its accumulated transform.
struct RayInfo {
// The ray to test in the object's coordinate system.
escher::ray4 ray;
// The accumulated inverse transformation matrix which maps the coordinate
// system of the node at which the hit test was initiated into the
// coordinate system of the object.
escher::mat4 inverse_transform;
};
// Accumulates hit test results from the node, as seen by its parent.
// Applies the node's transform to the ray stack.
// |ray_info_| must be in the parent's local coordinate system.
void AccumulateHitsOuter(Node* node);
// Accumulates hit test results from the node, as seen by the node itself.
// Applies the node's tag to the tag stack.
// |ray_info_| must be in the node's local coordinate system.
void AccumulateHitsLocal(Node* node);
// Accumulates hit test results from the node's content and children.
// |ray_info_| must be in the node's local coordinate system.
void AccumulateHitsInner(Node* node);
// Returns true if the ray passes through the node's parts.
// |ray| must be in the node's local coordinate system.
static bool IsRayWithinPartsInner(Node* node, const escher::ray4& ray);
// Returns true if the ray passes through the node's clipped content.
// |ray| must be in the parent's local coordinate system.
//
// TODO(MZ-207): The way this works only makes geometric sense if the ray
// is parallel to the camera projection at the point being sampled.
static bool IsRayWithinClippedContentOuter(Node* node,
const escher::ray4& ray);
// Returns true if the ray passes through the node's clipped content.
// |ray| must be in the node's local coordinate system.
static bool IsRayWithinClippedContentInner(Node* node,
const escher::ray4& ray);
// The vector which accumulates hits.
std::vector<Hit> hits_;
// The session in which the hit test was initiated.
// Only nodes belonging to this session will be considered.
Session* session_ = nullptr;
// The current tag information.
// Null if there is no enclosing tagged node.
TagInfo* tag_info_ = nullptr;
// The current ray information.
// Null if there is no hit test currently in progress.
RayInfo* ray_info_ = nullptr;
};
} // namespace scene_manager