blob: 589bd0abf6714b5d85ff52f2f9d4673ae4e5b0fa [file] [log] [blame]
// 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 <cstdint>
#include <cstring>
#include <limits>
#include <memory>
#include <type_traits>
#include "flutter/fml/logging.h"
#include "impeller/scene/importer/conversions.h"
#include "impeller/scene/importer/scene_flatbuffers.h"
namespace impeller {
namespace scene {
namespace importer {
//------------------------------------------------------------------------------
/// VerticesBuilder
///
std::unique_ptr<VerticesBuilder> VerticesBuilder::MakeUnskinned() {
return std::make_unique<UnskinnedVerticesBuilder>();
}
std::unique_ptr<VerticesBuilder> VerticesBuilder::MakeSkinned() {
return std::make_unique<SkinnedVerticesBuilder>();
}
VerticesBuilder::VerticesBuilder() = default;
VerticesBuilder::~VerticesBuilder() = default;
/// @brief Reads a numeric component from `source` and returns a 32bit float.
/// If `normalized` is `true`, signed SourceTypes convert to a range of
/// -1 to 1, and unsigned SourceTypes convert to a range of 0 to 1.
template <typename SourceType>
static Scalar ToScalar(const void* source, size_t index, bool normalized) {
const SourceType* s = reinterpret_cast<const SourceType*>(source) + index;
Scalar result = static_cast<Scalar>(*s);
if (normalized) {
constexpr SourceType divisor = std::is_integral_v<SourceType>
? std::numeric_limits<SourceType>::max()
: 1;
result = static_cast<Scalar>(*s) / static_cast<Scalar>(divisor);
}
return result;
}
/// @brief A ComponentWriter which simply converts all of an attribute's
/// components to normalized scalar form.
static void PassthroughAttributeWriter(
Scalar* destination,
const void* source,
const VerticesBuilder::ComponentProperties& component,
const VerticesBuilder::AttributeProperties& attribute) {
FML_DCHECK(attribute.size_bytes ==
attribute.component_count * sizeof(Scalar));
for (size_t component_i = 0; component_i < attribute.component_count;
component_i++) {
*(destination + component_i) =
component.convert_proc(source, component_i, true);
}
}
/// @brief A ComponentWriter which converts four vertex indices to scalars.
static void JointsAttributeWriter(
Scalar* destination,
const void* source,
const VerticesBuilder::ComponentProperties& component,
const VerticesBuilder::AttributeProperties& attribute) {
FML_DCHECK(attribute.component_count == 4);
for (int i = 0; i < 4; i++) {
*(destination + i) = component.convert_proc(source, i, false);
}
}
std::map<VerticesBuilder::AttributeType, VerticesBuilder::AttributeProperties>
VerticesBuilder::kAttributeTypes = {
{VerticesBuilder::AttributeType::kPosition,
{.offset_bytes = offsetof(UnskinnedVerticesBuilder::Vertex, position),
.size_bytes = sizeof(UnskinnedVerticesBuilder::Vertex::position),
.component_count = 3,
.write_proc = PassthroughAttributeWriter}},
{VerticesBuilder::AttributeType::kNormal,
{.offset_bytes = offsetof(UnskinnedVerticesBuilder::Vertex, normal),
.size_bytes = sizeof(UnskinnedVerticesBuilder::Vertex::normal),
.component_count = 3,
.write_proc = PassthroughAttributeWriter}},
{VerticesBuilder::AttributeType::kTangent,
{.offset_bytes = offsetof(UnskinnedVerticesBuilder::Vertex, tangent),
.size_bytes = sizeof(UnskinnedVerticesBuilder::Vertex::tangent),
.component_count = 4,
.write_proc = PassthroughAttributeWriter}},
{VerticesBuilder::AttributeType::kTextureCoords,
{.offset_bytes =
offsetof(UnskinnedVerticesBuilder::Vertex, texture_coords),
.size_bytes =
sizeof(UnskinnedVerticesBuilder::Vertex::texture_coords),
.component_count = 2,
.write_proc = PassthroughAttributeWriter}},
{VerticesBuilder::AttributeType::kColor,
{.offset_bytes = offsetof(UnskinnedVerticesBuilder::Vertex, color),
.size_bytes = sizeof(UnskinnedVerticesBuilder::Vertex::color),
.component_count = 4,
.write_proc = PassthroughAttributeWriter}},
{VerticesBuilder::AttributeType::kJoints,
{.offset_bytes = offsetof(SkinnedVerticesBuilder::Vertex, joints),
.size_bytes = sizeof(SkinnedVerticesBuilder::Vertex::joints),
.component_count = 4,
.write_proc = JointsAttributeWriter}},
{VerticesBuilder::AttributeType::kWeights,
{.offset_bytes = offsetof(SkinnedVerticesBuilder::Vertex, weights),
.size_bytes = sizeof(SkinnedVerticesBuilder::Vertex::weights),
.component_count = 4,
.write_proc = JointsAttributeWriter}}};
static std::map<VerticesBuilder::ComponentType,
VerticesBuilder::ComponentProperties>
kComponentTypes = {
{VerticesBuilder::ComponentType::kSignedByte,
{.size_bytes = sizeof(int8_t), .convert_proc = ToScalar<int8_t>}},
{VerticesBuilder::ComponentType::kUnsignedByte,
{.size_bytes = sizeof(int8_t), .convert_proc = ToScalar<uint8_t>}},
{VerticesBuilder::ComponentType::kSignedShort,
{.size_bytes = sizeof(int16_t), .convert_proc = ToScalar<int16_t>}},
{VerticesBuilder::ComponentType::kUnsignedShort,
{.size_bytes = sizeof(int16_t), .convert_proc = ToScalar<uint16_t>}},
{VerticesBuilder::ComponentType::kSignedInt,
{.size_bytes = sizeof(int32_t), .convert_proc = ToScalar<int32_t>}},
{VerticesBuilder::ComponentType::kUnsignedInt,
{.size_bytes = sizeof(int32_t), .convert_proc = ToScalar<uint32_t>}},
{VerticesBuilder::ComponentType::kFloat,
{.size_bytes = sizeof(float), .convert_proc = ToScalar<float>}},
};
void VerticesBuilder::WriteAttribute(void* destination,
size_t destination_stride_bytes,
AttributeType attribute,
ComponentType component_type,
const void* source,
size_t attribute_stride_bytes,
size_t attribute_count) {
const ComponentProperties& component_props = kComponentTypes[component_type];
const AttributeProperties& attribute_props = kAttributeTypes[attribute];
for (size_t i = 0; i < attribute_count; i++) {
const uint8_t* src =
reinterpret_cast<const uint8_t*>(source) + attribute_stride_bytes * i;
uint8_t* dst = reinterpret_cast<uint8_t*>(destination) +
i * destination_stride_bytes + attribute_props.offset_bytes;
attribute_props.write_proc(reinterpret_cast<Scalar*>(dst), src,
component_props, attribute_props);
}
}
//------------------------------------------------------------------------------
/// UnskinnedVerticesBuilder
///
UnskinnedVerticesBuilder::UnskinnedVerticesBuilder() = default;
UnskinnedVerticesBuilder::~UnskinnedVerticesBuilder() = default;
void UnskinnedVerticesBuilder::WriteFBVertices(
fb::MeshPrimitiveT& primitive) const {
auto vertex_buffer = fb::UnskinnedVertexBufferT();
vertex_buffer.vertices.resize(0);
for (auto& v : vertices_) {
vertex_buffer.vertices.push_back(fb::Vertex(
ToFBVec3(v.position), ToFBVec3(v.normal), ToFBVec4(v.tangent),
ToFBVec2(v.texture_coords), ToFBColor(v.color)));
}
primitive.vertices.Set(std::move(vertex_buffer));
}
void UnskinnedVerticesBuilder::SetAttributeFromBuffer(
AttributeType attribute,
ComponentType component_type,
const void* buffer_start,
size_t attribute_stride_bytes,
size_t attribute_count) {
if (attribute_count > vertices_.size()) {
vertices_.resize(attribute_count, Vertex());
}
WriteAttribute(vertices_.data(), // destination
sizeof(Vertex), // destination_stride_bytes
attribute, // attribute
component_type, // component_type
buffer_start, // source
attribute_stride_bytes, // attribute_stride_bytes
attribute_count); // attribute_count
}
//------------------------------------------------------------------------------
/// SkinnedVerticesBuilder
///
SkinnedVerticesBuilder::SkinnedVerticesBuilder() = default;
SkinnedVerticesBuilder::~SkinnedVerticesBuilder() = default;
void SkinnedVerticesBuilder::WriteFBVertices(
fb::MeshPrimitiveT& primitive) const {
auto vertex_buffer = fb::SkinnedVertexBufferT();
vertex_buffer.vertices.resize(0);
for (auto& v : vertices_) {
auto unskinned_attributes = fb::Vertex(
ToFBVec3(v.vertex.position), ToFBVec3(v.vertex.normal),
ToFBVec4(v.vertex.tangent), ToFBVec2(v.vertex.texture_coords),
ToFBColor(v.vertex.color));
vertex_buffer.vertices.push_back(fb::SkinnedVertex(
unskinned_attributes, ToFBVec4(v.joints), ToFBVec4(v.weights)));
}
primitive.vertices.Set(std::move(vertex_buffer));
}
void SkinnedVerticesBuilder::SetAttributeFromBuffer(
AttributeType attribute,
ComponentType component_type,
const void* buffer_start,
size_t attribute_stride_bytes,
size_t attribute_count) {
if (attribute_count > vertices_.size()) {
vertices_.resize(attribute_count, Vertex());
}
WriteAttribute(vertices_.data(), // destination
sizeof(Vertex), // destination_stride_bytes
attribute, // attribute
component_type, // component_type
buffer_start, // source
attribute_stride_bytes, // attribute_stride_bytes
attribute_count); // attribute_count
}
} // namespace importer
} // namespace scene
} // namespace impeller