1/**************************************************************************/
2/* primitive_meshes.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef PRIMITIVE_MESHES_H
32#define PRIMITIVE_MESHES_H
33
34#include "scene/resources/font.h"
35#include "scene/resources/mesh.h"
36#include "servers/text_server.h"
37
38///@TODO probably should change a few integers to unsigned integers...
39
40/**
41 Base class for all the classes in this file, handles a number of code functions that are shared among all meshes.
42 This class is set apart that it assumes a single surface is always generated for our mesh.
43*/
44
45class PrimitiveMesh : public Mesh {
46 GDCLASS(PrimitiveMesh, Mesh);
47
48private:
49 RID mesh;
50 mutable AABB aabb;
51 AABB custom_aabb;
52
53 mutable int array_len = 0;
54 mutable int index_array_len = 0;
55
56 Ref<Material> material;
57 bool flip_faces = false;
58
59 bool add_uv2 = false;
60 float uv2_padding = 2.0;
61
62 // make sure we do an update after we've finished constructing our object
63 mutable bool pending_request = true;
64 void _update() const;
65
66protected:
67 // assume primitive triangles as the type, correct for all but one and it will change this :)
68 Mesh::PrimitiveType primitive_type = Mesh::PRIMITIVE_TRIANGLES;
69
70 static void _bind_methods();
71
72 virtual void _create_mesh_array(Array &p_arr) const {}
73 void _request_update();
74 GDVIRTUAL0RC(Array, _create_mesh_array)
75
76 Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const;
77 float get_lightmap_texel_size() const;
78 virtual void _update_lightmap_size(){};
79
80public:
81 virtual int get_surface_count() const override;
82 virtual int surface_get_array_len(int p_idx) const override;
83 virtual int surface_get_array_index_len(int p_idx) const override;
84 virtual Array surface_get_arrays(int p_surface) const override;
85 virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
86 virtual Dictionary surface_get_lods(int p_surface) const override;
87 virtual BitField<ArrayFormat> surface_get_format(int p_idx) const override;
88 virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override;
89 virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override;
90 virtual Ref<Material> surface_get_material(int p_idx) const override;
91 virtual int get_blend_shape_count() const override;
92 virtual StringName get_blend_shape_name(int p_index) const override;
93 virtual void set_blend_shape_name(int p_index, const StringName &p_name) override;
94 virtual AABB get_aabb() const override;
95 virtual RID get_rid() const override;
96
97 void set_material(const Ref<Material> &p_material);
98 Ref<Material> get_material() const;
99
100 Array get_mesh_arrays() const;
101
102 void set_custom_aabb(const AABB &p_custom);
103 AABB get_custom_aabb() const;
104
105 void set_flip_faces(bool p_enable);
106 bool get_flip_faces() const;
107
108 void set_add_uv2(bool p_enable);
109 bool get_add_uv2() const { return add_uv2; }
110
111 void set_uv2_padding(float p_padding);
112 float get_uv2_padding() const { return uv2_padding; }
113
114 PrimitiveMesh();
115 ~PrimitiveMesh();
116};
117
118/**
119 Mesh for a simple capsule
120*/
121class CapsuleMesh : public PrimitiveMesh {
122 GDCLASS(CapsuleMesh, PrimitiveMesh);
123
124private:
125 float radius = 0.5;
126 float height = 2.0;
127 int radial_segments = 64;
128 int rings = 8;
129
130protected:
131 static void _bind_methods();
132 virtual void _create_mesh_array(Array &p_arr) const override;
133
134 virtual void _update_lightmap_size() override;
135
136public:
137 static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
138
139 void set_radius(const float p_radius);
140 float get_radius() const;
141
142 void set_height(const float p_height);
143 float get_height() const;
144
145 void set_radial_segments(const int p_segments);
146 int get_radial_segments() const;
147
148 void set_rings(const int p_rings);
149 int get_rings() const;
150
151 CapsuleMesh();
152};
153
154/**
155 A box
156*/
157class BoxMesh : public PrimitiveMesh {
158 GDCLASS(BoxMesh, PrimitiveMesh);
159
160private:
161 Vector3 size = Vector3(1, 1, 1);
162 int subdivide_w = 0;
163 int subdivide_h = 0;
164 int subdivide_d = 0;
165
166protected:
167 static void _bind_methods();
168 virtual void _create_mesh_array(Array &p_arr) const override;
169
170 virtual void _update_lightmap_size() override;
171
172public:
173 static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
174
175 void set_size(const Vector3 &p_size);
176 Vector3 get_size() const;
177
178 void set_subdivide_width(const int p_divisions);
179 int get_subdivide_width() const;
180
181 void set_subdivide_height(const int p_divisions);
182 int get_subdivide_height() const;
183
184 void set_subdivide_depth(const int p_divisions);
185 int get_subdivide_depth() const;
186
187 BoxMesh();
188};
189
190/**
191 A cylinder
192*/
193
194class CylinderMesh : public PrimitiveMesh {
195 GDCLASS(CylinderMesh, PrimitiveMesh);
196
197private:
198 float top_radius = 0.5;
199 float bottom_radius = 0.5;
200 float height = 2.0;
201 int radial_segments = 64;
202 int rings = 4;
203 bool cap_top = true;
204 bool cap_bottom = true;
205
206protected:
207 static void _bind_methods();
208 virtual void _create_mesh_array(Array &p_arr) const override;
209
210 virtual void _update_lightmap_size() override;
211
212public:
213 static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
214
215 void set_top_radius(const float p_radius);
216 float get_top_radius() const;
217
218 void set_bottom_radius(const float p_radius);
219 float get_bottom_radius() const;
220
221 void set_height(const float p_height);
222 float get_height() const;
223
224 void set_radial_segments(const int p_segments);
225 int get_radial_segments() const;
226
227 void set_rings(const int p_rings);
228 int get_rings() const;
229
230 void set_cap_top(bool p_cap_top);
231 bool is_cap_top() const;
232
233 void set_cap_bottom(bool p_cap_bottom);
234 bool is_cap_bottom() const;
235
236 CylinderMesh();
237};
238
239/*
240 A flat rectangle, can be used as quad or heightmap.
241*/
242class PlaneMesh : public PrimitiveMesh {
243 GDCLASS(PlaneMesh, PrimitiveMesh);
244
245public:
246 enum Orientation {
247 FACE_X,
248 FACE_Y,
249 FACE_Z,
250 };
251
252private:
253 Size2 size = Size2(2.0, 2.0);
254 int subdivide_w = 0;
255 int subdivide_d = 0;
256 Vector3 center_offset;
257 Orientation orientation = FACE_Y;
258
259protected:
260 static void _bind_methods();
261 virtual void _create_mesh_array(Array &p_arr) const override;
262
263 virtual void _update_lightmap_size() override;
264
265public:
266 void set_size(const Size2 &p_size);
267 Size2 get_size() const;
268
269 void set_subdivide_width(const int p_divisions);
270 int get_subdivide_width() const;
271
272 void set_subdivide_depth(const int p_divisions);
273 int get_subdivide_depth() const;
274
275 void set_center_offset(const Vector3 p_offset);
276 Vector3 get_center_offset() const;
277
278 void set_orientation(const Orientation p_orientation);
279 Orientation get_orientation() const;
280
281 PlaneMesh();
282};
283
284VARIANT_ENUM_CAST(PlaneMesh::Orientation)
285
286/*
287 A flat rectangle, inherits from PlaneMesh but defaults to facing the Z-plane.
288*/
289class QuadMesh : public PlaneMesh {
290 GDCLASS(QuadMesh, PlaneMesh);
291
292public:
293 QuadMesh() {
294 set_orientation(FACE_Z);
295 set_size(Size2(1, 1));
296 }
297};
298
299/**
300 A prism shapen, handy for ramps, triangles, etc.
301*/
302class PrismMesh : public PrimitiveMesh {
303 GDCLASS(PrismMesh, PrimitiveMesh);
304
305private:
306 float left_to_right = 0.5;
307 Vector3 size = Vector3(1.0, 1.0, 1.0);
308 int subdivide_w = 0;
309 int subdivide_h = 0;
310 int subdivide_d = 0;
311
312protected:
313 static void _bind_methods();
314 virtual void _create_mesh_array(Array &p_arr) const override;
315
316 virtual void _update_lightmap_size() override;
317
318public:
319 void set_left_to_right(const float p_left_to_right);
320 float get_left_to_right() const;
321
322 void set_size(const Vector3 &p_size);
323 Vector3 get_size() const;
324
325 void set_subdivide_width(const int p_divisions);
326 int get_subdivide_width() const;
327
328 void set_subdivide_height(const int p_divisions);
329 int get_subdivide_height() const;
330
331 void set_subdivide_depth(const int p_divisions);
332 int get_subdivide_depth() const;
333
334 PrismMesh();
335};
336
337/**
338 A sphere..
339*/
340class SphereMesh : public PrimitiveMesh {
341 GDCLASS(SphereMesh, PrimitiveMesh);
342
343private:
344 float radius = 0.5;
345 float height = 1.0;
346 int radial_segments = 64;
347 int rings = 32;
348 bool is_hemisphere = false;
349
350protected:
351 static void _bind_methods();
352 virtual void _create_mesh_array(Array &p_arr) const override;
353
354 virtual void _update_lightmap_size() override;
355
356public:
357 static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
358
359 void set_radius(const float p_radius);
360 float get_radius() const;
361
362 void set_height(const float p_height);
363 float get_height() const;
364
365 void set_radial_segments(const int p_radial_segments);
366 int get_radial_segments() const;
367
368 void set_rings(const int p_rings);
369 int get_rings() const;
370
371 void set_is_hemisphere(const bool p_is_hemisphere);
372 bool get_is_hemisphere() const;
373
374 SphereMesh();
375};
376
377/**
378 Big donut
379*/
380class TorusMesh : public PrimitiveMesh {
381 GDCLASS(TorusMesh, PrimitiveMesh);
382
383private:
384 float inner_radius = 0.5;
385 float outer_radius = 1.0;
386 int rings = 64;
387 int ring_segments = 32;
388
389protected:
390 static void _bind_methods();
391 virtual void _create_mesh_array(Array &p_arr) const override;
392
393 virtual void _update_lightmap_size() override;
394
395public:
396 void set_inner_radius(const float p_inner_radius);
397 float get_inner_radius() const;
398
399 void set_outer_radius(const float p_outer_radius);
400 float get_outer_radius() const;
401
402 void set_rings(const int p_rings);
403 int get_rings() const;
404
405 void set_ring_segments(const int p_ring_segments);
406 int get_ring_segments() const;
407
408 TorusMesh();
409};
410
411/**
412 A single point for use in particle systems
413*/
414
415class PointMesh : public PrimitiveMesh {
416 GDCLASS(PointMesh, PrimitiveMesh)
417
418protected:
419 virtual void _create_mesh_array(Array &p_arr) const override;
420
421public:
422 PointMesh();
423};
424
425class TubeTrailMesh : public PrimitiveMesh {
426 GDCLASS(TubeTrailMesh, PrimitiveMesh);
427
428private:
429 float radius = 0.5;
430 int radial_steps = 8;
431 int sections = 5;
432 float section_length = 0.2;
433 int section_rings = 3;
434 bool cap_top = true;
435 bool cap_bottom = true;
436
437 Ref<Curve> curve;
438
439 void _curve_changed();
440
441protected:
442 static void _bind_methods();
443 virtual void _create_mesh_array(Array &p_arr) const override;
444
445public:
446 void set_radius(const float p_radius);
447 float get_radius() const;
448
449 void set_radial_steps(const int p_radial_steps);
450 int get_radial_steps() const;
451
452 void set_sections(const int p_sections);
453 int get_sections() const;
454
455 void set_section_length(float p_sectionlength);
456 float get_section_length() const;
457
458 void set_section_rings(const int p_section_rings);
459 int get_section_rings() const;
460
461 void set_cap_top(bool p_cap_top);
462 bool is_cap_top() const;
463
464 void set_cap_bottom(bool p_cap_bottom);
465 bool is_cap_bottom() const;
466
467 void set_curve(const Ref<Curve> &p_curve);
468 Ref<Curve> get_curve() const;
469
470 virtual int get_builtin_bind_pose_count() const override;
471 virtual Transform3D get_builtin_bind_pose(int p_index) const override;
472
473 TubeTrailMesh();
474};
475
476class RibbonTrailMesh : public PrimitiveMesh {
477 GDCLASS(RibbonTrailMesh, PrimitiveMesh);
478
479public:
480 enum Shape {
481 SHAPE_FLAT,
482 SHAPE_CROSS
483 };
484
485private:
486 float size = 1.0;
487 int sections = 5;
488 float section_length = 0.2;
489 int section_segments = 3;
490
491 Shape shape = SHAPE_CROSS;
492
493 Ref<Curve> curve;
494
495 void _curve_changed();
496
497protected:
498 static void _bind_methods();
499 virtual void _create_mesh_array(Array &p_arr) const override;
500
501public:
502 void set_shape(Shape p_shape);
503 Shape get_shape() const;
504
505 void set_size(const float p_size);
506 float get_size() const;
507
508 void set_sections(const int p_sections);
509 int get_sections() const;
510
511 void set_section_length(float p_sectionlength);
512 float get_section_length() const;
513
514 void set_section_segments(const int p_section_segments);
515 int get_section_segments() const;
516
517 void set_curve(const Ref<Curve> &p_curve);
518 Ref<Curve> get_curve() const;
519
520 virtual int get_builtin_bind_pose_count() const override;
521 virtual Transform3D get_builtin_bind_pose(int p_index) const override;
522
523 RibbonTrailMesh();
524};
525
526/**
527 Text...
528*/
529
530class TextMesh : public PrimitiveMesh {
531 GDCLASS(TextMesh, PrimitiveMesh);
532
533private:
534 struct ContourPoint {
535 Vector2 point;
536 bool sharp = false;
537
538 ContourPoint(){};
539 ContourPoint(const Vector2 &p_pt, bool p_sharp) {
540 point = p_pt;
541 sharp = p_sharp;
542 };
543 };
544
545 struct ContourInfo {
546 real_t length = 0.0;
547 bool ccw = true;
548 ContourInfo(){};
549 ContourInfo(real_t p_len, bool p_ccw) {
550 length = p_len;
551 ccw = p_ccw;
552 }
553 };
554
555 struct GlyphMeshKey {
556 uint64_t font_id;
557 uint32_t gl_id;
558
559 bool operator==(const GlyphMeshKey &p_b) const {
560 return (font_id == p_b.font_id) && (gl_id == p_b.gl_id);
561 }
562
563 GlyphMeshKey(uint64_t p_font_id, uint32_t p_gl_id) {
564 font_id = p_font_id;
565 gl_id = p_gl_id;
566 }
567 };
568
569 struct GlyphMeshKeyHasher {
570 _FORCE_INLINE_ static uint32_t hash(const GlyphMeshKey &p_a) {
571 return hash_murmur3_buffer(&p_a, sizeof(GlyphMeshKey));
572 }
573 };
574
575 struct GlyphMeshData {
576 Vector<Vector2> triangles;
577 Vector<Vector<ContourPoint>> contours;
578 Vector<ContourInfo> contours_info;
579 Vector2 min_p = Vector2(INFINITY, INFINITY);
580 Vector2 max_p = Vector2(-INFINITY, -INFINITY);
581 };
582 mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
583
584 RID text_rid;
585 mutable Vector<RID> lines_rid;
586
587 String text;
588 String xl_text;
589
590 int font_size = 16;
591 Ref<Font> font_override;
592
593 TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
594 BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE;
595 float width = 500.0;
596 float line_spacing = 0.f;
597 Point2 lbl_offset;
598
599 HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
600 VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER;
601 bool uppercase = false;
602 String language;
603 TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
604 TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
605 Array st_args;
606
607 real_t depth = 0.05;
608 real_t pixel_size = 0.01;
609 real_t curve_step = 0.5;
610
611 mutable bool dirty_lines = true;
612 mutable bool dirty_text = true;
613 mutable bool dirty_font = true;
614 mutable bool dirty_cache = true;
615
616 void _generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_glyph) const;
617 void _font_changed();
618
619protected:
620 static void _bind_methods();
621 void _notification(int p_what);
622
623 virtual void _create_mesh_array(Array &p_arr) const override;
624
625public:
626 GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
627
628 TextMesh();
629 ~TextMesh();
630
631 void set_horizontal_alignment(HorizontalAlignment p_alignment);
632 HorizontalAlignment get_horizontal_alignment() const;
633
634 void set_vertical_alignment(VerticalAlignment p_alignment);
635 VerticalAlignment get_vertical_alignment() const;
636
637 void set_text(const String &p_string);
638 String get_text() const;
639
640 void set_font(const Ref<Font> &p_font);
641 Ref<Font> get_font() const;
642 Ref<Font> _get_font_or_default() const;
643
644 void set_font_size(int p_size);
645 int get_font_size() const;
646
647 void set_line_spacing(float p_size);
648 float get_line_spacing() const;
649
650 void set_autowrap_mode(TextServer::AutowrapMode p_mode);
651 TextServer::AutowrapMode get_autowrap_mode() const;
652
653 void set_justification_flags(BitField<TextServer::JustificationFlag> p_flags);
654 BitField<TextServer::JustificationFlag> get_justification_flags() const;
655
656 void set_text_direction(TextServer::Direction p_text_direction);
657 TextServer::Direction get_text_direction() const;
658
659 void set_language(const String &p_language);
660 String get_language() const;
661
662 void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser);
663 TextServer::StructuredTextParser get_structured_text_bidi_override() const;
664
665 void set_structured_text_bidi_override_options(Array p_args);
666 Array get_structured_text_bidi_override_options() const;
667
668 void set_uppercase(bool p_uppercase);
669 bool is_uppercase() const;
670
671 void set_width(real_t p_width);
672 real_t get_width() const;
673
674 void set_depth(real_t p_depth);
675 real_t get_depth() const;
676
677 void set_curve_step(real_t p_step);
678 real_t get_curve_step() const;
679
680 void set_pixel_size(real_t p_amount);
681 real_t get_pixel_size() const;
682
683 void set_offset(const Point2 &p_offset);
684 Point2 get_offset() const;
685};
686
687VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
688
689#endif // PRIMITIVE_MESHES_H
690