blob: c2d1521419741bb7a22c1982af7108e7c73f2879 [file]
// Copyright 2013 The Flutter 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 "impeller/scene/node.h"
#include <memory>
#include "impeller/base/validation.h"
#include "impeller/geometry/matrix.h"
#include "impeller/scene/importer/scene_flatbuffers.h"
#include "impeller/scene/mesh.h"
#include "impeller/scene/node.h"
#include "impeller/scene/scene_encoder.h"
namespace impeller {
namespace scene {
std::shared_ptr<Node> Node::MakeFromFlatbuffer(fml::Mapping& mapping,
Allocator& allocator) {
flatbuffers::Verifier verifier(mapping.GetMapping(), mapping.GetSize());
if (!fb::VerifySceneBuffer(verifier)) {
VALIDATION_LOG << "Failed to unpack scene: Scene flatbuffer is invalid.";
return nullptr;
}
return Node::MakeFromFlatbuffer(*fb::GetScene(mapping.GetMapping()),
allocator);
}
std::shared_ptr<Node> Node::MakeFromFlatbuffer(const fb::Scene& scene,
Allocator& allocator) {
auto result = std::make_shared<Node>();
if (!scene.nodes() || !scene.children()) {
return result; // The scene is empty.
}
// Initialize nodes for unpacking the entire scene.
std::vector<std::shared_ptr<Node>> scene_nodes;
scene_nodes.reserve(scene.nodes()->size());
for (size_t node_i = 0; node_i < scene.nodes()->size(); node_i++) {
scene_nodes.push_back(std::make_shared<Node>());
}
// Connect children to the root node.
for (int child : *scene.children()) {
if (child < 0 || static_cast<size_t>(child) >= scene_nodes.size()) {
VALIDATION_LOG << "Scene child index out of range.";
continue;
}
result->AddChild(scene_nodes[child]);
}
// TODO(bdero): Unpack animations.
// Unpack each node.
for (size_t node_i = 0; node_i < scene.nodes()->size(); node_i++) {
scene_nodes[node_i]->UnpackFromFlatbuffer(*scene.nodes()->Get(node_i),
scene_nodes, allocator);
}
return result;
}
void Node::UnpackFromFlatbuffer(
const fb::Node& source_node,
const std::vector<std::shared_ptr<Node>>& scene_nodes,
Allocator& allocator) {
if (source_node.mesh_primitives()) {
Mesh mesh;
for (const auto* primitives : *source_node.mesh_primitives()) {
auto geometry = Geometry::MakeFromFlatbuffer(*primitives, allocator);
mesh.AddPrimitive({geometry, Material::MakeUnlit()});
}
SetMesh(std::move(mesh));
}
if (!source_node.children()) {
return;
}
// Wire up graph connections.
for (int child : *source_node.children()) {
if (child < 0 || static_cast<size_t>(child) >= scene_nodes.size()) {
VALIDATION_LOG << "Node child index out of range.";
continue;
}
AddChild(scene_nodes[child]);
}
}
Node::Node() = default;
Node::~Node() = default;
Mesh::Mesh(Mesh&& mesh) = default;
Mesh& Mesh::operator=(Mesh&& mesh) = default;
Node::Node(Node&& node) = default;
Node& Node::operator=(Node&& node) = default;
void Node::SetLocalTransform(Matrix transform) {
local_transform_ = transform;
}
Matrix Node::GetLocalTransform() const {
return local_transform_;
}
void Node::SetGlobalTransform(Matrix transform) {
Matrix inverse_global_transform =
parent_ ? parent_->GetGlobalTransform().Invert() : Matrix();
local_transform_ = inverse_global_transform * transform;
}
Matrix Node::GetGlobalTransform() const {
if (parent_) {
return parent_->GetGlobalTransform() * local_transform_;
}
return local_transform_;
}
bool Node::AddChild(std::shared_ptr<Node> node) {
// This ensures that cycles are impossible.
if (node->parent_ != nullptr) {
VALIDATION_LOG
<< "Cannot add a node as a child which already has a parent.";
return false;
}
node->parent_ = this;
children_.push_back(std::move(node));
return true;
}
std::vector<std::shared_ptr<Node>>& Node::GetChildren() {
return children_;
}
void Node::SetMesh(Mesh mesh) {
mesh_ = std::move(mesh);
}
Mesh& Node::GetMesh() {
return mesh_;
}
bool Node::Render(SceneEncoder& encoder, const Matrix& parent_transform) const {
Matrix transform = parent_transform * local_transform_;
mesh_.Render(encoder, transform);
for (auto& child : children_) {
if (!child->Render(encoder, transform)) {
return false;
}
}
return true;
}
} // namespace scene
} // namespace impeller