///|
/// Vertex attribute types for 3D mesh data.
pub enum VertexAttribute {
  Position3 // 3 floats: x, y, z
  Normal3 // 3 floats: nx, ny, nz
  TexCoord2 // 2 floats: u, v
  Joints4 // 4 floats: joint indices
  Weights4 // 4 floats: bone weights
  Tangent4 // 4 floats: tx, ty, tz, sign
  Color4 // 4 floats: r, g, b, a
} derive(Eq, Debug)

///|
pub impl Show for VertexAttribute with output(self, logger) {
  logger.write_object(to_repr(self))
}

///|
/// Number of float components for a vertex attribute.
pub fn VertexAttribute::size(self : VertexAttribute) -> Int {
  match self {
    Position3 => 3
    Normal3 => 3
    TexCoord2 => 2
    Joints4 => 4
    Weights4 => 4
    Tangent4 => 4
    Color4 => 4
  }
}

///|
/// Describes the layout of vertex data as an ordered list of attributes.
pub struct VertexFormat {
  attributes : Array[VertexAttribute]
} derive(Debug)

///|
pub impl Show for VertexFormat with output(self, logger) {
  logger.write_object(to_repr(self))
}

///|
/// Total number of floats per vertex.
pub fn VertexFormat::stride(self : VertexFormat) -> Int {
  let mut s = 0
  for attr in self.attributes {
    s += attr.size()
  }
  s
}

///|
/// Byte offset of an attribute in the vertex layout.
/// Returns -1 if the attribute is not present.
pub fn VertexFormat::offset_of(
  self : VertexFormat,
  target : VertexAttribute,
) -> Int {
  let mut off = 0
  for attr in self.attributes {
    if attr == target {
      return off
    }
    off += attr.size()
  }
  -1
}

///|
/// Whether this format contains the given attribute.
pub fn VertexFormat::has(self : VertexFormat, target : VertexAttribute) -> Bool {
  for attr in self.attributes {
    if attr == target {
      return true
    }
  }
  false
}

///|
/// Standard 3D format: position(3) + normal(3) + uv(2) = stride 8.
pub fn VertexFormat::standard_3d() -> VertexFormat {
  { attributes: [Position3, Normal3, TexCoord2] }
}

///|
/// Skinned 3D format: position(3) + normal(3) + uv(2) + joints(4) + weights(4) = stride 16.
pub fn VertexFormat::skinned_3d() -> VertexFormat {
  { attributes: [Position3, Normal3, TexCoord2, Joints4, Weights4] }
}