15 : points_(
std::move(points)), radius_(radius), round_(round) {}
24 return GetPositionBufferGPU(renderer, entity, pass);
26 auto vtx_builder = GetPositionBufferCPU(renderer, entity, pass);
27 if (!vtx_builder.has_value()) {
34 .vertex_buffer = vtx_builder->CreateVertexBuffer(host_buffer),
37 .prevent_overdraw =
false,
41 GeometryResult PointFieldGeometry::GetPositionUVBuffer(
42 Rect texture_coverage,
43 Matrix effect_transform,
44 const ContentContext& renderer,
47 if (renderer.GetDeviceCapabilities().SupportsCompute()) {
48 return GetPositionBufferGPU(renderer, entity, pass, texture_coverage,
52 auto vtx_builder = GetPositionBufferCPU(renderer, entity, pass);
53 if (!vtx_builder.has_value()) {
57 vtx_builder.value(), {0, 0}, texture_coverage.size, effect_transform);
59 auto& host_buffer = pass.GetTransientsBuffer();
62 .vertex_buffer = uv_vtx_builder.CreateVertexBuffer(host_buffer),
64 entity.GetTransformation(),
65 .prevent_overdraw =
false,
69 std::optional<VertexBufferBuilder<SolidFillVertexShader::PerVertexData>>
70 PointFieldGeometry::GetPositionBufferCPU(
const ContentContext& renderer,
77 if (determinant == 0) {
81 Scalar min_size = 1.0f / sqrt(std::abs(determinant));
82 Scalar radius = std::max(radius_, min_size);
85 entity.GetTransformation().GetMaxBasisLength() * radius, round_);
86 auto points_per_circle = 3 + (vertices_per_geom - 3) * 3;
87 auto total = points_per_circle * points_.size();
88 auto radian_start = round_ ? 0.0f : 0.785398f;
89 auto radian_step =
k2Pi / vertices_per_geom;
91 VertexBufferBuilder<SolidFillVertexShader::PerVertexData> vtx_builder;
92 vtx_builder.Reserve(total);
95 auto elapsed_angle = radian_start;
96 std::vector<Point> angle_table(vertices_per_geom);
97 for (
auto i = 0u; i < vertices_per_geom; i++) {
98 angle_table[i] =
Point(cos(elapsed_angle), sin(elapsed_angle)) * radius;
99 elapsed_angle += radian_step;
102 for (
auto i = 0u; i < points_.size(); i++) {
103 auto center = points_[i];
105 auto origin = center + angle_table[0];
106 vtx_builder.AppendVertex({origin});
108 auto pt1 = center + angle_table[1];
109 vtx_builder.AppendVertex({pt1});
111 auto pt2 = center + angle_table[2];
112 vtx_builder.AppendVertex({pt2});
114 for (
auto j = 0u; j < vertices_per_geom - 3; j++) {
115 vtx_builder.AppendVertex({origin});
116 vtx_builder.AppendVertex({pt2});
118 pt2 = center + angle_table[j + 3];
119 vtx_builder.AppendVertex({pt2});
125 GeometryResult PointFieldGeometry::GetPositionBufferGPU(
126 const ContentContext& renderer,
127 const Entity& entity,
129 std::optional<Rect> texture_coverage,
130 std::optional<Matrix> effect_transform) {
131 FML_DCHECK(renderer.GetDeviceCapabilities().SupportsCompute());
135 auto determinant = entity.GetTransformation().GetDeterminant();
136 if (determinant == 0) {
140 Scalar min_size = 1.0f / sqrt(std::abs(determinant));
141 Scalar radius = std::max(radius_, min_size);
144 entity.GetTransformation().GetMaxBasisLength() * radius, round_);
146 auto points_per_circle = 3 + (vertices_per_geom - 3) * 3;
147 auto total = points_per_circle * points_.size();
149 auto cmd_buffer = renderer.GetContext()->CreateCommandBuffer();
150 auto compute_pass = cmd_buffer->CreateComputePass();
151 auto& host_buffer = compute_pass->GetTransientsBuffer();
154 host_buffer.Emplace(points_.data(), points_.size() *
sizeof(
Point),
157 DeviceBufferDescriptor buffer_desc;
158 buffer_desc.size = total *
sizeof(
Point);
161 auto geometry_buffer = renderer.GetContext()
162 ->GetResourceAllocator()
163 ->CreateBuffer(buffer_desc)
168 using PS = PointsComputeShader;
171 cmd.pipeline = renderer.GetPointComputePipeline();
173 PS::FrameInfo frame_info;
174 frame_info.count = points_.size();
175 frame_info.radius = radius;
176 frame_info.radian_start = round_ ? 0.0f :
kPiOver4;
177 frame_info.radian_step =
k2Pi / vertices_per_geom;
178 frame_info.points_per_circle = points_per_circle;
179 frame_info.divisions_per_circle = vertices_per_geom;
181 PS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
182 PS::BindGeometryData(cmd, geometry_buffer);
183 PS::BindPointData(cmd, points_data);
185 if (!compute_pass->AddCommand(std::move(cmd))) {
188 output = geometry_buffer;
191 if (texture_coverage.has_value() && effect_transform.has_value()) {
192 DeviceBufferDescriptor buffer_desc;
193 buffer_desc.size = total *
sizeof(Vector4);
196 auto geometry_uv_buffer = renderer.GetContext()
197 ->GetResourceAllocator()
198 ->CreateBuffer(buffer_desc)
201 using UV = UvComputeShader;
205 cmd.pipeline = renderer.GetUvComputePipeline();
207 UV::FrameInfo frame_info;
208 frame_info.count = total;
209 frame_info.effect_transform = effect_transform.value();
210 frame_info.texture_origin = {0, 0};
211 frame_info.texture_size =
Vector2(texture_coverage.value().size);
213 UV::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
214 UV::BindGeometryData(cmd, geometry_buffer);
215 UV::BindGeometryUVData(cmd, geometry_uv_buffer);
217 if (!compute_pass->AddCommand(std::move(cmd))) {
220 output = geometry_uv_buffer;
223 compute_pass->SetGridSize(
ISize(total, 1));
224 compute_pass->SetThreadGroupSize(
ISize(total, 1));
226 if (!compute_pass->EncodeCommands() || !cmd_buffer->SubmitCommands()) {
232 .vertex_buffer = {.vertex_buffer = output,
233 .vertex_count = total,
236 entity.GetTransformation(),
237 .prevent_overdraw =
false,
252 if (scaled_radius < 1.0) {
255 if (scaled_radius < 2.0) {
258 if (scaled_radius < 12.0) {
261 if (scaled_radius < 22.0) {
264 return std::min(scaled_radius, 140.0f);
273 std::optional<Rect> PointFieldGeometry::GetCoverage(
274 const Matrix& transform)
const {
275 if (points_.size() > 0) {
278 auto first = points_.begin();
279 auto last = points_.end();
280 auto left = first->x;
282 auto right = first->x;
283 auto bottom = first->y;
284 for (
auto it = first + 1; it < last; ++it) {
285 left = std::min(left, it->x);
286 top = std::min(top, it->y);
287 right = std::max(right, it->x);
288 bottom = std::max(bottom, it->y);
291 right + radius_, bottom + radius_);
292 return coverage.TransformBounds(transform);