blob: 00f7cfb665bb009cdff78540117c233bc3601b32 [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/geometry.h"
#include <memory>
#include <ostream>
#include "impeller/core/device_buffer_descriptor.h"
#include "impeller/core/formats.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/core/vertex_buffer.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/vector.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"
#include "impeller/scene/importer/scene_flatbuffers.h"
#include "impeller/scene/shaders/skinned.vert.h"
#include "impeller/scene/shaders/unskinned.vert.h"
namespace impeller {
namespace scene {
//------------------------------------------------------------------------------
/// Geometry
///
Geometry::~Geometry() = default;
std::shared_ptr<CuboidGeometry> Geometry::MakeCuboid(Vector3 size) {
auto result = std::make_shared<CuboidGeometry>();
result->SetSize(size);
return result;
}
std::shared_ptr<Geometry> Geometry::MakeVertexBuffer(VertexBuffer vertex_buffer,
bool is_skinned) {
if (is_skinned) {
auto result = std::make_shared<SkinnedVertexBufferGeometry>();
result->SetVertexBuffer(std::move(vertex_buffer));
return result;
} else {
auto result = std::make_shared<UnskinnedVertexBufferGeometry>();
result->SetVertexBuffer(std::move(vertex_buffer));
return result;
}
}
std::shared_ptr<Geometry> Geometry::MakeFromFlatbuffer(
const fb::MeshPrimitive& mesh,
Allocator& allocator) {
IndexType index_type;
switch (mesh.indices()->type()) {
case fb::IndexType::k16Bit:
index_type = IndexType::k16bit;
break;
case fb::IndexType::k32Bit:
index_type = IndexType::k32bit;
break;
}
const uint8_t* vertices_start;
size_t vertices_bytes;
bool is_skinned;
switch (mesh.vertices_type()) {
case fb::VertexBuffer::UnskinnedVertexBuffer: {
const auto* vertices =
mesh.vertices_as_UnskinnedVertexBuffer()->vertices();
vertices_start = reinterpret_cast<const uint8_t*>(vertices->Get(0));
vertices_bytes = vertices->size() * sizeof(fb::Vertex);
is_skinned = false;
break;
}
case fb::VertexBuffer::SkinnedVertexBuffer: {
const auto* vertices = mesh.vertices_as_SkinnedVertexBuffer()->vertices();
vertices_start = reinterpret_cast<const uint8_t*>(vertices->Get(0));
vertices_bytes = vertices->size() * sizeof(fb::SkinnedVertex);
is_skinned = true;
break;
}
case fb::VertexBuffer::NONE:
VALIDATION_LOG << "Invalid vertex buffer type.";
return nullptr;
}
const uint8_t* indices_start =
reinterpret_cast<const uint8_t*>(mesh.indices()->data()->Data());
const size_t indices_bytes = mesh.indices()->data()->size();
if (vertices_bytes == 0 || indices_bytes == 0) {
return nullptr;
}
DeviceBufferDescriptor buffer_desc;
buffer_desc.size = vertices_bytes + indices_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;
auto buffer = allocator.CreateBuffer(buffer_desc);
buffer->SetLabel("Mesh vertices+indices");
if (!buffer->CopyHostBuffer(vertices_start, Range(0, vertices_bytes))) {
return nullptr;
}
if (!buffer->CopyHostBuffer(indices_start, Range(0, indices_bytes),
vertices_bytes)) {
return nullptr;
}
VertexBuffer vertex_buffer = {
.vertex_buffer = {.buffer = buffer, .range = Range(0, vertices_bytes)},
.index_buffer = {.buffer = buffer,
.range = Range(vertices_bytes, indices_bytes)},
.vertex_count = mesh.indices()->count(),
.index_type = index_type,
};
return MakeVertexBuffer(std::move(vertex_buffer), is_skinned);
}
void Geometry::SetJointsTexture(const std::shared_ptr<Texture>& texture) {}
//------------------------------------------------------------------------------
/// CuboidGeometry
///
CuboidGeometry::CuboidGeometry() = default;
CuboidGeometry::~CuboidGeometry() = default;
void CuboidGeometry::SetSize(Vector3 size) {
size_ = size;
}
// |Geometry|
GeometryType CuboidGeometry::GetGeometryType() const {
return GeometryType::kUnskinned;
}
// |Geometry|
VertexBuffer CuboidGeometry::GetVertexBuffer(Allocator& allocator) const {
VertexBufferBuilder<UnskinnedVertexShader::PerVertexData, uint16_t> builder;
// Layout: position, normal, tangent, uv
builder.AddVertices({
// Front.
{Vector3(0, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 0),
Color::White()},
{Vector3(1, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 0),
Color::White()},
{Vector3(1, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 1),
Color::White()},
{Vector3(1, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 1),
Color::White()},
{Vector3(0, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 1),
Color::White()},
{Vector3(0, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 0),
Color::White()},
});
return builder.CreateVertexBuffer(allocator);
}
// |Geometry|
void CuboidGeometry::BindToCommand(const SceneContext& scene_context,
HostBuffer& buffer,
const Matrix& transform,
RenderPass& pass) const {
pass.SetVertexBuffer(
GetVertexBuffer(*scene_context.GetContext()->GetResourceAllocator()));
UnskinnedVertexShader::FrameInfo info;
info.mvp = transform;
UnskinnedVertexShader::BindFrameInfo(pass, buffer.EmplaceUniform(info));
}
//------------------------------------------------------------------------------
/// UnskinnedVertexBufferGeometry
///
UnskinnedVertexBufferGeometry::UnskinnedVertexBufferGeometry() = default;
UnskinnedVertexBufferGeometry::~UnskinnedVertexBufferGeometry() = default;
void UnskinnedVertexBufferGeometry::SetVertexBuffer(
VertexBuffer vertex_buffer) {
vertex_buffer_ = std::move(vertex_buffer);
}
// |Geometry|
GeometryType UnskinnedVertexBufferGeometry::GetGeometryType() const {
return GeometryType::kUnskinned;
}
// |Geometry|
VertexBuffer UnskinnedVertexBufferGeometry::GetVertexBuffer(
Allocator& allocator) const {
return vertex_buffer_;
}
// |Geometry|
void UnskinnedVertexBufferGeometry::BindToCommand(
const SceneContext& scene_context,
HostBuffer& buffer,
const Matrix& transform,
RenderPass& pass) const {
pass.SetVertexBuffer(
GetVertexBuffer(*scene_context.GetContext()->GetResourceAllocator()));
UnskinnedVertexShader::FrameInfo info;
info.mvp = transform;
UnskinnedVertexShader::BindFrameInfo(pass, buffer.EmplaceUniform(info));
}
//------------------------------------------------------------------------------
/// SkinnedVertexBufferGeometry
///
SkinnedVertexBufferGeometry::SkinnedVertexBufferGeometry() = default;
SkinnedVertexBufferGeometry::~SkinnedVertexBufferGeometry() = default;
void SkinnedVertexBufferGeometry::SetVertexBuffer(VertexBuffer vertex_buffer) {
vertex_buffer_ = std::move(vertex_buffer);
}
// |Geometry|
GeometryType SkinnedVertexBufferGeometry::GetGeometryType() const {
return GeometryType::kSkinned;
}
// |Geometry|
VertexBuffer SkinnedVertexBufferGeometry::GetVertexBuffer(
Allocator& allocator) const {
return vertex_buffer_;
}
// |Geometry|
void SkinnedVertexBufferGeometry::BindToCommand(
const SceneContext& scene_context,
HostBuffer& buffer,
const Matrix& transform,
RenderPass& pass) const {
pass.SetVertexBuffer(
GetVertexBuffer(*scene_context.GetContext()->GetResourceAllocator()));
SamplerDescriptor sampler_desc;
sampler_desc.min_filter = MinMagFilter::kNearest;
sampler_desc.mag_filter = MinMagFilter::kNearest;
sampler_desc.mip_filter = MipFilter::kNearest;
sampler_desc.width_address_mode = SamplerAddressMode::kRepeat;
sampler_desc.label = "NN Repeat";
SkinnedVertexShader::BindJointsTexture(
pass,
joints_texture_ ? joints_texture_ : scene_context.GetPlaceholderTexture(),
scene_context.GetContext()->GetSamplerLibrary()->GetSampler(
sampler_desc));
SkinnedVertexShader::FrameInfo info;
info.mvp = transform;
info.enable_skinning = joints_texture_ ? 1 : 0;
info.joint_texture_size =
joints_texture_ ? joints_texture_->GetSize().width : 1;
SkinnedVertexShader::BindFrameInfo(pass, buffer.EmplaceUniform(info));
}
// |Geometry|
void SkinnedVertexBufferGeometry::SetJointsTexture(
const std::shared_ptr<Texture>& texture) {
joints_texture_ = texture;
}
} // namespace scene
} // namespace impeller