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