Files
test/source/blender/geometry/intern/mesh_primitive_grid.cc
Hans Goudey 19001c9e6c Cleanup: Move attribute domain enum to C++ header, use enum class
Each value is now out of the global namespace, so they can be shorter
and easier to read. Most of this commit just adds the necessary casting
and namespace specification. `enum class` can be forward declared since
it has a specified size. We will make use of that in the next commit.
2023-12-20 13:25:28 -05:00

147 lines
5.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_attribute.hh"
#include "BKE_mesh.hh"
#include "GEO_mesh_primitive_grid.hh"
namespace blender::geometry {
static void calculate_uvs(Mesh *mesh,
const Span<float3> positions,
const Span<int> corner_verts,
const float size_x,
const float size_y,
const bke::AttributeIDRef &uv_map_id)
{
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
uv_map_id, bke::AttrDomain::Corner);
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
threading::parallel_for(corner_verts.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const float3 &co = positions[corner_verts[i]];
uv_attribute.span[i].x = (co.x + size_x * 0.5f) * dx;
uv_attribute.span[i].y = (co.y + size_y * 0.5f) * dy;
}
});
uv_attribute.finish();
}
Mesh *create_grid_mesh(const int verts_x,
const int verts_y,
const float size_x,
const float size_y,
const bke::AttributeIDRef &uv_map_id)
{
BLI_assert(verts_x > 0 && verts_y > 0);
const int edges_x = verts_x - 1;
const int edges_y = verts_y - 1;
Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y,
edges_x * verts_y + edges_y * verts_x,
edges_x * edges_y,
edges_x * edges_y * 4);
MutableSpan<float3> positions = mesh->vert_positions_for_write();
MutableSpan<int2> edges = mesh->edges_for_write();
MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
MutableSpan<int> corner_edges = mesh->corner_edges_for_write();
bke::mesh_smooth_set(*mesh, false);
offset_indices::fill_constant_group_size(4, 0, mesh->face_offsets_for_write());
{
const float dx = edges_x == 0 ? 0.0f : size_x / edges_x;
const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
const float x_shift = edges_x / 2.0f;
const float y_shift = edges_y / 2.0f;
threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
for (const int x : x_range) {
const int y_offset = x * verts_y;
threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
for (const int y : y_range) {
const int vert_index = y_offset + y;
positions[vert_index].x = (x - x_shift) * dx;
positions[vert_index].y = (y - y_shift) * dy;
positions[vert_index].z = 0.0f;
}
});
}
});
}
const int y_edges_start = 0;
const int x_edges_start = verts_x * edges_y;
/* Build the horizontal edges in the X direction. */
threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
for (const int x : x_range) {
const int y_vert_offset = x * verts_y;
const int y_edge_offset = y_edges_start + x * edges_y;
threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
for (const int y : y_range) {
const int vert_index = y_vert_offset + y;
edges[y_edge_offset + y] = int2(vert_index, vert_index + 1);
}
});
}
});
/* Build the vertical edges in the Y direction. */
threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
for (const int y : y_range) {
const int x_edge_offset = x_edges_start + y * edges_x;
threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
for (const int x : x_range) {
const int vert_index = x * verts_y + y;
edges[x_edge_offset + x] = int2(vert_index, vert_index + verts_y);
}
});
}
});
threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
for (const int x : x_range) {
const int y_offset = x * edges_y;
threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
for (const int y : y_range) {
const int face_index = y_offset + y;
const int loop_index = face_index * 4;
const int vert_index = x * verts_y + y;
corner_verts[loop_index] = vert_index;
corner_edges[loop_index] = x_edges_start + edges_x * y + x;
corner_verts[loop_index + 1] = vert_index + verts_y;
corner_edges[loop_index + 1] = y_edges_start + edges_y * (x + 1) + y;
corner_verts[loop_index + 2] = vert_index + verts_y + 1;
corner_edges[loop_index + 2] = x_edges_start + edges_x * (y + 1) + x;
corner_verts[loop_index + 3] = vert_index + 1;
corner_edges[loop_index + 3] = y_edges_start + edges_y * x + y;
}
});
}
});
if (uv_map_id && mesh->faces_num != 0) {
calculate_uvs(mesh, positions, corner_verts, size_x, size_y, uv_map_id);
}
mesh->tag_loose_verts_none();
mesh->tag_loose_edges_none();
mesh->tag_overlapping_none();
const float3 bounds = float3(size_x * 0.5f, size_y * 0.5f, 0.0f);
mesh->bounds_set_eager({-bounds, bounds});
return mesh;
}
} // namespace blender::geometry