Blender V5.0
mesh_primitive_cylinder_cone.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cmath>
6
7#include "BLI_math_numbers.hh"
8
9#include "BKE_attribute.hh"
10#include "BKE_mesh.hh"
11
15
16namespace blender::geometry {
17
18struct ConeConfig {
21 float height;
26
29 /* The cone tip and a triangle fan filling are topologically identical.
30 * This simplifies the logic in some cases. */
33
34 /* Helpful quantities. */
41
42 /* Helpful vertex indices. */
47
48 /* Helpful edge indices. */
53
54 /* Helpful face indices. */
61
63 float radius_bottom,
64 float depth,
66 int side_segments,
67 int fill_segments,
71 height(0.5f * depth),
76 {
77 this->top_is_point = this->radius_top == 0.0f;
78 this->bottom_is_point = this->radius_bottom == 0.0f;
79 this->top_has_center_vert = this->top_is_point || this->fill_type == ConeFillType::Triangles;
80 this->bottom_has_center_vert = this->bottom_is_point ||
81 this->fill_type == ConeFillType::Triangles;
82
83 this->tot_quad_rings = this->calculate_total_quad_rings();
84 this->tot_edge_rings = this->calculate_total_edge_rings();
85 this->tot_verts = this->calculate_total_verts();
86 this->tot_edges = this->calculate_total_edges();
87 this->tot_corners = this->calculate_total_corners();
88
89 this->first_vert = 0;
90 this->first_ring_verts_start = this->top_has_center_vert ? 1 : first_vert;
91 this->last_vert = this->tot_verts - 1;
92 this->last_ring_verts_start = this->last_vert - this->circle_segments;
93
94 this->first_ring_edges_start = this->top_has_center_vert ? this->circle_segments : 0;
95 this->last_ring_edges_start = this->first_ring_edges_start +
96 this->tot_quad_rings * this->circle_segments * 2;
97 this->last_fan_edges_start = this->tot_edges - this->circle_segments;
98 this->last_edge = this->tot_edges - 1;
99
100 this->top_faces_start = 0;
101 if (!this->top_is_point) {
102 this->top_faces_len = (fill_segments - 1) * circle_segments;
103 this->top_faces_len += this->top_has_center_vert ? circle_segments : 0;
104 this->top_faces_len += this->fill_type == ConeFillType::NGon ? 1 : 0;
105 }
106 else {
107 this->top_faces_len = 0;
108 }
109
110 this->side_faces_start = this->top_faces_len;
111 if (this->top_is_point && this->bottom_is_point) {
112 this->side_faces_len = 0;
113 }
114 else {
115 this->side_faces_len = side_segments * circle_segments;
116 }
117
118 if (!this->bottom_is_point) {
119 this->bottom_faces_len = (fill_segments - 1) * circle_segments;
120 this->bottom_faces_len += this->bottom_has_center_vert ? circle_segments : 0;
121 this->bottom_faces_len += this->fill_type == ConeFillType::NGon ? 1 : 0;
122 }
123 else {
124 this->bottom_faces_len = 0;
125 }
126 this->bottom_faces_start = this->side_faces_start + this->side_faces_len;
127
128 this->tot_faces = this->top_faces_len + this->side_faces_len + this->bottom_faces_len;
129 }
130
131 private:
132 int calculate_total_quad_rings();
133 int calculate_total_edge_rings();
134 int calculate_total_verts();
135 int calculate_total_edges();
136 int calculate_total_corners();
137};
138
139int ConeConfig::calculate_total_quad_rings()
140{
142 return 0;
143 }
144
145 int quad_rings = 0;
146
147 if (!top_is_point) {
148 quad_rings += fill_segments - 1;
149 }
150
151 quad_rings += (!top_is_point && !bottom_is_point) ? side_segments : (side_segments - 1);
152
153 if (!bottom_is_point) {
154 quad_rings += fill_segments - 1;
155 }
156
157 return quad_rings;
158}
159
160int ConeConfig::calculate_total_edge_rings()
161{
163 return 0;
164 }
165
166 int edge_rings = 0;
167
168 if (!top_is_point) {
169 edge_rings += fill_segments;
170 }
171
172 edge_rings += side_segments - 1;
173
174 if (!bottom_is_point) {
175 edge_rings += fill_segments;
176 }
177
178 return edge_rings;
179}
180
181int ConeConfig::calculate_total_verts()
182{
184 return side_segments + 1;
185 }
186
187 int vert_total = 0;
188
190 vert_total++;
191 }
192
193 if (!top_is_point) {
194 vert_total += circle_segments * fill_segments;
195 }
196
197 vert_total += circle_segments * (side_segments - 1);
198
199 if (!bottom_is_point) {
200 vert_total += circle_segments * fill_segments;
201 }
202
204 vert_total++;
205 }
206
207 return vert_total;
208}
209
210int ConeConfig::calculate_total_edges()
211{
213 return side_segments;
214 }
215
216 int edge_total = 0;
218 edge_total += circle_segments;
219 }
220
221 edge_total += circle_segments * (tot_quad_rings * 2 + 1);
222
224 edge_total += circle_segments;
225 }
226
227 return edge_total;
228}
229
230int ConeConfig::calculate_total_corners()
231{
233 return 0;
234 }
235
236 int corner_total = 0;
237
239 corner_total += (circle_segments * 3);
240 }
241 else if (!top_is_point && fill_type == ConeFillType::NGon) {
242 corner_total += circle_segments;
243 }
244
245 corner_total += tot_quad_rings * (circle_segments * 4);
246
248 corner_total += (circle_segments * 3);
249 }
251 corner_total += circle_segments;
252 }
253
254 return corner_total;
255}
256
257static void calculate_cone_verts(const ConeConfig &config, MutableSpan<float3> positions)
258{
259 Array<float2> circle(config.circle_segments);
260 const float angle_delta = 2.0f * (math::numbers::pi / float(config.circle_segments));
261 float angle = 0.0f;
262 for (const int i : IndexRange(config.circle_segments)) {
263 circle[i].x = std::cos(angle);
264 circle[i].y = std::sin(angle);
265 angle += angle_delta;
266 }
267
268 int vert_index = 0;
269
270 /* Top cone tip or triangle fan center. */
271 if (config.top_has_center_vert) {
272 positions[vert_index++] = {0.0f, 0.0f, config.height};
273 }
274
275 /* Top fill including the outer edge of the fill. */
276 if (!config.top_is_point) {
277 const float top_fill_radius_delta = config.radius_top / float(config.fill_segments);
278 for (const int i : IndexRange(config.fill_segments)) {
279 const float top_fill_radius = top_fill_radius_delta * (i + 1);
280 for (const int j : IndexRange(config.circle_segments)) {
281 const float x = circle[j].x * top_fill_radius;
282 const float y = circle[j].y * top_fill_radius;
283 positions[vert_index++] = {x, y, config.height};
284 }
285 }
286 }
287
288 /* Rings along the side. */
289 const float side_radius_delta = (config.radius_bottom - config.radius_top) /
290 float(config.side_segments);
291 const float height_delta = 2.0f * config.height / float(config.side_segments);
292 for (const int i : IndexRange(config.side_segments - 1)) {
293 const float ring_radius = config.radius_top + (side_radius_delta * (i + 1));
294 const float ring_height = config.height - (height_delta * (i + 1));
295 for (const int j : IndexRange(config.circle_segments)) {
296 const float x = circle[j].x * ring_radius;
297 const float y = circle[j].y * ring_radius;
298 positions[vert_index++] = {x, y, ring_height};
299 }
300 }
301
302 /* Bottom fill including the outer edge of the fill. */
303 if (!config.bottom_is_point) {
304 const float bottom_fill_radius_delta = config.radius_bottom / float(config.fill_segments);
305 for (const int i : IndexRange(config.fill_segments)) {
306 const float bottom_fill_radius = config.radius_bottom - (i * bottom_fill_radius_delta);
307 for (const int j : IndexRange(config.circle_segments)) {
308 const float x = circle[j].x * bottom_fill_radius;
309 const float y = circle[j].y * bottom_fill_radius;
310 positions[vert_index++] = {x, y, -config.height};
311 }
312 }
313 }
314
315 /* Bottom cone tip or triangle fan center. */
316 if (config.bottom_has_center_vert) {
317 positions[vert_index++] = {0.0f, 0.0f, -config.height};
318 }
319}
320
321static void calculate_cone_edges(const ConeConfig &config, MutableSpan<int2> edges)
322{
323 int edge_index = 0;
324
325 /* Edges for top cone tip or triangle fan */
326 if (config.top_has_center_vert) {
327 for (const int i : IndexRange(config.circle_segments)) {
328 int2 &edge = edges[edge_index++];
329 edge[0] = config.first_vert;
330 edge[1] = config.first_ring_verts_start + i;
331 }
332 }
333
334 /* Rings and connecting edges between the rings. */
335 for (const int i : IndexRange(config.tot_edge_rings)) {
336 const int this_ring_vert_start = config.first_ring_verts_start + (i * config.circle_segments);
337 const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
338 /* Edge rings. */
339 for (const int j : IndexRange(config.circle_segments)) {
340 int2 &edge = edges[edge_index++];
341 edge[0] = this_ring_vert_start + j;
342 edge[1] = this_ring_vert_start + ((j + 1) % config.circle_segments);
343 }
344 if (i == config.tot_edge_rings - 1) {
345 /* There is one fewer ring of connecting edges. */
346 break;
347 }
348 /* Connecting edges. */
349 for (const int j : IndexRange(config.circle_segments)) {
350 int2 &edge = edges[edge_index++];
351 edge[0] = this_ring_vert_start + j;
352 edge[1] = next_ring_vert_start + j;
353 }
354 }
355
356 /* Edges for bottom triangle fan or tip. */
357 if (config.bottom_has_center_vert) {
358 for (const int i : IndexRange(config.circle_segments)) {
359 int2 &edge = edges[edge_index++];
360 edge[0] = config.last_ring_verts_start + i;
361 edge[1] = config.last_vert;
362 }
363 }
364}
365
366static void calculate_cone_faces(const ConeConfig &config,
367 MutableSpan<int> corner_verts,
368 MutableSpan<int> corner_edges,
369 MutableSpan<int> face_sizes)
370{
371 int rings_face_start = 0;
372 int rings_loop_start = 0;
373 if (config.top_has_center_vert) {
374 rings_face_start = config.circle_segments;
375 rings_loop_start = config.circle_segments * 3;
376
377 face_sizes.take_front(config.circle_segments).fill(3);
378
379 /* Top cone tip or center triangle fan in the fill. */
380 const int top_center_vert = 0;
381 const int top_fan_edges_start = 0;
382
383 for (const int i : IndexRange(config.circle_segments)) {
384 const int loop_start = i * 3;
385
386 corner_verts[loop_start + 0] = config.first_ring_verts_start + i;
387 corner_edges[loop_start + 0] = config.first_ring_edges_start + i;
388
389 corner_verts[loop_start + 1] = config.first_ring_verts_start +
390 ((i + 1) % config.circle_segments);
391 corner_edges[loop_start + 1] = top_fan_edges_start + ((i + 1) % config.circle_segments);
392
393 corner_verts[loop_start + 2] = top_center_vert;
394 corner_edges[loop_start + 2] = top_fan_edges_start + i;
395 }
396 }
397 else if (config.fill_type == ConeFillType::NGon) {
398 rings_face_start = 1;
399 rings_loop_start = config.circle_segments;
400
401 /* Center n-gon in the fill. */
402 face_sizes.first() = config.circle_segments;
403 for (const int i : IndexRange(config.circle_segments)) {
404 corner_verts[i] = i;
405 corner_edges[i] = i;
406 }
407 }
408
409 /* Quads connect one edge ring to the next one. */
410 const int ring_faces_num = config.tot_quad_rings * config.circle_segments;
411 face_sizes.slice(rings_face_start, ring_faces_num).fill(4);
412 for (const int i : IndexRange(config.tot_quad_rings)) {
413 const int this_ring_loop_start = rings_loop_start + i * config.circle_segments * 4;
414 const int this_ring_vert_start = config.first_ring_verts_start + (i * config.circle_segments);
415 const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
416
417 const int this_ring_edges_start = config.first_ring_edges_start +
418 (i * 2 * config.circle_segments);
419 const int next_ring_edges_start = this_ring_edges_start + (2 * config.circle_segments);
420 const int ring_connections_start = this_ring_edges_start + config.circle_segments;
421
422 for (const int j : IndexRange(config.circle_segments)) {
423 const int loop_start = this_ring_loop_start + j * 4;
424
425 corner_verts[loop_start + 0] = this_ring_vert_start + j;
426 corner_edges[loop_start + 0] = ring_connections_start + j;
427
428 corner_verts[loop_start + 1] = next_ring_vert_start + j;
429 corner_edges[loop_start + 1] = next_ring_edges_start + j;
430
431 corner_verts[loop_start + 2] = next_ring_vert_start + ((j + 1) % config.circle_segments);
432 corner_edges[loop_start + 2] = ring_connections_start + ((j + 1) % config.circle_segments);
433
434 corner_verts[loop_start + 3] = this_ring_vert_start + ((j + 1) % config.circle_segments);
435 corner_edges[loop_start + 3] = this_ring_edges_start + j;
436 }
437 }
438
439 const int bottom_face_start = rings_face_start + ring_faces_num;
440 const int bottom_loop_start = rings_loop_start + ring_faces_num * 4;
441
442 if (config.bottom_has_center_vert) {
443 face_sizes.slice(bottom_face_start, config.circle_segments).fill(3);
444
445 /* Bottom cone tip or center triangle fan in the fill. */
446 for (const int i : IndexRange(config.circle_segments)) {
447 const int loop_start = bottom_loop_start + i * 3;
448
449 corner_verts[loop_start + 0] = config.last_ring_verts_start + i;
450 corner_edges[loop_start + 0] = config.last_fan_edges_start + i;
451
452 corner_verts[loop_start + 1] = config.last_vert;
453 corner_edges[loop_start + 1] = config.last_fan_edges_start +
454 (i + 1) % config.circle_segments;
455
456 corner_verts[loop_start + 2] = config.last_ring_verts_start +
457 (i + 1) % config.circle_segments;
458 corner_edges[loop_start + 2] = config.last_ring_edges_start + i;
459 }
460 }
461 else if (config.fill_type == ConeFillType::NGon) {
462 /* Center n-gon in the fill. */
463 face_sizes[bottom_face_start] = config.circle_segments;
464 for (const int i : IndexRange(config.circle_segments)) {
465 /* Go backwards to reverse surface normal. */
466 corner_verts[bottom_loop_start + i] = config.last_vert - i;
467 corner_edges[bottom_loop_start + i] = config.last_edge - ((i + 1) % config.circle_segments);
468 }
469 }
470}
471
472static void calculate_selection_outputs(const ConeConfig &config,
473 const ConeAttributeOutputs &attribute_outputs,
475{
476 /* Populate "Top" selection output. */
477 if (attribute_outputs.top_id) {
478 const bool face = !config.top_is_point && config.fill_type != ConeFillType::None;
480 *attribute_outputs.top_id, face ? bke::AttrDomain::Face : bke::AttrDomain::Point);
481
482 if (config.top_is_point) {
483 selection.span[config.first_vert] = true;
484 }
485 else {
486 selection.span.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
487 }
488 selection.finish();
489 }
490
491 /* Populate "Bottom" selection output. */
492 if (attribute_outputs.bottom_id) {
493 const bool face = !config.bottom_is_point && config.fill_type != ConeFillType::None;
495 *attribute_outputs.bottom_id, face ? bke::AttrDomain::Face : bke::AttrDomain::Point);
496
497 if (config.bottom_is_point) {
498 selection.span[config.last_vert] = true;
499 }
500 else if (face) {
501 selection.span.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true);
502 }
503 else {
504 selection.span.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true);
505 }
506 selection.finish();
507 }
508
509 /* Populate "Side" selection output. */
510 if (attribute_outputs.side_id) {
512 *attribute_outputs.side_id, bke::AttrDomain::Face);
513
514 selection.span.slice(config.side_faces_start, config.side_faces_len).fill(true);
515 selection.finish();
516 }
517}
518
527static void calculate_cone_uvs(const ConeConfig &config, Mesh *mesh, const StringRef uv_map_id)
528{
529 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
530
533 MutableSpan<float2> uvs = uv_attribute.span;
534
535 Array<float2> circle(config.circle_segments);
536 float angle = 0.0f;
537 const float angle_delta = 2.0f * math::numbers::pi / float(config.circle_segments);
538 for (const int i : IndexRange(config.circle_segments)) {
539 circle[i].x = std::cos(angle) * 0.225f;
540 circle[i].y = std::sin(angle) * 0.225f;
541 angle += angle_delta;
542 }
543
544 int corner = 0;
545
546 /* Left circle of the UV representing the top fill or top cone tip. */
547 if (config.top_is_point || config.fill_type != ConeFillType::None) {
548 const float2 center_left(0.25f, 0.25f);
549 const float radius_factor_delta = 1.0f / (config.top_is_point ? float(config.side_segments) :
550 float(config.fill_segments));
551 const int left_circle_segment_count = config.top_is_point ? config.side_segments :
552 config.fill_segments;
553
554 if (config.top_has_center_vert) {
555 /* Cone tip itself or triangle fan center of the fill. */
556 for (const int i : IndexRange(config.circle_segments)) {
557 uvs[corner++] = radius_factor_delta * circle[i] + center_left;
558 uvs[corner++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
559 center_left;
560 uvs[corner++] = center_left;
561 }
562 }
563 else if (!config.top_is_point && config.fill_type == ConeFillType::NGon) {
564 /* N-gon at the center of the fill. */
565 for (const int i : IndexRange(config.circle_segments)) {
566 uvs[corner++] = radius_factor_delta * circle[i] + center_left;
567 }
568 }
569 /* The rest of the top fill is made out of quad rings. */
570 for (const int i : IndexRange(1, left_circle_segment_count - 1)) {
571 const float inner_radius_factor = i * radius_factor_delta;
572 const float outer_radius_factor = (i + 1) * radius_factor_delta;
573 for (const int j : IndexRange(config.circle_segments)) {
574 uvs[corner++] = inner_radius_factor * circle[j] + center_left;
575 uvs[corner++] = outer_radius_factor * circle[j] + center_left;
576 uvs[corner++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
577 center_left;
578 uvs[corner++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
579 center_left;
580 }
581 }
582 }
583
584 if (!config.top_is_point && !config.bottom_is_point) {
585 /* Mesh is a truncated cone or cylinder. The sides are unwrapped into a rectangle. */
586 const float bottom = (config.fill_type == ConeFillType::None) ? 0.0f : 0.5f;
587 const float x_delta = 1.0f / float(config.circle_segments);
588 const float y_delta = (1.0f - bottom) / float(config.side_segments);
589
590 for (const int i : IndexRange(config.side_segments)) {
591 for (const int j : IndexRange(config.circle_segments)) {
592 uvs[corner++] = float2(j * x_delta, i * y_delta + bottom);
593 uvs[corner++] = float2(j * x_delta, (i + 1) * y_delta + bottom);
594 uvs[corner++] = float2((j + 1) * x_delta, (i + 1) * y_delta + bottom);
595 uvs[corner++] = float2((j + 1) * x_delta, i * y_delta + bottom);
596 }
597 }
598 }
599
600 /* Right circle of the UV representing the bottom fill or bottom cone tip. */
601 if (config.bottom_is_point || config.fill_type != ConeFillType::None) {
602 const float2 center_right(0.75f, 0.25f);
603 const float radius_factor_delta = 1.0f / (config.bottom_is_point ?
604 float(config.side_segments) :
605 float(config.fill_segments));
606 const int right_circle_segment_count = config.bottom_is_point ? config.side_segments :
607 config.fill_segments;
608
609 /* The bottom circle has to be created outside in to match the loop order. */
610 for (const int i : IndexRange(right_circle_segment_count - 1)) {
611 const float outer_radius_factor = 1.0f - i * radius_factor_delta;
612 const float inner_radius_factor = 1.0f - (i + 1) * radius_factor_delta;
613 for (const int j : IndexRange(config.circle_segments)) {
614 uvs[corner++] = outer_radius_factor * circle[j] + center_right;
615 uvs[corner++] = inner_radius_factor * circle[j] + center_right;
616 uvs[corner++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
617 center_right;
618 uvs[corner++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
619 center_right;
620 }
621 }
622
623 if (config.bottom_has_center_vert) {
624 /* Cone tip itself or triangle fan center of the fill. */
625 for (const int i : IndexRange(config.circle_segments)) {
626 uvs[corner++] = radius_factor_delta * circle[i] + center_right;
627 uvs[corner++] = center_right;
628 uvs[corner++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
629 center_right;
630 }
631 }
632 else if (!config.bottom_is_point && config.fill_type == ConeFillType::NGon) {
633 /* N-gon at the center of the fill. */
634 for (const int i : IndexRange(config.circle_segments)) {
635 /* Go backwards because of reversed face normal. */
636 uvs[corner++] = radius_factor_delta * circle[config.circle_segments - 1 - i] +
637 center_right;
638 }
639 }
640 }
641
642 uv_attribute.finish();
643}
644
646{
647 /* Returns a mesh with a single vertex at the origin. */
648 Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0);
649 mesh->vert_positions_for_write().first() = float3(0);
650 return mesh;
651}
652
658
659Mesh *create_cylinder_or_cone_mesh(const float radius_top,
660 const float radius_bottom,
661 const float depth,
662 const int circle_segments,
663 const int side_segments,
664 const int fill_segments,
665 const ConeFillType fill_type,
666 ConeAttributeOutputs &attribute_outputs)
667{
668 const ConeConfig config(
669 radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type);
670
671 /* Handle the case of a line / single point before everything else to avoid
672 * the need to check for it later. */
673 if (config.top_is_point && config.bottom_is_point) {
674 if (config.height == 0.0f) {
675 return create_vertex_mesh();
676 }
677 const float z_delta = -2.0f * config.height / float(config.side_segments);
678 const float3 start(0.0f, 0.0f, config.height);
679 const float3 delta(0.0f, 0.0f, z_delta);
680 return create_line_mesh(start, delta, config.tot_verts);
681 }
682
684 config.tot_verts, config.tot_edges, config.tot_faces, config.tot_corners);
685
686 MutableSpan<float3> positions = mesh->vert_positions_for_write();
687 MutableSpan<int2> edges = mesh->edges_for_write();
688 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
689 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
690 MutableSpan<int> corner_edges = mesh->corner_edges_for_write();
691 bke::mesh_smooth_set(*mesh, false);
692
693 calculate_cone_verts(config, positions);
694 calculate_cone_edges(config, edges);
695 calculate_cone_faces(config, corner_verts, corner_edges, face_offsets.drop_back(1));
697 if (attribute_outputs.uv_map_id) {
698 calculate_cone_uvs(config, mesh, *attribute_outputs.uv_map_id);
699 }
700 calculate_selection_outputs(config, attribute_outputs, mesh->attributes_for_write());
701
702 mesh->tag_loose_verts_none();
703 mesh->tag_loose_edges_none();
704 mesh->tag_overlapping_none();
705 mesh->bounds_set_eager(calculate_bounds_cylinder(config));
706
707 return mesh;
708}
709
710} // namespace blender::geometry
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr MutableSpan drop_back(const int64_t n) const
Definition BLI_span.hh:618
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr T & first() const
Definition BLI_span.hh:679
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
nullptr float
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
static Bounds< float3 > calculate_bounds_cylinder(const ConeConfig &config)
static void calculate_cone_uvs(const ConeConfig &config, Mesh *mesh, const StringRef uv_map_id)
Mesh * create_cylinder_or_cone_mesh(float radius_top, float radius_bottom, float depth, int circle_segments, int side_segments, int fill_segments, ConeFillType fill_type, ConeAttributeOutputs &attribute_outputs)
static void calculate_cone_faces(const ConeConfig &config, MutableSpan< int > corner_verts, MutableSpan< int > corner_edges, MutableSpan< int > face_sizes)
Bounds< float3 > calculate_bounds_radial_primitive(float radius_top, float radius_bottom, int segments, float height)
Mesh * create_line_mesh(float3 start, float3 delta, int count)
static void calculate_cone_edges(const ConeConfig &config, MutableSpan< int2 > edges)
static void calculate_selection_outputs(const ConeConfig &config, const ConeAttributeOutputs &attribute_outputs, bke::MutableAttributeAccessor attributes)
static void calculate_cone_verts(const ConeConfig &config, MutableSpan< float3 > positions)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
ConeConfig(float radius_top, float radius_bottom, float depth, int circle_segments, int side_segments, int fill_segments, ConeFillType fill_type)
i
Definition text_draw.cc:230