blob: c709d4050ae6c8337b045bd6d4e68a629efc57cb [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.
#include "src/ui/scenic/lib/gfx/resources/nodes/scene.h"
#include <trace/event.h>
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/ui/scenic/lib/gfx/resources/lights/ambient_light.h"
#include "src/ui/scenic/lib/gfx/resources/lights/directional_light.h"
#include "src/ui/scenic/lib/gfx/resources/lights/point_light.h"
#include "src/ui/scenic/lib/gfx/resources/view.h"
#include "src/ui/scenic/lib/scenic/event_reporter.h"
namespace scenic_impl {
namespace gfx {
const ResourceTypeInfo Scene::kTypeInfo = {ResourceType::kNode | ResourceType::kScene, "Scene"};
Scene::Scene(Session* session, SessionId session_id, ResourceId node_id,
fxl::WeakPtr<ViewTreeUpdater> view_tree_updater, EventReporterWeakPtr event_reporter)
: Node(session, session_id, node_id, Scene::kTypeInfo),
view_tree_updater_(view_tree_updater),
weak_factory_(this) {
scene_ = this;
{
// Safe and valid eventpair, by construction.
zx_status_t status = zx::eventpair::create(
/*flags*/ 0u, &control_ref_.reference, &view_ref_.reference);
FXL_DCHECK(status == ZX_OK);
// Remove signaling.
status = view_ref_.reference.replace(ZX_RIGHTS_BASIC, &view_ref_.reference);
FXL_DCHECK(status == ZX_OK);
FXL_DCHECK(validate_viewref(control_ref_, view_ref_));
view_ref_koid_ = fsl::GetKoid(view_ref_.reference.get());
FXL_DCHECK(view_ref_koid_ != ZX_KOID_INVALID);
}
{
TRACE_DURATION_BEGIN("gfx", "ResourceCtorViewRefClone");
fuchsia::ui::views::ViewRef clone;
fidl::Clone(view_ref_, &clone);
TRACE_DURATION_END("gfx", "ResourceCtorViewRefClone");
// Scene may *always* receive focus when connected to a compositor. If it is not actually
// connected to a compositor, the request-focus policy will ensure it is never sent focus.
fit::function<bool()> may_receive_focus = [] { return true; };
fit::function<std::optional<glm::mat4>()> global_transform = [weak_ptr = GetWeakPtr()] {
return weak_ptr ? std::optional<glm::mat4>{weak_ptr->GetGlobalTransform()} : std::nullopt;
};
fit::function<void(ViewHolderPtr)> add_annotation_view_holder = [](auto) {
FXL_NOTREACHED() << "Cannot create Annotation ViewHolder for Scene.";
};
FXL_DCHECK(session_id != 0u) << "GFX-side invariant for ViewTree";
if (view_tree_updater_) {
view_tree_updater_->AddUpdate(
ViewTreeNewRefNode{.view_ref = std::move(clone),
.event_reporter = std::move(event_reporter),
.may_receive_focus = std::move(may_receive_focus),
.global_transform = std::move(global_transform),
.add_annotation_view_holder = std::move(add_annotation_view_holder),
.session_id = session_id});
}
}
// NOTE: Whether or not this Scene is connected to the Compositor CANNOT be determined here (and
// hence we can't push ViewTreeMakeRoot(koid)). Instead, the session updater must determine which
// Scene is connected and explicitly make that Scene the root of the ViewTree.
}
Scene::~Scene() {
if (view_tree_updater_) {
view_tree_updater_->AddUpdate(ViewTreeDeleteNode({.koid = view_ref_koid_}));
}
}
void Scene::OnSceneChanged() {
FXL_CHECK(scene_ && scene_->global_id() == global_id())
<< "Error: "
<< "Scene cannot be changed to a different Scene.";
}
bool Scene::AddLight(const LightPtr& light, ErrorReporter* error_reporter) {
if (light->IsKindOf<AmbientLight>()) {
// TODO(SCN-1217): check for duplicates.
ambient_lights_.push_back(light->As<AmbientLight>());
return true;
} else if (light->IsKindOf<DirectionalLight>()) {
// TODO(SCN-1217): check for duplicates.
directional_lights_.push_back(light->As<DirectionalLight>());
return true;
} else if (light->IsKindOf<PointLight>()) {
// TODO(SCN-1217): check for duplicates.
point_lights_.push_back(light->As<PointLight>());
return true;
}
error_reporter->ERROR() << "scenic::gfx::Scene::AddLight(): unrecognized light type.";
return false;
}
bool Scene::AddAmbientLight(const AmbientLightPtr& light) {
ambient_lights_.push_back(light);
return true;
}
bool Scene::AddDirectionalLight(const DirectionalLightPtr& light) {
directional_lights_.push_back(light);
return true;
}
bool Scene::AddPointLight(const PointLightPtr& light) {
point_lights_.push_back(light);
return true;
}
bool Scene::Detach(ErrorReporter* error_reporter) {
// Skip Node's default implementation; use Resource's instead.
return Resource::Detach(error_reporter);
}
zx_koid_t Scene::view_ref_koid() const { return view_ref_koid_; }
} // namespace gfx
} // namespace scenic_impl