nsys-gl-utils 0.11.4

OpenGL and graphics utilities
Documentation
use std;
use crate::{math, vertex};
use super::*;

/// (vertex count, index count)
#[inline]
pub fn lines3d_vertex_index_counts (
  latitude_divisions : u16, longitude_divisions : u16
) -> (u32, u32) {
  let latitude_divisions  = latitude_divisions  as u32;
  let longitude_divisions = longitude_divisions as u32;
  (
    1 + latitude_divisions  * longitude_divisions,  // vertex count
    4 * longitude_divisions * latitude_divisions    // index count
  )
}

impl Lines3d {
  /// Generates a hemisphere with unit radius in the positive Z half-space
  /// with a number of parallels equal to `latitude_divisions` and a number of
  /// half-meridians equal to `longitude_divisions`
  pub fn hemisphere (
    index_offset : u32, latitude_divisions : u16, longitude_divisions : u16
  ) -> Self {
    use std::f32::consts::PI;
    assert!(1 <= latitude_divisions);
    assert!(2 <= longitude_divisions);
    let (num_vertices, num_indices) =
      lines3d_vertex_index_counts (latitude_divisions, longitude_divisions);
    let latitude_divisions  = latitude_divisions  as u32;
    let longitude_divisions = longitude_divisions as u32;
    let num_parallels       = latitude_divisions;
    let num_meridians       = longitude_divisions;
    let latitude_angle      = 0.5 * (PI / latitude_divisions  as f32);
    let longitude_angle     = 2.0 * (PI / longitude_divisions as f32);
    let mut vertices
      = Vec::<vertex::Vert3dInstanced>::with_capacity (num_vertices as usize);

    // the "north pole"
    vertices.push (vertex::Vert3dInstanced {
      inst_position: math::Vector3::unit_z().into_array()
    });

    // for each parallel, generate a vertex for each meridian
    for i in 0..num_parallels {
      let i = i as f32 + 1.0;
      let v = *math::Rotation3::from_angle_x (math::Rad (i * latitude_angle))
        * math::Vector3::unit_z();
      for j in 0..num_meridians {
        let j = j as f32;
        let w =
          *math::Rotation3::from_angle_z (math::Rad (j * longitude_angle)) * v;
        // each meridian for this parallel
        vertices.push (vertex::Vert3dInstanced { inst_position: w.into_array() });
      }
    }
    debug_assert_eq!(vertices.len(), num_vertices as usize);

    let mut indices  = Vec::<u32>::with_capacity (num_indices as usize);
    // connect north pole to first parallel
    for i in 0..num_meridians {
      indices.push (index_offset + 0);
      indices.push (index_offset + 1 + i);
    }
    // connect each parallel with itself and the next parallel along the meridians
    for i in 0..num_parallels {
      let parallel_base_index = index_offset + 1 + i * num_meridians;
      for j in 0..num_meridians {
        indices.push (parallel_base_index + j);
        indices.push (parallel_base_index + (j + 1) % num_meridians);
        // only connect to the next parallel if this is not the *last* parallel
        if i < num_parallels-1 {
          indices.push (parallel_base_index + j);
          indices.push (parallel_base_index + j + num_meridians);
        }
      }
    }
    debug_assert_eq!(indices.len(), num_indices as usize);

    Lines3d { vertices, indices }
  }
}