1 /*************************************************************************/
2 /* primitive_meshes.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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 #include "primitive_meshes.h"
32 #include "servers/visual_server.h"
33
34 /**
35 PrimitiveMesh
36 */
_update() const37 void PrimitiveMesh::_update() const {
38
39 Array arr;
40 arr.resize(VS::ARRAY_MAX);
41 _create_mesh_array(arr);
42
43 PoolVector<Vector3> points = arr[VS::ARRAY_VERTEX];
44
45 aabb = AABB();
46
47 int pc = points.size();
48 ERR_FAIL_COND(pc == 0);
49 {
50
51 PoolVector<Vector3>::Read r = points.read();
52 for (int i = 0; i < pc; i++) {
53 if (i == 0)
54 aabb.position = r[i];
55 else
56 aabb.expand_to(r[i]);
57 }
58 }
59
60 if (flip_faces) {
61 PoolVector<Vector3> normals = arr[VS::ARRAY_NORMAL];
62 PoolVector<int> indices = arr[VS::ARRAY_INDEX];
63 if (normals.size() && indices.size()) {
64
65 {
66 int nc = normals.size();
67 PoolVector<Vector3>::Write w = normals.write();
68 for (int i = 0; i < nc; i++) {
69 w[i] = -w[i];
70 }
71 }
72
73 {
74 int ic = indices.size();
75 PoolVector<int>::Write w = indices.write();
76 for (int i = 0; i < ic; i += 3) {
77 SWAP(w[i + 0], w[i + 1]);
78 }
79 }
80 arr[VS::ARRAY_NORMAL] = normals;
81 arr[VS::ARRAY_INDEX] = indices;
82 }
83 }
84
85 // in with the new
86 VisualServer::get_singleton()->mesh_clear(mesh);
87 VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr);
88 VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
89
90 pending_request = false;
91
92 clear_cache();
93
94 const_cast<PrimitiveMesh *>(this)->emit_changed();
95 }
96
_request_update()97 void PrimitiveMesh::_request_update() {
98
99 if (pending_request)
100 return;
101 _update();
102 }
103
get_surface_count() const104 int PrimitiveMesh::get_surface_count() const {
105 if (pending_request) {
106 _update();
107 }
108 return 1;
109 }
110
surface_get_array_len(int p_idx) const111 int PrimitiveMesh::surface_get_array_len(int p_idx) const {
112 ERR_FAIL_INDEX_V(p_idx, 1, -1);
113 if (pending_request) {
114 _update();
115 }
116
117 return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, 0);
118 }
119
surface_get_array_index_len(int p_idx) const120 int PrimitiveMesh::surface_get_array_index_len(int p_idx) const {
121 ERR_FAIL_INDEX_V(p_idx, 1, -1);
122 if (pending_request) {
123 _update();
124 }
125
126 return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, 0);
127 }
128
surface_get_arrays(int p_surface) const129 Array PrimitiveMesh::surface_get_arrays(int p_surface) const {
130 ERR_FAIL_INDEX_V(p_surface, 1, Array());
131 if (pending_request) {
132 _update();
133 }
134
135 return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0);
136 }
137
surface_get_blend_shape_arrays(int p_surface) const138 Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
139 ERR_FAIL_INDEX_V(p_surface, 1, Array());
140 if (pending_request) {
141 _update();
142 }
143
144 return Array();
145 }
146
surface_get_format(int p_idx) const147 uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
148 ERR_FAIL_INDEX_V(p_idx, 1, 0);
149 if (pending_request) {
150 _update();
151 }
152
153 return VisualServer::get_singleton()->mesh_surface_get_format(mesh, 0);
154 }
155
surface_get_primitive_type(int p_idx) const156 Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
157 return primitive_type;
158 }
159
surface_set_material(int p_idx,const Ref<Material> & p_material)160 void PrimitiveMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) {
161 ERR_FAIL_INDEX(p_idx, 1);
162
163 set_material(p_material);
164 }
165
surface_get_material(int p_idx) const166 Ref<Material> PrimitiveMesh::surface_get_material(int p_idx) const {
167 ERR_FAIL_INDEX_V(p_idx, 1, NULL);
168
169 return material;
170 }
171
get_blend_shape_count() const172 int PrimitiveMesh::get_blend_shape_count() const {
173 return 0;
174 }
175
get_blend_shape_name(int p_index) const176 StringName PrimitiveMesh::get_blend_shape_name(int p_index) const {
177 return StringName();
178 }
179
get_aabb() const180 AABB PrimitiveMesh::get_aabb() const {
181 if (pending_request) {
182 _update();
183 }
184
185 return aabb;
186 }
187
get_rid() const188 RID PrimitiveMesh::get_rid() const {
189 if (pending_request) {
190 _update();
191 }
192 return mesh;
193 }
194
_bind_methods()195 void PrimitiveMesh::_bind_methods() {
196 ClassDB::bind_method(D_METHOD("_update"), &PrimitiveMesh::_update);
197
198 ClassDB::bind_method(D_METHOD("set_material", "material"), &PrimitiveMesh::set_material);
199 ClassDB::bind_method(D_METHOD("get_material"), &PrimitiveMesh::get_material);
200
201 ClassDB::bind_method(D_METHOD("get_mesh_arrays"), &PrimitiveMesh::get_mesh_arrays);
202
203 ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &PrimitiveMesh::set_custom_aabb);
204 ClassDB::bind_method(D_METHOD("get_custom_aabb"), &PrimitiveMesh::get_custom_aabb);
205
206 ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces);
207 ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
208
209 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material");
210 ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
211 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
212 }
213
set_material(const Ref<Material> & p_material)214 void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
215 material = p_material;
216 if (!pending_request) {
217 // just apply it, else it'll happen when _update is called.
218 VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
219 _change_notify();
220 emit_changed();
221 };
222 }
223
get_material() const224 Ref<Material> PrimitiveMesh::get_material() const {
225 return material;
226 }
227
get_mesh_arrays() const228 Array PrimitiveMesh::get_mesh_arrays() const {
229 return surface_get_arrays(0);
230 }
231
set_custom_aabb(const AABB & p_custom)232 void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
233
234 custom_aabb = p_custom;
235 VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
236 emit_changed();
237 }
238
get_custom_aabb() const239 AABB PrimitiveMesh::get_custom_aabb() const {
240
241 return custom_aabb;
242 }
243
set_flip_faces(bool p_enable)244 void PrimitiveMesh::set_flip_faces(bool p_enable) {
245 flip_faces = p_enable;
246 _request_update();
247 }
248
get_flip_faces() const249 bool PrimitiveMesh::get_flip_faces() const {
250 return flip_faces;
251 }
252
PrimitiveMesh()253 PrimitiveMesh::PrimitiveMesh() {
254
255 flip_faces = false;
256 // defaults
257 mesh = VisualServer::get_singleton()->mesh_create();
258
259 // assume primitive triangles as the type, correct for all but one and it will change this :)
260 primitive_type = Mesh::PRIMITIVE_TRIANGLES;
261
262 // make sure we do an update after we've finished constructing our object
263 pending_request = true;
264 }
265
~PrimitiveMesh()266 PrimitiveMesh::~PrimitiveMesh() {
267 VisualServer::get_singleton()->free(mesh);
268 }
269
270 /**
271 CapsuleMesh
272 */
273
_create_mesh_array(Array & p_arr) const274 void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
275 int i, j, prevrow, thisrow, point;
276 float x, y, z, u, v, w;
277 float onethird = 1.0 / 3.0;
278 float twothirds = 2.0 / 3.0;
279
280 // note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom
281
282 PoolVector<Vector3> points;
283 PoolVector<Vector3> normals;
284 PoolVector<float> tangents;
285 PoolVector<Vector2> uvs;
286 PoolVector<int> indices;
287 point = 0;
288
289 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
290 tangents.push_back(m_x); \
291 tangents.push_back(m_y); \
292 tangents.push_back(m_z); \
293 tangents.push_back(m_d);
294
295 /* top hemisphere */
296 thisrow = 0;
297 prevrow = 0;
298 for (j = 0; j <= (rings + 1); j++) {
299 v = j;
300
301 v /= (rings + 1);
302 w = sin(0.5 * Math_PI * v);
303 z = radius * cos(0.5 * Math_PI * v);
304
305 for (i = 0; i <= radial_segments; i++) {
306 u = i;
307 u /= radial_segments;
308
309 x = sin(u * (Math_PI * 2.0));
310 y = -cos(u * (Math_PI * 2.0));
311
312 Vector3 p = Vector3(x * radius * w, y * radius * w, z);
313 points.push_back(p + Vector3(0.0, 0.0, 0.5 * mid_height));
314 normals.push_back(p.normalized());
315 ADD_TANGENT(-y, x, 0.0, 1.0)
316 uvs.push_back(Vector2(u, v * onethird));
317 point++;
318
319 if (i > 0 && j > 0) {
320 indices.push_back(prevrow + i - 1);
321 indices.push_back(prevrow + i);
322 indices.push_back(thisrow + i - 1);
323
324 indices.push_back(prevrow + i);
325 indices.push_back(thisrow + i);
326 indices.push_back(thisrow + i - 1);
327 };
328 };
329
330 prevrow = thisrow;
331 thisrow = point;
332 };
333
334 /* cylinder */
335 thisrow = point;
336 prevrow = 0;
337 for (j = 0; j <= (rings + 1); j++) {
338 v = j;
339 v /= (rings + 1);
340
341 z = mid_height * v;
342 z = (mid_height * 0.5) - z;
343
344 for (i = 0; i <= radial_segments; i++) {
345 u = i;
346 u /= radial_segments;
347
348 x = sin(u * (Math_PI * 2.0));
349 y = -cos(u * (Math_PI * 2.0));
350
351 Vector3 p = Vector3(x * radius, y * radius, z);
352 points.push_back(p);
353 normals.push_back(Vector3(x, y, 0.0));
354 ADD_TANGENT(-y, x, 0.0, 1.0)
355 uvs.push_back(Vector2(u, onethird + (v * onethird)));
356 point++;
357
358 if (i > 0 && j > 0) {
359 indices.push_back(prevrow + i - 1);
360 indices.push_back(prevrow + i);
361 indices.push_back(thisrow + i - 1);
362
363 indices.push_back(prevrow + i);
364 indices.push_back(thisrow + i);
365 indices.push_back(thisrow + i - 1);
366 };
367 };
368
369 prevrow = thisrow;
370 thisrow = point;
371 };
372
373 /* bottom hemisphere */
374 thisrow = point;
375 prevrow = 0;
376 for (j = 0; j <= (rings + 1); j++) {
377 v = j;
378
379 v /= (rings + 1);
380 v += 1.0;
381 w = sin(0.5 * Math_PI * v);
382 z = radius * cos(0.5 * Math_PI * v);
383
384 for (i = 0; i <= radial_segments; i++) {
385 float u2 = i;
386 u2 /= radial_segments;
387
388 x = sin(u2 * (Math_PI * 2.0));
389 y = -cos(u2 * (Math_PI * 2.0));
390
391 Vector3 p = Vector3(x * radius * w, y * radius * w, z);
392 points.push_back(p + Vector3(0.0, 0.0, -0.5 * mid_height));
393 normals.push_back(p.normalized());
394 ADD_TANGENT(-y, x, 0.0, 1.0)
395 uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird)));
396 point++;
397
398 if (i > 0 && j > 0) {
399 indices.push_back(prevrow + i - 1);
400 indices.push_back(prevrow + i);
401 indices.push_back(thisrow + i - 1);
402
403 indices.push_back(prevrow + i);
404 indices.push_back(thisrow + i);
405 indices.push_back(thisrow + i - 1);
406 };
407 };
408
409 prevrow = thisrow;
410 thisrow = point;
411 };
412
413 p_arr[VS::ARRAY_VERTEX] = points;
414 p_arr[VS::ARRAY_NORMAL] = normals;
415 p_arr[VS::ARRAY_TANGENT] = tangents;
416 p_arr[VS::ARRAY_TEX_UV] = uvs;
417 p_arr[VS::ARRAY_INDEX] = indices;
418 }
419
_bind_methods()420 void CapsuleMesh::_bind_methods() {
421 ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleMesh::set_radius);
422 ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleMesh::get_radius);
423 ClassDB::bind_method(D_METHOD("set_mid_height", "mid_height"), &CapsuleMesh::set_mid_height);
424 ClassDB::bind_method(D_METHOD("get_mid_height"), &CapsuleMesh::get_mid_height);
425
426 ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CapsuleMesh::set_radial_segments);
427 ClassDB::bind_method(D_METHOD("get_radial_segments"), &CapsuleMesh::get_radial_segments);
428 ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings);
429 ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings);
430
431 ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
432 ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_mid_height", "get_mid_height");
433 ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
434 ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
435 }
436
set_radius(const float p_radius)437 void CapsuleMesh::set_radius(const float p_radius) {
438 radius = p_radius;
439 _request_update();
440 }
441
get_radius() const442 float CapsuleMesh::get_radius() const {
443 return radius;
444 }
445
set_mid_height(const float p_mid_height)446 void CapsuleMesh::set_mid_height(const float p_mid_height) {
447 mid_height = p_mid_height;
448 _request_update();
449 }
450
get_mid_height() const451 float CapsuleMesh::get_mid_height() const {
452 return mid_height;
453 }
454
set_radial_segments(const int p_segments)455 void CapsuleMesh::set_radial_segments(const int p_segments) {
456 radial_segments = p_segments > 4 ? p_segments : 4;
457 _request_update();
458 }
459
get_radial_segments() const460 int CapsuleMesh::get_radial_segments() const {
461 return radial_segments;
462 }
463
set_rings(const int p_rings)464 void CapsuleMesh::set_rings(const int p_rings) {
465 rings = p_rings > 1 ? p_rings : 1;
466 _request_update();
467 }
468
get_rings() const469 int CapsuleMesh::get_rings() const {
470 return rings;
471 }
472
CapsuleMesh()473 CapsuleMesh::CapsuleMesh() {
474 // defaults
475 radius = 1.0;
476 mid_height = 1.0;
477 radial_segments = 64;
478 rings = 8;
479 }
480
481 /**
482 CubeMesh
483 */
484
_create_mesh_array(Array & p_arr) const485 void CubeMesh::_create_mesh_array(Array &p_arr) const {
486 int i, j, prevrow, thisrow, point;
487 float x, y, z;
488 float onethird = 1.0 / 3.0;
489 float twothirds = 2.0 / 3.0;
490
491 Vector3 start_pos = size * -0.5;
492
493 // set our bounding box
494
495 PoolVector<Vector3> points;
496 PoolVector<Vector3> normals;
497 PoolVector<float> tangents;
498 PoolVector<Vector2> uvs;
499 PoolVector<int> indices;
500 point = 0;
501
502 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
503 tangents.push_back(m_x); \
504 tangents.push_back(m_y); \
505 tangents.push_back(m_z); \
506 tangents.push_back(m_d);
507
508 // front + back
509 y = start_pos.y;
510 thisrow = point;
511 prevrow = 0;
512 for (j = 0; j <= subdivide_h + 1; j++) {
513 x = start_pos.x;
514 for (i = 0; i <= subdivide_w + 1; i++) {
515 float u = i;
516 float v = j;
517 u /= (3.0 * (subdivide_w + 1.0));
518 v /= (2.0 * (subdivide_h + 1.0));
519
520 // front
521 points.push_back(Vector3(x, -y, -start_pos.z)); // double negative on the Z!
522 normals.push_back(Vector3(0.0, 0.0, 1.0));
523 ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
524 uvs.push_back(Vector2(u, v));
525 point++;
526
527 // back
528 points.push_back(Vector3(-x, -y, start_pos.z));
529 normals.push_back(Vector3(0.0, 0.0, -1.0));
530 ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
531 uvs.push_back(Vector2(twothirds + u, v));
532 point++;
533
534 if (i > 0 && j > 0) {
535 int i2 = i * 2;
536
537 // front
538 indices.push_back(prevrow + i2 - 2);
539 indices.push_back(prevrow + i2);
540 indices.push_back(thisrow + i2 - 2);
541 indices.push_back(prevrow + i2);
542 indices.push_back(thisrow + i2);
543 indices.push_back(thisrow + i2 - 2);
544
545 // back
546 indices.push_back(prevrow + i2 - 1);
547 indices.push_back(prevrow + i2 + 1);
548 indices.push_back(thisrow + i2 - 1);
549 indices.push_back(prevrow + i2 + 1);
550 indices.push_back(thisrow + i2 + 1);
551 indices.push_back(thisrow + i2 - 1);
552 };
553
554 x += size.x / (subdivide_w + 1.0);
555 };
556
557 y += size.y / (subdivide_h + 1.0);
558 prevrow = thisrow;
559 thisrow = point;
560 };
561
562 // left + right
563 y = start_pos.y;
564 thisrow = point;
565 prevrow = 0;
566 for (j = 0; j <= (subdivide_h + 1); j++) {
567 z = start_pos.z;
568 for (i = 0; i <= (subdivide_d + 1); i++) {
569 float u = i;
570 float v = j;
571 u /= (3.0 * (subdivide_d + 1.0));
572 v /= (2.0 * (subdivide_h + 1.0));
573
574 // right
575 points.push_back(Vector3(-start_pos.x, -y, -z));
576 normals.push_back(Vector3(1.0, 0.0, 0.0));
577 ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
578 uvs.push_back(Vector2(onethird + u, v));
579 point++;
580
581 // left
582 points.push_back(Vector3(start_pos.x, -y, z));
583 normals.push_back(Vector3(-1.0, 0.0, 0.0));
584 ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
585 uvs.push_back(Vector2(u, 0.5 + v));
586 point++;
587
588 if (i > 0 && j > 0) {
589 int i2 = i * 2;
590
591 // right
592 indices.push_back(prevrow + i2 - 2);
593 indices.push_back(prevrow + i2);
594 indices.push_back(thisrow + i2 - 2);
595 indices.push_back(prevrow + i2);
596 indices.push_back(thisrow + i2);
597 indices.push_back(thisrow + i2 - 2);
598
599 // left
600 indices.push_back(prevrow + i2 - 1);
601 indices.push_back(prevrow + i2 + 1);
602 indices.push_back(thisrow + i2 - 1);
603 indices.push_back(prevrow + i2 + 1);
604 indices.push_back(thisrow + i2 + 1);
605 indices.push_back(thisrow + i2 - 1);
606 };
607
608 z += size.z / (subdivide_d + 1.0);
609 };
610
611 y += size.y / (subdivide_h + 1.0);
612 prevrow = thisrow;
613 thisrow = point;
614 };
615
616 // top + bottom
617 z = start_pos.z;
618 thisrow = point;
619 prevrow = 0;
620 for (j = 0; j <= (subdivide_d + 1); j++) {
621 x = start_pos.x;
622 for (i = 0; i <= (subdivide_w + 1); i++) {
623 float u = i;
624 float v = j;
625 u /= (3.0 * (subdivide_w + 1.0));
626 v /= (2.0 * (subdivide_d + 1.0));
627
628 // top
629 points.push_back(Vector3(-x, -start_pos.y, -z));
630 normals.push_back(Vector3(0.0, 1.0, 0.0));
631 ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
632 uvs.push_back(Vector2(onethird + u, 0.5 + v));
633 point++;
634
635 // bottom
636 points.push_back(Vector3(x, start_pos.y, -z));
637 normals.push_back(Vector3(0.0, -1.0, 0.0));
638 ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
639 uvs.push_back(Vector2(twothirds + u, 0.5 + v));
640 point++;
641
642 if (i > 0 && j > 0) {
643 int i2 = i * 2;
644
645 // top
646 indices.push_back(prevrow + i2 - 2);
647 indices.push_back(prevrow + i2);
648 indices.push_back(thisrow + i2 - 2);
649 indices.push_back(prevrow + i2);
650 indices.push_back(thisrow + i2);
651 indices.push_back(thisrow + i2 - 2);
652
653 // bottom
654 indices.push_back(prevrow + i2 - 1);
655 indices.push_back(prevrow + i2 + 1);
656 indices.push_back(thisrow + i2 - 1);
657 indices.push_back(prevrow + i2 + 1);
658 indices.push_back(thisrow + i2 + 1);
659 indices.push_back(thisrow + i2 - 1);
660 };
661
662 x += size.x / (subdivide_w + 1.0);
663 };
664
665 z += size.z / (subdivide_d + 1.0);
666 prevrow = thisrow;
667 thisrow = point;
668 };
669
670 p_arr[VS::ARRAY_VERTEX] = points;
671 p_arr[VS::ARRAY_NORMAL] = normals;
672 p_arr[VS::ARRAY_TANGENT] = tangents;
673 p_arr[VS::ARRAY_TEX_UV] = uvs;
674 p_arr[VS::ARRAY_INDEX] = indices;
675 }
676
_bind_methods()677 void CubeMesh::_bind_methods() {
678 ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size);
679 ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size);
680
681 ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width);
682 ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width);
683 ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &CubeMesh::set_subdivide_height);
684 ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height);
685 ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth);
686 ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth);
687
688 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
689 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
690 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
691 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
692 }
693
set_size(const Vector3 & p_size)694 void CubeMesh::set_size(const Vector3 &p_size) {
695 size = p_size;
696 _request_update();
697 }
698
get_size() const699 Vector3 CubeMesh::get_size() const {
700 return size;
701 }
702
set_subdivide_width(const int p_divisions)703 void CubeMesh::set_subdivide_width(const int p_divisions) {
704 subdivide_w = p_divisions > 0 ? p_divisions : 0;
705 _request_update();
706 }
707
get_subdivide_width() const708 int CubeMesh::get_subdivide_width() const {
709 return subdivide_w;
710 }
711
set_subdivide_height(const int p_divisions)712 void CubeMesh::set_subdivide_height(const int p_divisions) {
713 subdivide_h = p_divisions > 0 ? p_divisions : 0;
714 _request_update();
715 }
716
get_subdivide_height() const717 int CubeMesh::get_subdivide_height() const {
718 return subdivide_h;
719 }
720
set_subdivide_depth(const int p_divisions)721 void CubeMesh::set_subdivide_depth(const int p_divisions) {
722 subdivide_d = p_divisions > 0 ? p_divisions : 0;
723 _request_update();
724 }
725
get_subdivide_depth() const726 int CubeMesh::get_subdivide_depth() const {
727 return subdivide_d;
728 }
729
CubeMesh()730 CubeMesh::CubeMesh() {
731 // defaults
732 size = Vector3(2.0, 2.0, 2.0);
733 subdivide_w = 0;
734 subdivide_h = 0;
735 subdivide_d = 0;
736 }
737
738 /**
739 CylinderMesh
740 */
741
_create_mesh_array(Array & p_arr) const742 void CylinderMesh::_create_mesh_array(Array &p_arr) const {
743 int i, j, prevrow, thisrow, point;
744 float x, y, z, u, v, radius;
745
746 PoolVector<Vector3> points;
747 PoolVector<Vector3> normals;
748 PoolVector<float> tangents;
749 PoolVector<Vector2> uvs;
750 PoolVector<int> indices;
751 point = 0;
752
753 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
754 tangents.push_back(m_x); \
755 tangents.push_back(m_y); \
756 tangents.push_back(m_z); \
757 tangents.push_back(m_d);
758
759 thisrow = 0;
760 prevrow = 0;
761 for (j = 0; j <= (rings + 1); j++) {
762 v = j;
763 v /= (rings + 1);
764
765 radius = top_radius + ((bottom_radius - top_radius) * v);
766
767 y = height * v;
768 y = (height * 0.5) - y;
769
770 for (i = 0; i <= radial_segments; i++) {
771 u = i;
772 u /= radial_segments;
773
774 x = sin(u * (Math_PI * 2.0));
775 z = cos(u * (Math_PI * 2.0));
776
777 Vector3 p = Vector3(x * radius, y, z * radius);
778 points.push_back(p);
779 normals.push_back(Vector3(x, 0.0, z));
780 ADD_TANGENT(z, 0.0, -x, 1.0)
781 uvs.push_back(Vector2(u, v * 0.5));
782 point++;
783
784 if (i > 0 && j > 0) {
785 indices.push_back(prevrow + i - 1);
786 indices.push_back(prevrow + i);
787 indices.push_back(thisrow + i - 1);
788
789 indices.push_back(prevrow + i);
790 indices.push_back(thisrow + i);
791 indices.push_back(thisrow + i - 1);
792 };
793 };
794
795 prevrow = thisrow;
796 thisrow = point;
797 };
798
799 // add top
800 if (top_radius > 0.0) {
801 y = height * 0.5;
802
803 thisrow = point;
804 points.push_back(Vector3(0.0, y, 0.0));
805 normals.push_back(Vector3(0.0, 1.0, 0.0));
806 ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
807 uvs.push_back(Vector2(0.25, 0.75));
808 point++;
809
810 for (i = 0; i <= radial_segments; i++) {
811 float r = i;
812 r /= radial_segments;
813
814 x = sin(r * (Math_PI * 2.0));
815 z = cos(r * (Math_PI * 2.0));
816
817 u = ((x + 1.0) * 0.25);
818 v = 0.5 + ((z + 1.0) * 0.25);
819
820 Vector3 p = Vector3(x * top_radius, y, z * top_radius);
821 points.push_back(p);
822 normals.push_back(Vector3(0.0, 1.0, 0.0));
823 ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
824 uvs.push_back(Vector2(u, v));
825 point++;
826
827 if (i > 0) {
828 indices.push_back(thisrow);
829 indices.push_back(point - 1);
830 indices.push_back(point - 2);
831 };
832 };
833 };
834
835 // add bottom
836 if (bottom_radius > 0.0) {
837 y = height * -0.5;
838
839 thisrow = point;
840 points.push_back(Vector3(0.0, y, 0.0));
841 normals.push_back(Vector3(0.0, -1.0, 0.0));
842 ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
843 uvs.push_back(Vector2(0.75, 0.75));
844 point++;
845
846 for (i = 0; i <= radial_segments; i++) {
847 float r = i;
848 r /= radial_segments;
849
850 x = sin(r * (Math_PI * 2.0));
851 z = cos(r * (Math_PI * 2.0));
852
853 u = 0.5 + ((x + 1.0) * 0.25);
854 v = 1.0 - ((z + 1.0) * 0.25);
855
856 Vector3 p = Vector3(x * bottom_radius, y, z * bottom_radius);
857 points.push_back(p);
858 normals.push_back(Vector3(0.0, -1.0, 0.0));
859 ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
860 uvs.push_back(Vector2(u, v));
861 point++;
862
863 if (i > 0) {
864 indices.push_back(thisrow);
865 indices.push_back(point - 2);
866 indices.push_back(point - 1);
867 };
868 };
869 };
870
871 p_arr[VS::ARRAY_VERTEX] = points;
872 p_arr[VS::ARRAY_NORMAL] = normals;
873 p_arr[VS::ARRAY_TANGENT] = tangents;
874 p_arr[VS::ARRAY_TEX_UV] = uvs;
875 p_arr[VS::ARRAY_INDEX] = indices;
876 }
877
_bind_methods()878 void CylinderMesh::_bind_methods() {
879 ClassDB::bind_method(D_METHOD("set_top_radius", "radius"), &CylinderMesh::set_top_radius);
880 ClassDB::bind_method(D_METHOD("get_top_radius"), &CylinderMesh::get_top_radius);
881 ClassDB::bind_method(D_METHOD("set_bottom_radius", "radius"), &CylinderMesh::set_bottom_radius);
882 ClassDB::bind_method(D_METHOD("get_bottom_radius"), &CylinderMesh::get_bottom_radius);
883 ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderMesh::set_height);
884 ClassDB::bind_method(D_METHOD("get_height"), &CylinderMesh::get_height);
885
886 ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CylinderMesh::set_radial_segments);
887 ClassDB::bind_method(D_METHOD("get_radial_segments"), &CylinderMesh::get_radial_segments);
888 ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings);
889 ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings);
890
891 ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_top_radius", "get_top_radius");
892 ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius");
893 ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
894 ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
895 ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
896 }
897
set_top_radius(const float p_radius)898 void CylinderMesh::set_top_radius(const float p_radius) {
899 top_radius = p_radius;
900 _request_update();
901 }
902
get_top_radius() const903 float CylinderMesh::get_top_radius() const {
904 return top_radius;
905 }
906
set_bottom_radius(const float p_radius)907 void CylinderMesh::set_bottom_radius(const float p_radius) {
908 bottom_radius = p_radius;
909 _request_update();
910 }
911
get_bottom_radius() const912 float CylinderMesh::get_bottom_radius() const {
913 return bottom_radius;
914 }
915
set_height(const float p_height)916 void CylinderMesh::set_height(const float p_height) {
917 height = p_height;
918 _request_update();
919 }
920
get_height() const921 float CylinderMesh::get_height() const {
922 return height;
923 }
924
set_radial_segments(const int p_segments)925 void CylinderMesh::set_radial_segments(const int p_segments) {
926 radial_segments = p_segments > 4 ? p_segments : 4;
927 _request_update();
928 }
929
get_radial_segments() const930 int CylinderMesh::get_radial_segments() const {
931 return radial_segments;
932 }
933
set_rings(const int p_rings)934 void CylinderMesh::set_rings(const int p_rings) {
935 rings = p_rings > 0 ? p_rings : 0;
936 _request_update();
937 }
938
get_rings() const939 int CylinderMesh::get_rings() const {
940 return rings;
941 }
942
CylinderMesh()943 CylinderMesh::CylinderMesh() {
944 // defaults
945 top_radius = 1.0;
946 bottom_radius = 1.0;
947 height = 2.0;
948 radial_segments = 64;
949 rings = 4;
950 }
951
952 /**
953 PlaneMesh
954 */
955
_create_mesh_array(Array & p_arr) const956 void PlaneMesh::_create_mesh_array(Array &p_arr) const {
957 int i, j, prevrow, thisrow, point;
958 float x, z;
959
960 Size2 start_pos = size * -0.5;
961
962 PoolVector<Vector3> points;
963 PoolVector<Vector3> normals;
964 PoolVector<float> tangents;
965 PoolVector<Vector2> uvs;
966 PoolVector<int> indices;
967 point = 0;
968
969 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
970 tangents.push_back(m_x); \
971 tangents.push_back(m_y); \
972 tangents.push_back(m_z); \
973 tangents.push_back(m_d);
974
975 /* top + bottom */
976 z = start_pos.y;
977 thisrow = point;
978 prevrow = 0;
979 for (j = 0; j <= (subdivide_d + 1); j++) {
980 x = start_pos.x;
981 for (i = 0; i <= (subdivide_w + 1); i++) {
982 float u = i;
983 float v = j;
984 u /= (subdivide_w + 1.0);
985 v /= (subdivide_d + 1.0);
986
987 points.push_back(Vector3(-x, 0.0, -z));
988 normals.push_back(Vector3(0.0, 1.0, 0.0));
989 ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
990 uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */
991 point++;
992
993 if (i > 0 && j > 0) {
994 indices.push_back(prevrow + i - 1);
995 indices.push_back(prevrow + i);
996 indices.push_back(thisrow + i - 1);
997 indices.push_back(prevrow + i);
998 indices.push_back(thisrow + i);
999 indices.push_back(thisrow + i - 1);
1000 };
1001
1002 x += size.x / (subdivide_w + 1.0);
1003 };
1004
1005 z += size.y / (subdivide_d + 1.0);
1006 prevrow = thisrow;
1007 thisrow = point;
1008 };
1009
1010 p_arr[VS::ARRAY_VERTEX] = points;
1011 p_arr[VS::ARRAY_NORMAL] = normals;
1012 p_arr[VS::ARRAY_TANGENT] = tangents;
1013 p_arr[VS::ARRAY_TEX_UV] = uvs;
1014 p_arr[VS::ARRAY_INDEX] = indices;
1015 }
1016
_bind_methods()1017 void PlaneMesh::_bind_methods() {
1018 ClassDB::bind_method(D_METHOD("set_size", "size"), &PlaneMesh::set_size);
1019 ClassDB::bind_method(D_METHOD("get_size"), &PlaneMesh::get_size);
1020
1021 ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &PlaneMesh::set_subdivide_width);
1022 ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width);
1023 ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth);
1024 ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth);
1025
1026 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
1027 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
1028 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
1029 }
1030
set_size(const Size2 & p_size)1031 void PlaneMesh::set_size(const Size2 &p_size) {
1032 size = p_size;
1033 _request_update();
1034 }
1035
get_size() const1036 Size2 PlaneMesh::get_size() const {
1037 return size;
1038 }
1039
set_subdivide_width(const int p_divisions)1040 void PlaneMesh::set_subdivide_width(const int p_divisions) {
1041 subdivide_w = p_divisions > 0 ? p_divisions : 0;
1042 _request_update();
1043 }
1044
get_subdivide_width() const1045 int PlaneMesh::get_subdivide_width() const {
1046 return subdivide_w;
1047 }
1048
set_subdivide_depth(const int p_divisions)1049 void PlaneMesh::set_subdivide_depth(const int p_divisions) {
1050 subdivide_d = p_divisions > 0 ? p_divisions : 0;
1051 _request_update();
1052 }
1053
get_subdivide_depth() const1054 int PlaneMesh::get_subdivide_depth() const {
1055 return subdivide_d;
1056 }
1057
PlaneMesh()1058 PlaneMesh::PlaneMesh() {
1059 // defaults
1060 size = Size2(2.0, 2.0);
1061 subdivide_w = 0;
1062 subdivide_d = 0;
1063 }
1064
1065 /**
1066 PrismMesh
1067 */
1068
_create_mesh_array(Array & p_arr) const1069 void PrismMesh::_create_mesh_array(Array &p_arr) const {
1070 int i, j, prevrow, thisrow, point;
1071 float x, y, z;
1072 float onethird = 1.0 / 3.0;
1073 float twothirds = 2.0 / 3.0;
1074
1075 Vector3 start_pos = size * -0.5;
1076
1077 // set our bounding box
1078
1079 PoolVector<Vector3> points;
1080 PoolVector<Vector3> normals;
1081 PoolVector<float> tangents;
1082 PoolVector<Vector2> uvs;
1083 PoolVector<int> indices;
1084 point = 0;
1085
1086 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
1087 tangents.push_back(m_x); \
1088 tangents.push_back(m_y); \
1089 tangents.push_back(m_z); \
1090 tangents.push_back(m_d);
1091
1092 /* front + back */
1093 y = start_pos.y;
1094 thisrow = point;
1095 prevrow = 0;
1096 for (j = 0; j <= (subdivide_h + 1); j++) {
1097 float scale = (y - start_pos.y) / size.y;
1098 float scaled_size_x = size.x * scale;
1099 float start_x = start_pos.x + (1.0 - scale) * size.x * left_to_right;
1100 float offset_front = (1.0 - scale) * onethird * left_to_right;
1101 float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right);
1102
1103 x = 0.0;
1104 for (i = 0; i <= (subdivide_w + 1); i++) {
1105 float u = i;
1106 float v = j;
1107 u /= (3.0 * (subdivide_w + 1.0));
1108 v /= (2.0 * (subdivide_h + 1.0));
1109
1110 u *= scale;
1111
1112 /* front */
1113 points.push_back(Vector3(start_x + x, -y, -start_pos.z)); // double negative on the Z!
1114 normals.push_back(Vector3(0.0, 0.0, 1.0));
1115 ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
1116 uvs.push_back(Vector2(offset_front + u, v));
1117 point++;
1118
1119 /* back */
1120 points.push_back(Vector3(start_x + scaled_size_x - x, -y, start_pos.z));
1121 normals.push_back(Vector3(0.0, 0.0, -1.0));
1122 ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
1123 uvs.push_back(Vector2(twothirds + offset_back + u, v));
1124 point++;
1125
1126 if (i > 0 && j == 1) {
1127 int i2 = i * 2;
1128
1129 /* front */
1130 indices.push_back(prevrow + i2);
1131 indices.push_back(thisrow + i2);
1132 indices.push_back(thisrow + i2 - 2);
1133
1134 /* back */
1135 indices.push_back(prevrow + i2 + 1);
1136 indices.push_back(thisrow + i2 + 1);
1137 indices.push_back(thisrow + i2 - 1);
1138 } else if (i > 0 && j > 0) {
1139 int i2 = i * 2;
1140
1141 /* front */
1142 indices.push_back(prevrow + i2 - 2);
1143 indices.push_back(prevrow + i2);
1144 indices.push_back(thisrow + i2 - 2);
1145 indices.push_back(prevrow + i2);
1146 indices.push_back(thisrow + i2);
1147 indices.push_back(thisrow + i2 - 2);
1148
1149 /* back */
1150 indices.push_back(prevrow + i2 - 1);
1151 indices.push_back(prevrow + i2 + 1);
1152 indices.push_back(thisrow + i2 - 1);
1153 indices.push_back(prevrow + i2 + 1);
1154 indices.push_back(thisrow + i2 + 1);
1155 indices.push_back(thisrow + i2 - 1);
1156 };
1157
1158 x += scale * size.x / (subdivide_w + 1.0);
1159 };
1160
1161 y += size.y / (subdivide_h + 1.0);
1162 prevrow = thisrow;
1163 thisrow = point;
1164 };
1165
1166 /* left + right */
1167 Vector3 normal_left, normal_right;
1168
1169 normal_left = Vector3(-size.y, size.x * left_to_right, 0.0);
1170 normal_right = Vector3(size.y, size.x * left_to_right, 0.0);
1171 normal_left.normalize();
1172 normal_right.normalize();
1173
1174 y = start_pos.y;
1175 thisrow = point;
1176 prevrow = 0;
1177 for (j = 0; j <= (subdivide_h + 1); j++) {
1178 float left, right;
1179 float scale = (y - start_pos.y) / size.y;
1180
1181 left = start_pos.x + (size.x * (1.0 - scale) * left_to_right);
1182 right = left + (size.x * scale);
1183
1184 z = start_pos.z;
1185 for (i = 0; i <= (subdivide_d + 1); i++) {
1186 float u = i;
1187 float v = j;
1188 u /= (3.0 * (subdivide_d + 1.0));
1189 v /= (2.0 * (subdivide_h + 1.0));
1190
1191 /* right */
1192 points.push_back(Vector3(right, -y, -z));
1193 normals.push_back(normal_right);
1194 ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
1195 uvs.push_back(Vector2(onethird + u, v));
1196 point++;
1197
1198 /* left */
1199 points.push_back(Vector3(left, -y, z));
1200 normals.push_back(normal_left);
1201 ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
1202 uvs.push_back(Vector2(u, 0.5 + v));
1203 point++;
1204
1205 if (i > 0 && j > 0) {
1206 int i2 = i * 2;
1207
1208 /* right */
1209 indices.push_back(prevrow + i2 - 2);
1210 indices.push_back(prevrow + i2);
1211 indices.push_back(thisrow + i2 - 2);
1212 indices.push_back(prevrow + i2);
1213 indices.push_back(thisrow + i2);
1214 indices.push_back(thisrow + i2 - 2);
1215
1216 /* left */
1217 indices.push_back(prevrow + i2 - 1);
1218 indices.push_back(prevrow + i2 + 1);
1219 indices.push_back(thisrow + i2 - 1);
1220 indices.push_back(prevrow + i2 + 1);
1221 indices.push_back(thisrow + i2 + 1);
1222 indices.push_back(thisrow + i2 - 1);
1223 };
1224
1225 z += size.z / (subdivide_d + 1.0);
1226 };
1227
1228 y += size.y / (subdivide_h + 1.0);
1229 prevrow = thisrow;
1230 thisrow = point;
1231 };
1232
1233 /* bottom */
1234 z = start_pos.z;
1235 thisrow = point;
1236 prevrow = 0;
1237 for (j = 0; j <= (subdivide_d + 1); j++) {
1238 x = start_pos.x;
1239 for (i = 0; i <= (subdivide_w + 1); i++) {
1240 float u = i;
1241 float v = j;
1242 u /= (3.0 * (subdivide_w + 1.0));
1243 v /= (2.0 * (subdivide_d + 1.0));
1244
1245 /* bottom */
1246 points.push_back(Vector3(x, start_pos.y, -z));
1247 normals.push_back(Vector3(0.0, -1.0, 0.0));
1248 ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
1249 uvs.push_back(Vector2(twothirds + u, 0.5 + v));
1250 point++;
1251
1252 if (i > 0 && j > 0) {
1253 /* bottom */
1254 indices.push_back(prevrow + i - 1);
1255 indices.push_back(prevrow + i);
1256 indices.push_back(thisrow + i - 1);
1257 indices.push_back(prevrow + i);
1258 indices.push_back(thisrow + i);
1259 indices.push_back(thisrow + i - 1);
1260 };
1261
1262 x += size.x / (subdivide_w + 1.0);
1263 };
1264
1265 z += size.z / (subdivide_d + 1.0);
1266 prevrow = thisrow;
1267 thisrow = point;
1268 };
1269
1270 p_arr[VS::ARRAY_VERTEX] = points;
1271 p_arr[VS::ARRAY_NORMAL] = normals;
1272 p_arr[VS::ARRAY_TANGENT] = tangents;
1273 p_arr[VS::ARRAY_TEX_UV] = uvs;
1274 p_arr[VS::ARRAY_INDEX] = indices;
1275 }
1276
_bind_methods()1277 void PrismMesh::_bind_methods() {
1278 ClassDB::bind_method(D_METHOD("set_left_to_right", "left_to_right"), &PrismMesh::set_left_to_right);
1279 ClassDB::bind_method(D_METHOD("get_left_to_right"), &PrismMesh::get_left_to_right);
1280
1281 ClassDB::bind_method(D_METHOD("set_size", "size"), &PrismMesh::set_size);
1282 ClassDB::bind_method(D_METHOD("get_size"), &PrismMesh::get_size);
1283
1284 ClassDB::bind_method(D_METHOD("set_subdivide_width", "segments"), &PrismMesh::set_subdivide_width);
1285 ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PrismMesh::get_subdivide_width);
1286 ClassDB::bind_method(D_METHOD("set_subdivide_height", "segments"), &PrismMesh::set_subdivide_height);
1287 ClassDB::bind_method(D_METHOD("get_subdivide_height"), &PrismMesh::get_subdivide_height);
1288 ClassDB::bind_method(D_METHOD("set_subdivide_depth", "segments"), &PrismMesh::set_subdivide_depth);
1289 ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth);
1290
1291 ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right");
1292 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
1293 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
1294 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_height", "get_subdivide_height");
1295 ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
1296 }
1297
set_left_to_right(const float p_left_to_right)1298 void PrismMesh::set_left_to_right(const float p_left_to_right) {
1299 left_to_right = p_left_to_right;
1300 _request_update();
1301 }
1302
get_left_to_right() const1303 float PrismMesh::get_left_to_right() const {
1304 return left_to_right;
1305 }
1306
set_size(const Vector3 & p_size)1307 void PrismMesh::set_size(const Vector3 &p_size) {
1308 size = p_size;
1309 _request_update();
1310 }
1311
get_size() const1312 Vector3 PrismMesh::get_size() const {
1313 return size;
1314 }
1315
set_subdivide_width(const int p_divisions)1316 void PrismMesh::set_subdivide_width(const int p_divisions) {
1317 subdivide_w = p_divisions > 0 ? p_divisions : 0;
1318 _request_update();
1319 }
1320
get_subdivide_width() const1321 int PrismMesh::get_subdivide_width() const {
1322 return subdivide_w;
1323 }
1324
set_subdivide_height(const int p_divisions)1325 void PrismMesh::set_subdivide_height(const int p_divisions) {
1326 subdivide_h = p_divisions > 0 ? p_divisions : 0;
1327 _request_update();
1328 }
1329
get_subdivide_height() const1330 int PrismMesh::get_subdivide_height() const {
1331 return subdivide_h;
1332 }
1333
set_subdivide_depth(const int p_divisions)1334 void PrismMesh::set_subdivide_depth(const int p_divisions) {
1335 subdivide_d = p_divisions > 0 ? p_divisions : 0;
1336 _request_update();
1337 }
1338
get_subdivide_depth() const1339 int PrismMesh::get_subdivide_depth() const {
1340 return subdivide_d;
1341 }
1342
PrismMesh()1343 PrismMesh::PrismMesh() {
1344 // defaults
1345 left_to_right = 0.5;
1346 size = Vector3(2.0, 2.0, 2.0);
1347 subdivide_w = 0;
1348 subdivide_h = 0;
1349 subdivide_d = 0;
1350 }
1351
1352 /**
1353 QuadMesh
1354 */
1355
_create_mesh_array(Array & p_arr) const1356 void QuadMesh::_create_mesh_array(Array &p_arr) const {
1357 PoolVector<Vector3> faces;
1358 PoolVector<Vector3> normals;
1359 PoolVector<float> tangents;
1360 PoolVector<Vector2> uvs;
1361
1362 faces.resize(6);
1363 normals.resize(6);
1364 tangents.resize(6 * 4);
1365 uvs.resize(6);
1366
1367 Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
1368
1369 Vector3 quad_faces[4] = {
1370 Vector3(-_size.x, -_size.y, 0),
1371 Vector3(-_size.x, _size.y, 0),
1372 Vector3(_size.x, _size.y, 0),
1373 Vector3(_size.x, -_size.y, 0),
1374 };
1375
1376 static const int indices[6] = {
1377 0, 1, 2,
1378 0, 2, 3
1379 };
1380
1381 for (int i = 0; i < 6; i++) {
1382
1383 int j = indices[i];
1384 faces.set(i, quad_faces[j]);
1385 normals.set(i, Vector3(0, 0, 1));
1386 tangents.set(i * 4 + 0, 1.0);
1387 tangents.set(i * 4 + 1, 0.0);
1388 tangents.set(i * 4 + 2, 0.0);
1389 tangents.set(i * 4 + 3, 1.0);
1390
1391 static const Vector2 quad_uv[4] = {
1392 Vector2(0, 1),
1393 Vector2(0, 0),
1394 Vector2(1, 0),
1395 Vector2(1, 1),
1396 };
1397
1398 uvs.set(i, quad_uv[j]);
1399 }
1400
1401 p_arr[VS::ARRAY_VERTEX] = faces;
1402 p_arr[VS::ARRAY_NORMAL] = normals;
1403 p_arr[VS::ARRAY_TANGENT] = tangents;
1404 p_arr[VS::ARRAY_TEX_UV] = uvs;
1405 }
1406
_bind_methods()1407 void QuadMesh::_bind_methods() {
1408 ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
1409 ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size);
1410 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
1411 }
1412
QuadMesh()1413 QuadMesh::QuadMesh() {
1414 primitive_type = PRIMITIVE_TRIANGLES;
1415 size = Size2(1.0, 1.0);
1416 }
1417
set_size(const Size2 & p_size)1418 void QuadMesh::set_size(const Size2 &p_size) {
1419 size = p_size;
1420 _request_update();
1421 }
1422
get_size() const1423 Size2 QuadMesh::get_size() const {
1424 return size;
1425 }
1426
1427 /**
1428 SphereMesh
1429 */
1430
_create_mesh_array(Array & p_arr) const1431 void SphereMesh::_create_mesh_array(Array &p_arr) const {
1432 int i, j, prevrow, thisrow, point;
1433 float x, y, z;
1434
1435 // set our bounding box
1436
1437 PoolVector<Vector3> points;
1438 PoolVector<Vector3> normals;
1439 PoolVector<float> tangents;
1440 PoolVector<Vector2> uvs;
1441 PoolVector<int> indices;
1442 point = 0;
1443
1444 #define ADD_TANGENT(m_x, m_y, m_z, m_d) \
1445 tangents.push_back(m_x); \
1446 tangents.push_back(m_y); \
1447 tangents.push_back(m_z); \
1448 tangents.push_back(m_d);
1449
1450 thisrow = 0;
1451 prevrow = 0;
1452 for (j = 0; j <= (rings + 1); j++) {
1453 float v = j;
1454 float w;
1455
1456 v /= (rings + 1);
1457 w = sin(Math_PI * v);
1458 y = height * (is_hemisphere ? 1.0 : 0.5) * cos(Math_PI * v);
1459
1460 for (i = 0; i <= radial_segments; i++) {
1461 float u = i;
1462 u /= radial_segments;
1463
1464 x = sin(u * (Math_PI * 2.0));
1465 z = cos(u * (Math_PI * 2.0));
1466
1467 if (is_hemisphere && y < 0.0) {
1468 points.push_back(Vector3(x * radius * w, 0.0, z * radius * w));
1469 normals.push_back(Vector3(0.0, -1.0, 0.0));
1470 } else {
1471 Vector3 p = Vector3(x * radius * w, y, z * radius * w);
1472 points.push_back(p);
1473 normals.push_back(p.normalized());
1474 };
1475 ADD_TANGENT(z, 0.0, -x, 1.0)
1476 uvs.push_back(Vector2(u, v));
1477 point++;
1478
1479 if (i > 0 && j > 0) {
1480 indices.push_back(prevrow + i - 1);
1481 indices.push_back(prevrow + i);
1482 indices.push_back(thisrow + i - 1);
1483
1484 indices.push_back(prevrow + i);
1485 indices.push_back(thisrow + i);
1486 indices.push_back(thisrow + i - 1);
1487 };
1488 };
1489
1490 prevrow = thisrow;
1491 thisrow = point;
1492 };
1493
1494 p_arr[VS::ARRAY_VERTEX] = points;
1495 p_arr[VS::ARRAY_NORMAL] = normals;
1496 p_arr[VS::ARRAY_TANGENT] = tangents;
1497 p_arr[VS::ARRAY_TEX_UV] = uvs;
1498 p_arr[VS::ARRAY_INDEX] = indices;
1499 }
1500
_bind_methods()1501 void SphereMesh::_bind_methods() {
1502 ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereMesh::set_radius);
1503 ClassDB::bind_method(D_METHOD("get_radius"), &SphereMesh::get_radius);
1504 ClassDB::bind_method(D_METHOD("set_height", "height"), &SphereMesh::set_height);
1505 ClassDB::bind_method(D_METHOD("get_height"), &SphereMesh::get_height);
1506
1507 ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &SphereMesh::set_radial_segments);
1508 ClassDB::bind_method(D_METHOD("get_radial_segments"), &SphereMesh::get_radial_segments);
1509 ClassDB::bind_method(D_METHOD("set_rings", "rings"), &SphereMesh::set_rings);
1510 ClassDB::bind_method(D_METHOD("get_rings"), &SphereMesh::get_rings);
1511
1512 ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere);
1513 ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere);
1514
1515 ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
1516 ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
1517 ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
1518 ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
1519 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere");
1520 }
1521
set_radius(const float p_radius)1522 void SphereMesh::set_radius(const float p_radius) {
1523 radius = p_radius;
1524 _request_update();
1525 }
1526
get_radius() const1527 float SphereMesh::get_radius() const {
1528 return radius;
1529 }
1530
set_height(const float p_height)1531 void SphereMesh::set_height(const float p_height) {
1532 height = p_height;
1533 _request_update();
1534 }
1535
get_height() const1536 float SphereMesh::get_height() const {
1537 return height;
1538 }
1539
set_radial_segments(const int p_radial_segments)1540 void SphereMesh::set_radial_segments(const int p_radial_segments) {
1541 radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
1542 _request_update();
1543 }
1544
get_radial_segments() const1545 int SphereMesh::get_radial_segments() const {
1546 return radial_segments;
1547 }
1548
set_rings(const int p_rings)1549 void SphereMesh::set_rings(const int p_rings) {
1550 rings = p_rings > 1 ? p_rings : 1;
1551 _request_update();
1552 }
1553
get_rings() const1554 int SphereMesh::get_rings() const {
1555 return rings;
1556 }
1557
set_is_hemisphere(const bool p_is_hemisphere)1558 void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
1559 is_hemisphere = p_is_hemisphere;
1560 _request_update();
1561 }
1562
get_is_hemisphere() const1563 bool SphereMesh::get_is_hemisphere() const {
1564 return is_hemisphere;
1565 }
1566
SphereMesh()1567 SphereMesh::SphereMesh() {
1568 // defaults
1569 radius = 1.0;
1570 height = 2.0;
1571 radial_segments = 64;
1572 rings = 32;
1573 is_hemisphere = false;
1574 }
1575
1576 /**
1577 PointMesh
1578 */
1579
_create_mesh_array(Array & p_arr) const1580 void PointMesh::_create_mesh_array(Array &p_arr) const {
1581 PoolVector<Vector3> faces;
1582 faces.resize(1);
1583 faces.set(0, Vector3(0.0, 0.0, 0.0));
1584
1585 p_arr[VS::ARRAY_VERTEX] = faces;
1586 }
1587
PointMesh()1588 PointMesh::PointMesh() {
1589 primitive_type = PRIMITIVE_POINTS;
1590 }
1591