ncollide3d/procedural/
quad.rs

1use super::{IndexBuffer, TriMesh};
2use crate::math::{Point, Vector};
3use na::{self, Point2, Point3, RealField};
4
5/// Adds a double-sided quad to the scene.
6///
7/// The quad is initially centered at (0, 0, 0). Its normal is the `z` axis. The quad itself is
8/// composed of a user-defined number of triangles regularly spaced on a grid. This is the main way
9/// to draw height maps.
10///
11/// # Arguments
12/// * `w` - the quad width.
13/// * `h` - the quad height.
14/// * `usubdivs` - number of horizontal subdivisions. This correspond to the number of squares
15/// which will be placed horizontally on each line. Must not be `0`.
16/// * `vsubdivs` - number of vertical subdivisions. This correspond to the number of squares
17/// which will be placed vertically on each line. Must not be `0`.
18pub fn quad<N: RealField + Copy>(
19    width: N,
20    height: N,
21    usubdivs: usize,
22    vsubdivs: usize,
23) -> TriMesh<N> {
24    let mut quad = unit_quad(usubdivs, vsubdivs);
25
26    let mut s = Vector::zeros();
27    s[0] = width;
28    s[1] = height;
29
30    for i in 2..3 {
31        s[i] = na::one();
32    }
33
34    quad.scale_by(&s);
35
36    quad
37}
38
39/// Adds a double-sided quad with the specified grid of vertices.
40///
41/// Normals are automatically computed.
42///
43/// # Arguments
44/// * `nhpoints` - number of columns on the grid.
45/// * `nvpoints` - number of lines on the grid.
46pub fn quad_with_vertices<N: RealField + Copy>(
47    vertices: &[Point<N>],
48    nhpoints: usize,
49    nvpoints: usize,
50) -> TriMesh<N> {
51    assert!(
52        nhpoints > 1 && nvpoints > 1,
53        "The number of points must be at least 2 in each dimension."
54    );
55
56    let mut res = unit_quad(nhpoints - 1, nvpoints - 1);
57
58    for (dest, src) in res.coords.iter_mut().zip(vertices.iter()) {
59        *dest = src.clone();
60    }
61
62    res
63}
64
65/// Adds a double-sided quad with unit size to the scene.
66///
67/// The quad is initially centered at (0, 0, 0). Its normal is the `z` axis. The quad itself is
68/// composed of a user-defined number of triangles regularly spaced on a grid. This is the main way
69/// to draw height maps.
70///
71/// # Arguments
72/// * `usubdivs` - number of horizontal subdivisions. This correspond to the number of squares
73/// which will be placed horizontally on each line. Must not be `0`.
74/// * `vsubdivs` - number of vertical subdivisions. This correspond to the number of squares
75/// which will be placed vertically on each line. Must not be `0`.
76pub fn unit_quad<N: RealField + Copy>(usubdivs: usize, vsubdivs: usize) -> TriMesh<N> {
77    assert!(
78        usubdivs > 0 && vsubdivs > 0,
79        "The number of subdivisions cannot be zero"
80    );
81    assert!(3 >= 2);
82
83    let wstep = na::one::<N>() / na::convert(usubdivs as f64);
84    let hstep = na::one::<N>() / na::convert(vsubdivs as f64);
85    let cw = na::convert(0.5);
86    let ch = na::convert(0.5);
87
88    let mut vertices = Vec::new();
89    let mut normals = Vec::new();
90    let mut triangles = Vec::new();
91    let mut tex_coords = Vec::new();
92
93    // create the vertices
94    for i in 0usize..vsubdivs + 1 {
95        for j in 0usize..usubdivs + 1 {
96            let ni: N = na::convert(i as f64);
97            let nj: N = na::convert(j as f64);
98
99            let mut v = Point::origin();
100            v[0] = nj * wstep - cw;
101            v[1] = ni * hstep - ch;
102            vertices.push(v);
103            let _1 = na::one::<N>();
104            tex_coords.push(Point2::new(_1 - nj * wstep, _1 - ni * hstep))
105        }
106    }
107
108    // create the normals
109    for _ in 0..(vsubdivs + 1) * (usubdivs + 1) {
110        let mut n = Vector::zeros();
111        n[0] = na::one();
112        normals.push(n)
113    }
114
115    // create triangles
116    fn dl_triangle(i: u32, j: u32, ws: u32) -> Point3<u32> {
117        Point3::new((i + 1) * ws + j, i * ws + j, (i + 1) * ws + j + 1)
118    }
119
120    fn ur_triangle(i: u32, j: u32, ws: u32) -> Point3<u32> {
121        Point3::new(i * ws + j, i * ws + (j + 1), (i + 1) * ws + j + 1)
122    }
123
124    for i in 0usize..vsubdivs {
125        for j in 0usize..usubdivs {
126            // build two triangles...
127            triangles.push(dl_triangle(i as u32, j as u32, (usubdivs + 1) as u32));
128            triangles.push(ur_triangle(i as u32, j as u32, (usubdivs + 1) as u32));
129        }
130    }
131
132    TriMesh::new(
133        vertices,
134        Some(normals),
135        Some(tex_coords),
136        Some(IndexBuffer::Unified(triangles)),
137    )
138}