Skip to content
15 changes: 13 additions & 2 deletions crates/league-primitives/src/aabb.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use super::Sphere;
use glam::{vec3, Vec3};

/// Axis-aligned bounding box
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct AABB {
pub min: Vec3,
pub max: Vec3,
}

impl AABB {
pub fn new(min: Vec3, max: Vec3) -> Self {
/// Creates a new axis-aligned bounding box from min and max corner points
pub fn from_corners(min: Vec3, max: Vec3) -> Self {
Self { min, max }
}
}
Expand All @@ -18,19 +20,28 @@ fn dist(a: &Vec3, b: &Vec3) -> f32 {
}

impl AABB {
/// Compute the center point of the axis-aligned bounding box
#[inline]
#[must_use]
pub fn center(&self) -> Vec3 {
Vec3::new(
0.5 * (self.min[0] + self.max[0]),
0.5 * (self.min[1] + self.max[1]),
0.5 * (self.min[2] + self.max[2]),
)
}

/// Compute the smallest sphere that contains this AABB
#[inline]
#[must_use]
pub fn bounding_sphere(&self) -> Sphere {
let center = self.center();
Sphere::new(center, dist(&center, &self.max))
}

pub fn from_vertex_iter(verts: impl IntoIterator<Item = Vec3>) -> Self {
/// Calculate the AABB of a set of points
#[must_use]
pub fn of_points(verts: impl IntoIterator<Item = Vec3>) -> Self {
let mut min = vec3(f32::INFINITY, f32::INFINITY, f32::INFINITY);
let mut max = vec3(f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY);
for v in verts {
Expand Down
5 changes: 4 additions & 1 deletion crates/league-primitives/src/color.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
use std::io::{self, Write};

/// Generic RGBA Color struct
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Color<T = f32> {
Expand All @@ -12,7 +13,7 @@ pub struct Color<T = f32> {

impl<T> AsRef<Color<T>> for Color<T> {
fn as_ref(&self) -> &Color<T> {
&self
self
}
}

Expand All @@ -32,6 +33,7 @@ impl Color<u8> {
Ok(())
}

#[inline]
pub fn from_reader<R: io::Read + ?Sized>(reader: &mut R) -> io::Result<Self> {
Ok(Self {
r: reader.read_u8()?,
Expand All @@ -55,6 +57,7 @@ impl Color<f32> {
Ok(())
}

#[inline]
pub fn from_reader<E: ByteOrder, R: io::Read + ?Sized>(reader: &mut R) -> io::Result<Self> {
Ok(Self {
r: reader.read_f32::<E>()?,
Expand Down
6 changes: 3 additions & 3 deletions crates/league-primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pub mod color;
mod color;
pub use color::*;

pub mod sphere;
mod sphere;
pub use sphere::*;

pub mod aabb;
mod aabb;
pub use aabb::*;
3 changes: 3 additions & 0 deletions crates/league-primitives/src/sphere.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use glam::Vec3;

/// A sphere. Origin and radius.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Sphere {
pub origin: Vec3,
Expand All @@ -9,6 +10,8 @@ pub struct Sphere {
impl Sphere {
pub const INFINITE: Sphere = Self::new(Vec3::ZERO, f32::INFINITY);

#[inline]
#[must_use]
pub const fn new(origin: Vec3, radius: f32) -> Self {
Self { origin, radius }
}
Expand Down
5 changes: 5 additions & 0 deletions crates/league-toolkit/src/core/animation/asset/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Animation assets
mod compressed;

pub use compressed::*;
Expand All @@ -15,12 +16,15 @@ use error::AssetParseError::UnknownAssetType;
use std::io;
use std::io::{Read, Seek, SeekFrom};

/// Encapsulates a .anm file
#[derive(Clone, Debug)]
pub enum AnimationAsset {
Uncompressed(Uncompressed),
Compressed(Compressed),
}

/// The type of animation asset
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum AnimationAssetType {
Uncompressed,
Compressed,
Expand All @@ -40,6 +44,7 @@ impl AnimationAsset {
}
}

/// Reads the animation magic (8 bytes), and identifies the animation asset type
pub fn identify_from_reader<R: Read + ?Sized>(
reader: &mut R,
) -> io::Result<AnimationAssetType> {
Expand Down
3 changes: 3 additions & 0 deletions crates/league-toolkit/src/core/animation/rig/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::core::animation::{joint, Joint, RigResource};
use std::collections::VecDeque;

/// Builder for [`RigResource`]
pub struct Builder {
name: String,
asset_name: String,
Expand All @@ -15,11 +16,13 @@ impl Builder {
root_joints: vec![],
}
}

pub fn with_root_joint(mut self, child: joint::Builder) -> Self {
self.add_root_joint(child);
self
}

/// Mutably add a root joint
pub fn add_root_joint(&mut self, child: joint::Builder) {
self.root_joints.push(child);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/league-toolkit/src/core/animation/rig/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Read/write .skl
mod builder;
mod read;
mod write;
pub use builder::Builder;

use super::Joint;

/// Encapsulates a .skl file
#[derive(Debug, Clone, PartialEq)]
pub struct RigResource {
flags: u16,
Expand Down
132 changes: 132 additions & 0 deletions crates/league-toolkit/src/core/mem/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! Index buffer types
use std::{fmt::Debug, io, marker::PhantomData, mem::size_of};

/// Trait to read from an index buffer, in a given format. (u16, u32)
pub trait Format {
type Item;
#[must_use]
fn get(buf: &[u8], index: usize) -> Self::Item;
}

/// Wrapper around a raw buffer of indices, supporting either u16 or u32 indices.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IndexBuffer<F: Format> {
count: usize,

buffer: Vec<u8>,

_format: PhantomData<F>,
}

impl<F: Format> Debug for IndexBuffer<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IndexBuffer")
.field("count", &self.count)
.field("stride", &self.stride())
.field("buffer (size)", &self.buffer.len())
.finish()
}
}

impl Format for u32 {
type Item = u32;
fn get(buf: &[u8], index: usize) -> u32 {
let off = index * size_of::<u32>();
u32::from_le_bytes(buf[off..off + 4].try_into().unwrap())
}
}
impl Format for u16 {
type Item = u16;
fn get(buf: &[u8], index: usize) -> u16 {
let off = index * size_of::<u16>();
u16::from_le_bytes(buf[off..off + 2].try_into().unwrap())
}
}
impl<F: Format> IndexBuffer<F> {
#[must_use]
/// Creates a new index buffer from a buffer
pub fn new(buffer: Vec<u8>) -> Self {
let stride = size_of::<F>();
if buffer.len() % stride != 0 {
panic!("Index buffer size must be a multiple of index size!");
}
Self {
count: buffer.len() / stride,
buffer,
_format: PhantomData,
}
}

/// Reads an index buffer from a reader.
///
/// # Arguments
/// * `reader` - The reader to read from.
/// * `count` - The number of indices to read.
pub fn read<R: io::Read>(reader: &mut R, count: usize) -> Result<Self, io::Error> {
let mut buffer = vec![0u8; size_of::<F>() * count];
reader.read_exact(&mut buffer)?;
Ok(Self::new(buffer))
}

#[inline(always)]
#[must_use]
/// The size in bytes of a single index.
pub fn stride(&self) -> usize {
size_of::<F>()
}

#[inline(always)]
#[must_use]
/// An iterator over the indices in the buffer.
pub fn iter(&self) -> IndexBufferIter<F> {
IndexBufferIter {
buffer: self,
counter: 0,
}
}

#[inline]
#[must_use]
/// Get an item from the buffer, at a given index.
pub fn get(&self, index: usize) -> F::Item {
F::get(&self.buffer, index)
}

#[inline(always)]
#[must_use]
/// The number of indices in the buffer.
pub fn count(&self) -> usize {
self.count
}

#[inline(always)]
#[must_use]
/// The raw underlying bytes.
pub fn as_bytes(&self) -> &[u8] {
&self.buffer
}
#[inline(always)]
#[must_use]
/// Take ownership of the underlying bytes.
pub fn into_inner(self) -> Vec<u8> {
self.buffer
}
}

pub struct IndexBufferIter<'a, F: Format> {
buffer: &'a IndexBuffer<F>,
counter: usize,
}

impl<'a, F: Format> Iterator for IndexBufferIter<'a, F> {
type Item = F::Item;

fn next(&mut self) -> Option<Self::Item> {
if self.counter >= self.buffer.count {
return None;
}
let item = F::get(self.buffer.as_bytes(), self.counter);
self.counter += 1;
Some(item)
}
}
Loading
Loading