1use crate::{color::Color, get_context};
4
5use crate::{quad_gl::DrawMode, texture::Texture2D};
6use glam::{vec2, vec3, vec4, Quat, Vec2, Vec3, Vec4};
7
8#[repr(C)]
9#[derive(Clone, Debug, Copy)]
10pub struct Vertex {
11 pub position: Vec3,
12 pub uv: Vec2,
13 pub color: [u8; 4],
14 pub normal: Vec4,
19}
20
21impl Vertex {
22 pub fn new(x: f32, y: f32, z: f32, u: f32, v: f32, color: Color) -> Vertex {
23 Vertex {
24 position: vec3(x, y, z),
25 uv: vec2(u, v),
26 color: color.into(),
27 normal: vec4(0.0, 0.0, 0.0, 0.0),
28 }
29 }
30
31 pub fn new2(position: Vec3, uv: Vec2, color: Color) -> Vertex {
32 Vertex {
33 position,
34 uv,
35 color: color.into(),
36 normal: vec4(0.0, 0.0, 0.0, 0.0),
37 }
38 }
39}
40
41pub struct Mesh {
42 pub vertices: Vec<Vertex>,
43 pub indices: Vec<u16>,
44 pub texture: Option<Texture2D>,
45}
46
47pub fn draw_mesh(mesh: &Mesh) {
48 let context = get_context();
49
50 context.gl.texture(mesh.texture.as_ref());
51 context.gl.draw_mode(DrawMode::Triangles);
52 context.gl.geometry(&mesh.vertices[..], &mesh.indices[..]);
53}
54
55fn draw_quad(vertices: [Vertex; 4]) {
56 let context = get_context();
57 let indices = [0, 1, 2, 0, 2, 3];
58 context.gl.draw_mode(DrawMode::Triangles);
59 context.gl.geometry(&vertices, &indices);
60}
61
62pub fn draw_line_3d(start: Vec3, end: Vec3, color: Color) {
63 let context = get_context();
64 let uv = vec2(0., 0.);
65 let indices = [0, 1];
66
67 let line = [Vertex::new2(start, uv, color), Vertex::new2(end, uv, color)];
68
69 context.gl.texture(None);
70 context.gl.draw_mode(DrawMode::Lines);
71 context.gl.geometry(&line, &indices);
72}
73
74pub fn draw_grid(slices: u32, spacing: f32, axes_color: Color, other_color: Color) {
76 draw_grid_ex(
77 slices,
78 spacing,
79 axes_color,
80 other_color,
81 vec3(0., 0., 0.),
82 Quat::IDENTITY,
83 );
84}
85
86pub fn draw_grid_ex(
88 slices: u32,
89 spacing: f32,
90 axes_color: Color,
91 other_color: Color,
92 center: Vec3,
93 rotation: Quat,
94) {
95 let half_slices = (slices as i32) / 2;
96 for i in -half_slices..half_slices + 1 {
97 let color = if i == 0 { axes_color } else { other_color };
98
99 let start = vec3(i as f32 * spacing, 0., -half_slices as f32 * spacing);
100 let end = vec3(i as f32 * spacing, 0., half_slices as f32 * spacing);
101
102 draw_line_3d(
103 rotation.mul_vec3(start) + center,
104 rotation.mul_vec3(end) + center,
105 color,
106 );
107
108 let start = vec3(-half_slices as f32 * spacing, 0., i as f32 * spacing);
109 let end = vec3(half_slices as f32 * spacing, 0., i as f32 * spacing);
110
111 draw_line_3d(
112 rotation.mul_vec3(start) + center,
113 rotation.mul_vec3(end) + center,
114 color,
115 );
116 }
117}
118
119pub fn draw_plane(center: Vec3, size: Vec2, texture: Option<&Texture2D>, color: Color) {
120 let v1 = Vertex::new2(center + vec3(-size.x, 0., -size.y), vec2(0., 0.), color);
121 let v2 = Vertex::new2(center + vec3(-size.x, 0., size.y), vec2(0., 1.), color);
122 let v3 = Vertex::new2(center + vec3(size.x, 0., size.y), vec2(1., 1.), color);
123 let v4 = Vertex::new2(center + vec3(size.x, 0., -size.y), vec2(1., 0.), color);
124
125 {
126 let context = get_context();
127 context.gl.texture(texture);
128 }
129 draw_quad([v1, v2, v3, v4]);
130}
131
132pub fn draw_affine_parallelogram(
152 offset: Vec3,
153 e1: Vec3,
154 e2: Vec3,
155 texture: Option<&Texture2D>,
156 color: Color,
157) {
158 let v1 = Vertex::new2(offset, vec2(0., 0.), color);
159 let v2 = Vertex::new2(offset + e1, vec2(0., 1.), color);
160 let v3 = Vertex::new2(offset + e1 + e2, vec2(1., 1.), color);
161 let v4 = Vertex::new2(offset + e2, vec2(1., 0.), color);
162
163 {
164 let context = get_context();
165 context.gl.texture(texture);
166 }
167 draw_quad([v1, v2, v3, v4]);
168}
169
170pub fn draw_affine_parallelepiped(
197 offset: Vec3,
198 e1: Vec3,
199 e2: Vec3,
200 e3: Vec3,
201 texture: Option<&Texture2D>,
202 color: Color,
203) {
204 draw_affine_parallelogram(offset, e1, e2, texture, color);
205 draw_affine_parallelogram(offset, e1, e3, texture, color);
206 draw_affine_parallelogram(offset, e2, e3, texture, color);
207
208 draw_affine_parallelogram(offset + e1, e2, e3, texture, color);
209 draw_affine_parallelogram(offset + e2, e1, e3, texture, color);
210 draw_affine_parallelogram(offset + e3, e1, e2, texture, color);
211}
212
213pub fn draw_cube(position: Vec3, size: Vec3, texture: Option<&Texture2D>, color: Color) {
214 let context = get_context();
215 context.gl.texture(texture);
216
217 let (x, y, z) = (position.x, position.y, position.z);
218 let (width, height, length) = (size.x, size.y, size.z);
219
220 let bl_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
222 let bl_uv = vec2(0., 0.);
223 let br_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
224 let br_uv = vec2(1., 0.);
225
226 let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
227 let tr_uv = vec2(1., 1.);
228
229 let tl_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
230 let tl_uv = vec2(0., 1.);
231
232 draw_quad([
233 Vertex::new2(bl_pos, bl_uv, color),
234 Vertex::new2(br_pos, br_uv, color),
235 Vertex::new2(tr_pos, tr_uv, color),
236 Vertex::new2(tl_pos, tl_uv, color),
237 ]);
238
239 let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
241 let bl_uv = vec2(0., 0.);
242 let br_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
243 let br_uv = vec2(1., 0.);
244
245 let tr_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
246 let tr_uv = vec2(1., 1.);
247
248 let tl_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
249 let tl_uv = vec2(0., 1.);
250
251 draw_quad([
252 Vertex::new2(bl_pos, bl_uv, color),
253 Vertex::new2(br_pos, br_uv, color),
254 Vertex::new2(tr_pos, tr_uv, color),
255 Vertex::new2(tl_pos, tl_uv, color),
256 ]);
257
258 let bl_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
260 let bl_uv = vec2(0., 1.);
261 let br_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
262 let br_uv = vec2(0., 0.);
263
264 let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
265 let tr_uv = vec2(1., 0.);
266
267 let tl_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
268 let tl_uv = vec2(1., 1.);
269
270 draw_quad([
271 Vertex::new2(bl_pos, bl_uv, color),
272 Vertex::new2(br_pos, br_uv, color),
273 Vertex::new2(tr_pos, tr_uv, color),
274 Vertex::new2(tl_pos, tl_uv, color),
275 ]);
276
277 let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
279 let bl_uv = vec2(0., 1.);
280 let br_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
281 let br_uv = vec2(0., 0.);
282
283 let tr_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
284 let tr_uv = vec2(1., 0.);
285
286 let tl_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
287 let tl_uv = vec2(1., 1.);
288
289 draw_quad([
290 Vertex::new2(bl_pos, bl_uv, color),
291 Vertex::new2(br_pos, br_uv, color),
292 Vertex::new2(tr_pos, tr_uv, color),
293 Vertex::new2(tl_pos, tl_uv, color),
294 ]);
295
296 let bl_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
298 let bl_uv = vec2(0., 1.);
299 let br_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
300 let br_uv = vec2(0., 0.);
301
302 let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
303 let tr_uv = vec2(1., 0.);
304
305 let tl_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
306 let tl_uv = vec2(1., 1.);
307
308 draw_quad([
309 Vertex::new2(bl_pos, bl_uv, color),
310 Vertex::new2(br_pos, br_uv, color),
311 Vertex::new2(tr_pos, tr_uv, color),
312 Vertex::new2(tl_pos, tl_uv, color),
313 ]);
314
315 let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
317 let bl_uv = vec2(0., 1.);
318 let br_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
319 let br_uv = vec2(0., 0.);
320
321 let tr_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
322 let tr_uv = vec2(1., 0.);
323
324 let tl_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
325 let tl_uv = vec2(1., 1.);
326
327 draw_quad([
328 Vertex::new2(bl_pos, bl_uv, color),
329 Vertex::new2(br_pos, br_uv, color),
330 Vertex::new2(tr_pos, tr_uv, color),
331 Vertex::new2(tl_pos, tl_uv, color),
332 ]);
333}
334
335pub fn draw_cube_wires(position: Vec3, size: Vec3, color: Color) {
336 let (x, y, z) = (position.x, position.y, position.z);
337 let (width, height, length) = (size.x, size.y, size.z);
338
339 draw_line_3d(
343 vec3(x - width / 2., y - height / 2., z + length / 2.),
344 vec3(x + width / 2., y - height / 2., z + length / 2.),
345 color,
346 );
347
348 draw_line_3d(
350 vec3(x + width / 2., y - height / 2., z + length / 2.),
351 vec3(x + width / 2., y + height / 2., z + length / 2.),
352 color,
353 );
354
355 draw_line_3d(
357 vec3(x + width / 2., y + height / 2., z + length / 2.),
358 vec3(x - width / 2., y + height / 2., z + length / 2.),
359 color,
360 );
361
362 draw_line_3d(
364 vec3(x - width / 2., y + height / 2., z + length / 2.),
365 vec3(x - width / 2., y - height / 2., z + length / 2.),
366 color,
367 );
368
369 draw_line_3d(
372 vec3(x - width / 2., y - height / 2., z - length / 2.),
373 vec3(x + width / 2., y - height / 2., z - length / 2.),
374 color,
375 );
376
377 draw_line_3d(
379 vec3(x + width / 2., y - height / 2., z - length / 2.),
380 vec3(x + width / 2., y + height / 2., z - length / 2.),
381 color,
382 );
383
384 draw_line_3d(
386 vec3(x + width / 2., y + height / 2., z - length / 2.),
387 vec3(x - width / 2., y + height / 2., z - length / 2.),
388 color,
389 );
390
391 draw_line_3d(
393 vec3(x - width / 2., y + height / 2., z - length / 2.),
394 vec3(x - width / 2., y - height / 2., z - length / 2.),
395 color,
396 );
397
398 draw_line_3d(
401 vec3(x - width / 2., y + height / 2., z + length / 2.),
402 vec3(x - width / 2., y + height / 2., z - length / 2.),
403 color,
404 );
405
406 draw_line_3d(
408 vec3(x + width / 2., y + height / 2., z + length / 2.),
409 vec3(x + width / 2., y + height / 2., z - length / 2.),
410 color,
411 );
412
413 draw_line_3d(
416 vec3(x - width / 2., y - height / 2., z + length / 2.),
417 vec3(x - width / 2., y - height / 2., z - length / 2.),
418 color,
419 );
420
421 draw_line_3d(
423 vec3(x + width / 2., y - height / 2., z + length / 2.),
424 vec3(x + width / 2., y - height / 2., z - length / 2.),
425 color,
426 );
427}
428
429#[derive(Debug, Clone)]
430pub struct DrawSphereParams {
431 pub rings: usize,
432 pub slices: usize,
433 pub draw_mode: DrawMode,
434}
435
436impl Default for DrawSphereParams {
437 fn default() -> DrawSphereParams {
438 DrawSphereParams {
439 rings: 16,
440 slices: 16,
441 draw_mode: DrawMode::Triangles,
442 }
443 }
444}
445
446pub fn draw_sphere(center: Vec3, radius: f32, texture: Option<&Texture2D>, color: Color) {
447 draw_sphere_ex(center, radius, texture, color, Default::default());
448}
449
450pub fn draw_sphere_wires(center: Vec3, radius: f32, texture: Option<&Texture2D>, color: Color) {
451 let params = DrawSphereParams {
452 draw_mode: DrawMode::Lines,
453 ..Default::default()
454 };
455 draw_sphere_ex(center, radius, texture, color, params);
456}
457
458pub fn draw_sphere_ex(
459 center: Vec3,
460 radius: f32,
461 texture: Option<&Texture2D>,
462 color: Color,
463 params: DrawSphereParams,
464) {
465 let context = get_context();
466
467 let rings = params.rings;
468 let slices = params.slices;
469
470 let scale = vec3(radius, radius, radius);
471
472 context.gl.texture(texture);
473 context.gl.draw_mode(params.draw_mode);
474
475 for i in 0..rings + 1 {
476 for j in 0..slices {
477 use std::f32::consts::PI;
478
479 let pi34 = PI / 2. * 3.;
480 let pi2 = PI * 2.;
481 let i = i as f32;
482 let j = j as f32;
483 let rings: f32 = rings as _;
484 let slices: f32 = slices as _;
485
486 let v1 = vec3(
487 (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).sin(),
488 (pi34 + (PI / (rings + 1.)) * i).sin(),
489 (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).cos(),
490 );
491 let uv1 = vec2(i / rings, j / slices);
492 let v2 = vec3(
493 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).sin(),
494 (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
495 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).cos(),
496 );
497 let uv2 = vec2((i + 1.) / rings, (j + 1.) / slices);
498 let v3 = vec3(
499 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * (j * pi2 / slices).sin(),
500 (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
501 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * (j * pi2 / slices).cos(),
502 );
503 let uv3 = vec2((i + 1.) / rings, j / slices);
504
505 context.gl.geometry(
506 &[
507 Vertex::new2(v1 * scale + center, uv1, color),
508 Vertex::new2(v2 * scale + center, uv2, color),
509 Vertex::new2(v3 * scale + center, uv3, color),
510 ],
511 &[0, 1, 2],
512 );
513
514 let v1 = vec3(
515 (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).sin(),
516 (pi34 + (PI / (rings + 1.)) * i).sin(),
517 (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).cos(),
518 );
519 let uv1 = vec2(i / rings, j / slices);
520 let v2 = vec3(
521 (pi34 + (PI / (rings + 1.)) * (i)).cos() * ((j + 1.) * pi2 / slices).sin(),
522 (pi34 + (PI / (rings + 1.)) * (i)).sin(),
523 (pi34 + (PI / (rings + 1.)) * (i)).cos() * ((j + 1.) * pi2 / slices).cos(),
524 );
525 let uv2 = vec2(i / rings, (j + 1.) / slices);
526 let v3 = vec3(
527 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).sin(),
528 (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
529 (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).cos(),
530 );
531 let uv3 = vec2((i + 1.) / rings, (j + 1.) / slices);
532
533 context.gl.geometry(
534 &[
535 Vertex::new2(v1 * scale + center, uv1, color),
536 Vertex::new2(v2 * scale + center, uv2, color),
537 Vertex::new2(v3 * scale + center, uv3, color),
538 ],
539 &[0, 1, 2],
540 );
541 }
542 }
543}
544
545#[derive(Debug, Clone)]
546pub struct DrawCylinderParams {
547 pub sides: usize,
548 pub draw_mode: DrawMode,
549}
550
551impl Default for DrawCylinderParams {
552 fn default() -> DrawCylinderParams {
553 DrawCylinderParams {
554 sides: 16,
555 draw_mode: DrawMode::Triangles,
556 }
557 }
558}
559
560pub fn draw_cylinder(
561 position: Vec3,
562 radius_top: f32,
563 radius_bottom: f32,
564 height: f32,
565 texture: Option<&Texture2D>,
566 color: Color,
567) {
568 draw_cylinder_ex(
569 position,
570 radius_top,
571 radius_bottom,
572 height,
573 texture,
574 color,
575 Default::default(),
576 );
577}
578
579pub fn draw_cylinder_wires(
580 position: Vec3,
581 radius_top: f32,
582 radius_bottom: f32,
583 height: f32,
584 texture: Option<&Texture2D>,
585 color: Color,
586) {
587 let params = DrawCylinderParams {
588 draw_mode: DrawMode::Lines,
589 ..Default::default()
590 };
591 draw_cylinder_ex(
592 position,
593 radius_top,
594 radius_bottom,
595 height,
596 texture,
597 color,
598 params,
599 );
600}
601
602pub fn draw_cylinder_ex(
604 position: Vec3,
605 radius_top: f32,
606 radius_bottom: f32,
607 height: f32,
608 texture: Option<&Texture2D>,
609 color: Color,
610 params: DrawCylinderParams,
611) {
612 let context = get_context();
613
614 let sides = params.sides;
615
616 context.gl.texture(texture);
617 context.gl.draw_mode(params.draw_mode);
618
619 use std::f32::consts::PI;
620 let angle_step = PI * 2.0 / sides as f32;
621 for i in 0..sides + 1 {
623 let i = i as f32;
624 let v1 = vec3(
626 (i * angle_step).sin() * radius_bottom,
627 0.0,
628 (i * angle_step).cos() * radius_bottom,
629 );
630 let v2 = vec3(
632 ((i + 1.0) * angle_step).sin() * radius_bottom,
633 0.0,
634 ((i + 1.0) * angle_step).cos() * radius_bottom,
635 );
636 let v3 = vec3(
638 ((i + 1.0) * angle_step).sin() * radius_top,
639 height,
640 ((i + 1.0) * angle_step).cos() * radius_top,
641 );
642
643 context.gl.geometry(
644 &[
645 Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
646 Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
647 Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
648 ],
649 &[0, 1, 2],
650 );
651
652 let v1 = vec3(
654 (i * angle_step).sin() * radius_top,
655 height,
656 (i * angle_step).cos() * radius_top,
657 );
658 let v2 = vec3(
660 (i * angle_step).sin() * radius_bottom,
661 0.0,
662 (i * angle_step).cos() * radius_bottom,
663 );
664 let v3 = vec3(
666 ((i + 1.0) * angle_step).sin() * radius_top,
667 height,
668 ((i + 1.0) * angle_step).cos() * radius_top,
669 );
670
671 context.gl.geometry(
672 &[
673 Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
674 Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
675 Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
676 ],
677 &[0, 1, 2],
678 );
679 }
680
681 for i in 0..sides + 1 {
683 let i = i as f32;
684 let v1 = vec3(0.0, height, 0.0);
685 let v2 = vec3(
686 (i * angle_step).sin() * radius_top,
687 height,
688 (i * angle_step).cos() * radius_top,
689 );
690 let v3 = vec3(
691 ((i + 1.0) * angle_step).sin() * radius_top,
692 height,
693 ((i + 1.0) * angle_step).cos() * radius_top,
694 );
695
696 context.gl.geometry(
697 &[
698 Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
699 Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
700 Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
701 ],
702 &[0, 1, 2],
703 );
704 }
705
706 for i in 0..sides + 1 {
708 let i = i as f32;
709 let v1 = vec3(0.0, 0.0, 0.0);
710 let v2 = vec3(
711 (i * angle_step).sin() * radius_bottom,
712 0.0,
713 (i * angle_step).cos() * radius_bottom,
714 );
715 let v3 = vec3(
716 ((i + 1.0) * angle_step).sin() * radius_bottom,
717 0.0,
718 ((i + 1.0) * angle_step).cos() * radius_bottom,
719 );
720
721 context.gl.geometry(
722 &[
723 Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
724 Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
725 Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
726 ],
727 &[0, 1, 2],
728 );
729 }
730}