diff --git a/DEPS b/DEPS index b0cf330bfedf6..86c410bf6003a 100644 --- a/DEPS +++ b/DEPS @@ -236,7 +236,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8747bce41d0dc6d9dc45c4d1b46d2100bb9ee688', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '908edab91bffdea18876868b20bef94f44746d21', # Fuchsia compatibility # diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 951638d5c9eda..ea0738c72c1b3 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1648,13 +1648,18 @@ FILE: ../../../flutter/impeller/scene/camera.cc FILE: ../../../flutter/impeller/scene/camera.h FILE: ../../../flutter/impeller/scene/geometry.cc FILE: ../../../flutter/impeller/scene/geometry.h +FILE: ../../../flutter/impeller/scene/importer/conversions.cc +FILE: ../../../flutter/impeller/scene/importer/conversions.h FILE: ../../../flutter/impeller/scene/importer/importer.h FILE: ../../../flutter/impeller/scene/importer/importer_gltf.cc -FILE: ../../../flutter/impeller/scene/importer/mesh.fbs +FILE: ../../../flutter/impeller/scene/importer/importer_unittests.cc +FILE: ../../../flutter/impeller/scene/importer/scene.fbs FILE: ../../../flutter/impeller/scene/importer/scenec_main.cc FILE: ../../../flutter/impeller/scene/importer/switches.cc FILE: ../../../flutter/impeller/scene/importer/switches.h FILE: ../../../flutter/impeller/scene/importer/types.h +FILE: ../../../flutter/impeller/scene/importer/vertices_builder.cc +FILE: ../../../flutter/impeller/scene/importer/vertices_builder.h FILE: ../../../flutter/impeller/scene/material.cc FILE: ../../../flutter/impeller/scene/material.h FILE: ../../../flutter/impeller/scene/scene.cc diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 2920b94f91949..496ec8c9c498b 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -74,6 +74,7 @@ impeller_component("impeller_unittests") { "compiler:compiler_unittests", "geometry:geometry_unittests", "runtime_stage:runtime_stage_unittests", + "scene/importer:importer_unittests", "tessellator:tessellator_unittests", ] diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 055110133720d..d0a17e970781d 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -58,6 +58,7 @@ test_fixtures("file_fixtures") { "blue_noise.png", "boston.jpg", "embarcadero.jpg", + "flutter_logo.glb", "kalimba.jpg", "multiple_stages.hlsl", "resources_limit.vert", diff --git a/impeller/scene/importer/BUILD.gn b/impeller/scene/importer/BUILD.gn index f7ec98c0f5f38..87b9946cb636e 100644 --- a/impeller/scene/importer/BUILD.gn +++ b/impeller/scene/importer/BUILD.gn @@ -12,22 +12,26 @@ config("runtime_stage_config") { } flatbuffers("importer_flatbuffers") { - flatbuffers = [ "mesh.fbs" ] + flatbuffers = [ "scene.fbs" ] public_configs = [ ":runtime_stage_config" ] public_deps = [ "//third_party/flatbuffers" ] } -impeller_component("scenec_lib") { +impeller_component("importer_lib") { # Current versions of libcxx have deprecated some of the UTF-16 string # conversion APIs. defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ] sources = [ + "conversions.cc", + "conversions.h", "importer.h", "importer_gltf.cc", "switches.cc", "switches.h", "types.h", + "vertices_builder.cc", + "vertices_builder.h", ] public_deps = [ @@ -39,8 +43,7 @@ impeller_component("scenec_lib") { # All third_party deps must be reflected below in the scenec_license # target. - # TODO(bdero): Fix tinygltf compilation warnings. - #"//third_party/tinygltf", + "//third_party/tinygltf", ] } @@ -85,9 +88,24 @@ impeller_component("scenec") { sources = [ "scenec_main.cc" ] - deps = [ ":scenec_lib" ] + deps = [ ":importer_lib" ] metadata = { entitlement_file_path = [ "scenec" ] } } + +impeller_component("importer_unittests") { + testonly = true + + output_name = "scenec_unittests" + + sources = [ "importer_unittests.cc" ] + + deps = [ + ":importer_lib", + "../../fixtures", + "../../geometry:geometry_unittests", + "//flutter/testing:testing_lib", + ] +} diff --git a/impeller/scene/importer/conversions.cc b/impeller/scene/importer/conversions.cc new file mode 100644 index 0000000000000..7031ed3ba7ccd --- /dev/null +++ b/impeller/scene/importer/conversions.cc @@ -0,0 +1,80 @@ +// 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/importer/conversions.h" + +#include + +#include "impeller/scene/importer/scene_flatbuffers.h" + +namespace impeller { +namespace scene { +namespace importer { + +Matrix ToMatrix(const std::vector& m) { + return Matrix(m[0], m[1], m[2], m[3], // + m[4], m[5], m[6], m[7], // + m[8], m[9], m[10], m[11], // + m[12], m[13], m[14], m[15]); +} + +//----------------------------------------------------------------------------- +/// Flatbuffers -> Impeller +/// + +Matrix ToMatrix(const fb::Matrix& m) { + auto& a = *m.m(); + return Matrix(a[0], a[1], a[2], a[3], // + a[4], a[5], a[6], a[7], // + a[8], a[9], a[10], a[11], // + a[12], a[13], a[14], a[15]); +} + +Vector2 ToVector2(const fb::Vec2& v) { + return Vector2(v.x(), v.y()); +} + +Vector3 ToVector3(const fb::Vec3& v) { + return Vector3(v.x(), v.y(), v.z()); +} + +Vector4 ToVector4(const fb::Vec4& v) { + return Vector4(v.x(), v.y(), v.z(), v.w()); +} + +Color ToColor(const fb::Color& c) { + return Color(c.r(), c.g(), c.b(), c.a()); +} + +//----------------------------------------------------------------------------- +/// Impeller -> Flatbuffers +/// + +std::unique_ptr ToFBMatrix(const Matrix& m) { + auto array = std::array{m.m[0], m.m[1], m.m[2], m.m[3], // + m.m[4], m.m[5], m.m[6], m.m[7], // + m.m[8], m.m[9], m.m[10], m.m[11], // + m.m[12], m.m[13], m.m[14], m.m[15]}; + return std::make_unique(array); +} + +fb::Vec2 ToFBVec2(const Vector2 v) { + return fb::Vec2(v.x, v.y); +} + +fb::Vec3 ToFBVec3(const Vector3 v) { + return fb::Vec3(v.x, v.y, v.z); +} + +fb::Vec4 ToFBVec4(const Vector4 v) { + return fb::Vec4(v.x, v.y, v.z, v.w); +} + +fb::Color ToFBColor(const Color c) { + return fb::Color(c.red, c.green, c.blue, c.alpha); +} + +} // namespace importer +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/importer/conversions.h b/impeller/scene/importer/conversions.h new file mode 100644 index 0000000000000..9388e7ed4b79d --- /dev/null +++ b/impeller/scene/importer/conversions.h @@ -0,0 +1,49 @@ +// 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. + +#pragma once + +#include +#include + +#include "impeller/geometry/matrix.h" +#include "impeller/scene/importer/scene_flatbuffers.h" + +namespace impeller { +namespace scene { +namespace importer { + +Matrix ToMatrix(const std::vector& m); + +//----------------------------------------------------------------------------- +/// Flatbuffers -> Impeller +/// + +Matrix ToMatrix(const fb::Matrix& m); + +Vector2 ToVector2(const fb::Vec2& c); + +Vector3 ToVector3(const fb::Vec3& c); + +Vector4 ToVector4(const fb::Vec4& c); + +Color ToColor(const fb::Color& c); + +//----------------------------------------------------------------------------- +/// Impeller -> Flatbuffers +/// + +std::unique_ptr ToFBMatrix(const Matrix& m); + +fb::Vec2 ToFBVec2(const Vector2 v); + +fb::Vec3 ToFBVec3(const Vector3 v); + +fb::Vec4 ToFBVec4(const Vector4 v); + +fb::Color ToFBColor(const Color c); + +} // namespace importer +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/importer/importer.h b/impeller/scene/importer/importer.h index 69abcf90d510f..6766adbce19da 100644 --- a/impeller/scene/importer/importer.h +++ b/impeller/scene/importer/importer.h @@ -2,17 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#pragma once + #include #include #include "flutter/fml/mapping.h" -#include "impeller/scene/importer/mesh_flatbuffers.h" +#include "impeller/scene/importer/scene_flatbuffers.h" namespace impeller { namespace scene { namespace importer { -bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh); +bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene); } } // namespace scene diff --git a/impeller/scene/importer/importer_gltf.cc b/impeller/scene/importer/importer_gltf.cc index b39831a6eba32..0edbe7ea3402b 100644 --- a/impeller/scene/importer/importer_gltf.cc +++ b/impeller/scene/importer/importer_gltf.cc @@ -2,20 +2,211 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "impeller/scene/importer/importer.h" + #include +#include +#include +#include #include - -#include "impeller/scene/importer/importer.h" +#include #include "flutter/fml/mapping.h" +#include "impeller/geometry/matrix.h" +#include "impeller/scene/importer/conversions.h" +#include "impeller/scene/importer/scene_flatbuffers.h" +#include "impeller/scene/importer/vertices_builder.h" +#include "third_party/tinygltf/tiny_gltf.h" namespace impeller { namespace scene { namespace importer { -bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh) { - // TODO(bdero): Parse source_mapping and populare out_mesh with just the first - // mesh in the GLTF. +static const std::map kAttributes = { + {"POSITION", VerticesBuilder::Attribute::kPosition}, + {"NORMAL", VerticesBuilder::Attribute::kNormal}, + {"TANGENT", VerticesBuilder::Attribute::kTangent}, + {"TEXCOORD_0", VerticesBuilder::Attribute::kTextureCoords}, + {"COLOR_0", VerticesBuilder::Attribute::kColor}, +}; + +static bool WithinRange(int index, size_t size) { + return index >= 0 && static_cast(index) < size; +} + +static bool ProcessStaticMesh(const tinygltf::Model& gltf, + const tinygltf::Primitive& primitive, + fb::StaticMeshT& static_mesh) { + //--------------------------------------------------------------------------- + /// Vertices. + /// + + { + VerticesBuilder builder; + + for (const auto& attribute : primitive.attributes) { + auto attribute_type = kAttributes.find(attribute.first); + if (attribute_type == kAttributes.end()) { + std::cerr << "Vertex attribute \"" << attribute.first + << "\" not supported." << std::endl; + continue; + } + + const auto accessor = gltf.accessors[attribute.second]; + const auto view = gltf.bufferViews[accessor.bufferView]; + + const auto buffer = gltf.buffers[view.buffer]; + const unsigned char* source_start = &buffer.data[view.byteOffset]; + + VerticesBuilder::ComponentType type; + switch (accessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_BYTE: + type = VerticesBuilder::ComponentType::kSignedByte; + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + type = VerticesBuilder::ComponentType::kUnsignedByte; + break; + case TINYGLTF_COMPONENT_TYPE_SHORT: + type = VerticesBuilder::ComponentType::kSignedShort; + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + type = VerticesBuilder::ComponentType::kUnsignedShort; + break; + case TINYGLTF_COMPONENT_TYPE_INT: + type = VerticesBuilder::ComponentType::kSignedInt; + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + type = VerticesBuilder::ComponentType::kUnsignedInt; + break; + case TINYGLTF_COMPONENT_TYPE_FLOAT: + type = VerticesBuilder::ComponentType::kFloat; + break; + default: + std::cerr << "Skipping attribute \"" << attribute.first + << "\" due to invalid component type." << std::endl; + continue; + } + + builder.SetAttributeFromBuffer(attribute_type->second, // attribute + type, // component_type + source_start, // buffer_start + accessor.ByteStride(view), // stride_bytes + accessor.count); // count + } + + builder.WriteFBVertices(static_mesh.vertices); + } + + //--------------------------------------------------------------------------- + /// Indices. + /// + + if (!WithinRange(primitive.indices, gltf.accessors.size())) { + std::cerr << "Mesh primitive has no index buffer. Skipping." << std::endl; + return false; + } + + auto index_accessor = gltf.accessors[primitive.indices]; + auto index_view = gltf.bufferViews[index_accessor.bufferView]; + static_mesh.indices.resize(index_accessor.count); + const auto* index_buffer = + &gltf.buffers[index_view.buffer].data[index_view.byteOffset]; + std::memcpy(static_mesh.indices.data(), index_buffer, index_view.byteLength); + + return true; +} + +static void ProcessNode(const tinygltf::Model& gltf, + const tinygltf::Node& in_node, + fb::NodeT& out_node) { + //--------------------------------------------------------------------------- + /// Transform. + /// + + Matrix transform; + if (in_node.translation.size() == 3) { + transform = transform * Matrix::MakeTranslation( + {static_cast(in_node.translation[0]), + static_cast(in_node.translation[0]), + static_cast(in_node.translation[0])}); + } + if (in_node.rotation.size() == 4) { + transform = transform * Matrix::MakeRotation(Quaternion( + in_node.rotation[0], in_node.rotation[1], + in_node.rotation[2], in_node.rotation[3])); + } + if (in_node.scale.size() == 3) { + transform = + transform * Matrix::MakeScale({static_cast(in_node.scale[0]), + static_cast(in_node.scale[1]), + static_cast(in_node.scale[2])}); + } + if (in_node.matrix.size() == 16) { + if (!transform.IsIdentity()) { + std::cerr << "The `matrix` attribute of node (name: " << in_node.name + << ") is set in addition to one or more of the " + "`translation/rotation/scale` attributes. Using only the " + "`matrix` " + "attribute."; + } + transform = ToMatrix(in_node.matrix); + } + out_node.transform = ToFBMatrix(transform); + + //--------------------------------------------------------------------------- + /// Static meshes. + /// + + if (WithinRange(in_node.mesh, gltf.meshes.size())) { + auto& mesh = gltf.meshes[in_node.mesh]; + for (const auto& primitive : mesh.primitives) { + auto static_mesh = std::make_unique(); + if (!ProcessStaticMesh(gltf, primitive, *static_mesh)) { + continue; + } + out_node.meshes.push_back(std::move(static_mesh)); + } + } + + //--------------------------------------------------------------------------- + /// Children. + /// + + for (size_t node_i = 0; node_i < out_node.children.size(); node_i++) { + auto child = std::make_unique(); + ProcessNode(gltf, gltf.nodes[in_node.children[node_i]], *child); + out_node.children.push_back(std::move(child)); + } +} + +bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene) { + tinygltf::Model gltf; + + { + tinygltf::TinyGLTF loader; + std::string error; + std::string warning; + bool success = loader.LoadBinaryFromMemory(&gltf, &error, &warning, + source_mapping.GetMapping(), + source_mapping.GetSize()); + if (!warning.empty()) { + std::cerr << "Warning while loading GLTF: " << warning << std::endl; + } + if (!error.empty()) { + std::cerr << "Error while loading GLTF: " << error << std::endl; + } + if (!success) { + return false; + } + } + + const tinygltf::Scene& scene = gltf.scenes[gltf.defaultScene]; + for (size_t node_i = 0; node_i < scene.nodes.size(); node_i++) { + auto node = std::make_unique(); + ProcessNode(gltf, gltf.nodes[scene.nodes[node_i]], *node); + out_scene.children.push_back(std::move(node)); + } + return true; } diff --git a/impeller/scene/importer/importer_unittests.cc b/impeller/scene/importer/importer_unittests.cc new file mode 100644 index 0000000000000..5a8accc0dfb39 --- /dev/null +++ b/impeller/scene/importer/importer_unittests.cc @@ -0,0 +1,55 @@ +// 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 "flutter/testing/testing.h" +#include "impeller/geometry/geometry_unittests.h" +#include "impeller/geometry/matrix.h" +#include "impeller/scene/importer/conversions.h" +#include "impeller/scene/importer/importer.h" +#include "impeller/scene/importer/scene_flatbuffers.h" + +namespace impeller { +namespace scene { +namespace importer { +namespace testing { + +TEST(ImporterTest, CanParseGLTF) { + auto mapping = flutter::testing::OpenFixtureAsMapping("flutter_logo.glb"); + + fb::SceneT scene; + ASSERT_TRUE(ParseGLTF(*mapping, scene)); + + ASSERT_EQ(scene.children.size(), 1u); + auto& node = *scene.children[0]; + + Matrix node_transform = ToMatrix(*node.transform); + ASSERT_MATRIX_NEAR(node_transform, Matrix()); + + ASSERT_EQ(node.meshes.size(), 1u); + auto& mesh = *node.meshes[0]; + ASSERT_EQ(mesh.indices.size(), 918u); + + ASSERT_EQ(mesh.vertices.size(), 260u); + auto& vertex = mesh.vertices[0]; + + Vector3 position = ToVector3(vertex.position()); + ASSERT_VECTOR3_NEAR(position, Vector3(-0.0100185, -0.522907, 0.133178)); + + Vector3 normal = ToVector3(vertex.normal()); + ASSERT_VECTOR3_NEAR(normal, Vector3(0.556997, -0.810833, 0.179733)); + + Vector4 tangent = ToVector4(vertex.tangent()); + ASSERT_VECTOR4_NEAR(tangent, Vector4(0.155901, -0.110485, -0.981574, 1)); + + Vector2 texture_coords = ToVector2(vertex.texture_coords()); + ASSERT_POINT_NEAR(texture_coords, Vector2(0.727937, 0.713817)); + + Color color = ToColor(vertex.color()); + ASSERT_COLOR_NEAR(color, Color(0.0221714, 0.467781, 0.921584, 1)); +} + +} // namespace testing +} // namespace importer +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/importer/mesh.fbs b/impeller/scene/importer/mesh.fbs deleted file mode 100644 index 87044f1527a0c..0000000000000 --- a/impeller/scene/importer/mesh.fbs +++ /dev/null @@ -1,37 +0,0 @@ -// 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. - -namespace impeller.fb; - -struct Vec2 { - x: float; - y: float; -} - -struct Vec3 { - x: float; - y: float; - z: float; -} - -struct Color { - r: float; - g: float; - b: float; -} - -struct Vertex { - position: Vec3; - normal: Vec3; - tangent: Vec3; - texture_coords: Vec2; -} - -table Mesh { - vertices: [Vertex]; - indices: [uint16]; -} - -root_type Mesh; -file_identifier "IPME"; diff --git a/impeller/scene/importer/scene.fbs b/impeller/scene/importer/scene.fbs new file mode 100644 index 0000000000000..f998be4858efc --- /dev/null +++ b/impeller/scene/importer/scene.fbs @@ -0,0 +1,72 @@ +// 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. + +namespace impeller.fb; + +struct Vec2 { + x: float; + y: float; +} + +struct Vec3 { + x: float; + y: float; + z: float; +} + +struct Vec4 { + x: float; + y: float; + z: float; + w: float; +} + +struct Color { + r: float; + g: float; + b: float; + a: float; +} + +struct Matrix { + m: [float:16]; +} + +struct Vertex { + position: Vec3; + normal: Vec3; + tangent: Vec4; // The 4th component determines the handedness of the tangent. + texture_coords: Vec2; + color: Color; +} + +table Texture { + // TODO(bdero): Allow optional image data embedding. + uri: string; +} + +table Material { + base_color_factor: Color; + base_color_texture: Texture; + // TODO(bdero): PBR textures. +} + +table StaticMesh { + vertices: [Vertex]; + indices: [uint32]; + material: Material; +} + +table Node { + children: [Node]; + transform: Matrix; + meshes: [StaticMesh]; +} + +table Scene { + children: [Node]; +} + +root_type Scene; +file_identifier "IPSC"; diff --git a/impeller/scene/importer/scenec_main.cc b/impeller/scene/importer/scenec_main.cc index 52538d6c2585f..73d0982798971 100644 --- a/impeller/scene/importer/scenec_main.cc +++ b/impeller/scene/importer/scenec_main.cc @@ -58,11 +58,11 @@ bool Main(const fml::CommandLine& command_line) { return false; } - fb::MeshT mesh; + fb::SceneT scene; bool success = false; switch (switches.input_type) { case SourceType::kGLTF: - success = ParseGLTF(*source_file_mapping, mesh); + success = ParseGLTF(*source_file_mapping, scene); break; case SourceType::kUnknown: std::cerr << "Unknown input type." << std::endl; @@ -74,7 +74,7 @@ bool Main(const fml::CommandLine& command_line) { } flatbuffers::FlatBufferBuilder builder; - builder.Finish(fb::Mesh::Pack(builder, &mesh)); + builder.Finish(fb::Scene::Pack(builder, &scene)); auto output_file_name = std::filesystem::absolute( std::filesystem::current_path() / switches.output_file_name); diff --git a/impeller/scene/importer/vertices_builder.cc b/impeller/scene/importer/vertices_builder.cc new file mode 100644 index 0000000000000..d08268df4fdf9 --- /dev/null +++ b/impeller/scene/importer/vertices_builder.cc @@ -0,0 +1,115 @@ +// 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/importer/vertices_builder.h" + +#include +#include +#include + +#include "impeller/scene/importer/conversions.h" +#include "impeller/scene/importer/scene_flatbuffers.h" + +namespace impeller { +namespace scene { +namespace importer { + +VerticesBuilder::VerticesBuilder() = default; + +std::map + VerticesBuilder::kAttributes = { + {VerticesBuilder::Attribute::kPosition, + {.offset_bytes = offsetof(Vertex, position), + .size_bytes = sizeof(Vertex::position), + .component_count = 3}}, + {VerticesBuilder::Attribute::kNormal, + {.offset_bytes = offsetof(Vertex, normal), + .size_bytes = sizeof(Vertex::normal), + .component_count = 3}}, + {VerticesBuilder::Attribute::kTangent, + {.offset_bytes = offsetof(Vertex, tangent), + .size_bytes = sizeof(Vertex::tangent), + .component_count = 4}}, + {VerticesBuilder::Attribute::kTextureCoords, + {.offset_bytes = offsetof(Vertex, texture_coords), + .size_bytes = sizeof(Vertex::texture_coords), + .component_count = 2}}, + {VerticesBuilder::Attribute::kColor, + {.offset_bytes = offsetof(Vertex, color), + .size_bytes = sizeof(Vertex::color), + .component_count = 4}}}; + +void VerticesBuilder::WriteFBVertices(std::vector& vertices) const { + vertices.resize(0); + for (auto& v : vertices_) { + vertices.push_back(fb::Vertex( + ToFBVec3(v.position), ToFBVec3(v.normal), ToFBVec4(v.tangent), + ToFBVec2(v.texture_coords), ToFBColor(v.color))); + } +} + +/// @brief Reads a contiguous sequence of numeric components from `source` and +/// writes them to `destination` as 32bit floats. Signed SourceTypes +/// convert to a range of -1 to 1, and unsigned SourceTypes convert to a +/// range of 0 to 1. +template +static void WriteComponentsAsScalars(void* destination, + const void* source, + size_t component_count) { + constexpr SourceType divisor = std::is_integral_v + ? std::numeric_limits::max() + : 1; + for (size_t i = 0; i < component_count; i++) { + const SourceType* s = reinterpret_cast(source) + i; + Scalar v = static_cast(*s) / static_cast(divisor); + Scalar* dest = reinterpret_cast(destination) + i; + *dest = v; + } +} + +static std::map< + VerticesBuilder::ComponentType, + std::function< + void(void* destination, const void* source, size_t component_count)>> + kAttributeWriters = { + {VerticesBuilder::ComponentType::kSignedByte, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kUnsignedByte, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kSignedShort, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kUnsignedShort, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kSignedInt, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kUnsignedInt, + WriteComponentsAsScalars}, + {VerticesBuilder::ComponentType::kFloat, + WriteComponentsAsScalars}, +}; + +void VerticesBuilder::SetAttributeFromBuffer(Attribute attribute, + ComponentType component_type, + const void* buffer_start, + size_t stride_bytes, + size_t count) { + if (count > vertices_.size()) { + vertices_.resize(count, Vertex()); + } + + const auto& properties = kAttributes[attribute]; + const auto& writer = kAttributeWriters[component_type]; + for (size_t i = 0; i < count; i++) { + const char* source = + reinterpret_cast(buffer_start) + stride_bytes * i; + char* destination = + reinterpret_cast(&vertices_.data()[i]) + properties.offset_bytes; + + writer(destination, source, properties.component_count); + } +} + +} // namespace importer +} // namespace scene +} // namespace impeller diff --git a/impeller/scene/importer/vertices_builder.h b/impeller/scene/importer/vertices_builder.h new file mode 100644 index 0000000000000..1ff3d42894964 --- /dev/null +++ b/impeller/scene/importer/vertices_builder.h @@ -0,0 +1,74 @@ +// 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. + +#pragma once + +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/geometry/matrix.h" +#include "impeller/scene/importer/scene_flatbuffers.h" + +namespace impeller { +namespace scene { +namespace importer { + +class VerticesBuilder { + public: + enum class Attribute { + kPosition, + kNormal, + kTangent, + kTextureCoords, + kColor, + }; + + enum class ComponentType { + kSignedByte = 5120, + kUnsignedByte, + kSignedShort, + kUnsignedShort, + kSignedInt, + kUnsignedInt, + kFloat, + }; + + VerticesBuilder(); + + void WriteFBVertices(std::vector& vertices) const; + + void SetAttributeFromBuffer(Attribute attribute, + ComponentType component_type, + const void* buffer_start, + size_t stride_bytes, + size_t count); + + private: + struct AttributeProperties { + size_t offset_bytes; + size_t size_bytes; + size_t component_count; + }; + + static std::map + kAttributes; + + struct Vertex { + Vector3 position; + Vector3 normal; + Vector4 tangent; + Vector2 texture_coords; + Color color = Color::White(); + }; + + std::vector vertices_; + + FML_DISALLOW_COPY_AND_ASSIGN(VerticesBuilder); +}; + +} // namespace importer +} // namespace scene +} // namespace impeller