| // 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 |