// 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 #include #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 Geometry::MakeCuboid(Vector3 size) { auto result = std::make_shared(); result->SetSize(size); return result; } std::shared_ptr Geometry::MakeVertexBuffer(VertexBuffer vertex_buffer, bool is_skinned) { if (is_skinned) { auto result = std::make_shared(); result->SetVertexBuffer(std::move(vertex_buffer)); return result; } else { auto result = std::make_shared(); result->SetVertexBuffer(std::move(vertex_buffer)); return result; } } std::shared_ptr 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(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(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(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) {} //------------------------------------------------------------------------------ /// 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 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) { joints_texture_ = texture; } } // namespace scene } // namespace impeller