Replace cgmath with glam in the examples (#2475)

* Replace cgmath with glam in the examples

* Implement type_for_format! for glam

* Remove comment where I'm freaking out because of OpenGL flashbacks

* Update Cargo.toml

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* Update vulkano/autogen/formats.rs

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* Fix glam type_for_format

* Format the code

---------

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
This commit is contained in:
stefnotch 2024-02-21 09:30:15 +01:00 committed by GitHub
parent 1b91d4e5a9
commit d60677b59e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 126 additions and 104 deletions

44
Cargo.lock generated
View File

@ -82,15 +82,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
[[package]]
name = "approx"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
dependencies = [
"num-traits",
]
[[package]]
name = "arrayref"
version = "0.3.7"
@ -128,7 +119,7 @@ dependencies = [
name = "async-update"
version = "0.0.0"
dependencies = [
"cgmath",
"glam",
"rand",
"vulkano",
"vulkano-shaders",
@ -334,16 +325,6 @@ dependencies = [
"libc",
]
[[package]]
name = "cgmath"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317"
dependencies = [
"approx",
"num-traits",
]
[[package]]
name = "clear-attachments"
version = "0.0.0"
@ -606,7 +587,7 @@ dependencies = [
name = "deferred"
version = "0.0.0"
dependencies = [
"cgmath",
"glam",
"vulkano",
"vulkano-shaders",
"winit 0.29.9",
@ -828,6 +809,12 @@ dependencies = [
"xml-rs",
]
[[package]]
name = "glam"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
[[package]]
name = "glium"
version = "0.32.1"
@ -1023,7 +1010,7 @@ dependencies = [
name = "interactive-fractal"
version = "0.0.0"
dependencies = [
"cgmath",
"glam",
"rand",
"vulkano",
"vulkano-shaders",
@ -1252,7 +1239,7 @@ dependencies = [
name = "multi-window-game-of-life"
version = "0.0.0"
dependencies = [
"cgmath",
"glam",
"rand",
"vulkano",
"vulkano-shaders",
@ -1388,15 +1375,6 @@ dependencies = [
"memoffset 0.7.1",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "num_enum"
version = "0.5.11"
@ -2157,7 +2135,7 @@ checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0"
name = "teapot"
version = "0.0.0"
dependencies = [
"cgmath",
"glam",
"vulkano",
"vulkano-shaders",
"winit 0.29.9",

View File

@ -57,7 +57,7 @@ vk-parse = "0.12"
winit = "0.29"
# Only used in examples
cgmath = "0.18"
glam = "0.25"
png = "0.17"
rand = "0.8"
ron = "0.8"

View File

@ -12,7 +12,7 @@ bench = false
doc = false
[dependencies]
cgmath = { workspace = true }
glam = { workspace = true }
rand = { workspace = true }
vulkano = { workspace = true, features = ["macros"] }
vulkano-shaders = { workspace = true }

View File

@ -27,7 +27,7 @@
// same data but their consistency is not strict. A replica might be out-of-date for some time
// before *reaching convergence*, hence becoming consistent, eventually.
use cgmath::{Matrix4, Rad};
use glam::f32::Mat4;
use rand::Rng;
use std::{
error::Error,
@ -659,7 +659,7 @@ fn main() -> Result<(), impl Error> {
let delta = (remainder / DURATION) as f32;
let angle = delta * std::f32::consts::PI * 2.0;
Matrix4::from_angle_z(Rad(angle)).into()
Mat4::from_rotation_z(angle).to_cols_array_2d()
},
};

View File

@ -12,7 +12,7 @@ bench = false
doc = false
[dependencies]
cgmath = { workspace = true }
glam = { workspace = true }
vulkano = { workspace = true, features = ["macros"] }
vulkano-shaders = { workspace = true }
winit = { workspace = true }

View File

@ -1,5 +1,5 @@
use super::LightingVertex;
use cgmath::Vector3;
use glam::f32::Vec3;
use std::sync::Arc;
use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
@ -168,7 +168,7 @@ impl DirectionalLightingSystem {
viewport_dimensions: [u32; 2],
color_input: Arc<ImageView>,
normals_input: Arc<ImageView>,
direction: Vector3<f32>,
direction: Vec3,
color: [f32; 3],
) -> Arc<CommandBuffer> {
let push_constants = fs::PushConstants {

View File

@ -1,5 +1,5 @@
use super::LightingVertex;
use cgmath::{Matrix4, Vector3};
use glam::f32::{Mat4, Vec3};
use std::sync::Arc;
use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
@ -178,12 +178,12 @@ impl PointLightingSystem {
color_input: Arc<ImageView>,
normals_input: Arc<ImageView>,
depth_input: Arc<ImageView>,
screen_to_world: Matrix4<f32>,
position: Vector3<f32>,
screen_to_world: Mat4,
position: Vec3,
color: [f32; 3],
) -> Arc<CommandBuffer> {
let push_constants = fs::PushConstants {
screen_to_world: screen_to_world.into(),
screen_to_world: screen_to_world.to_cols_array_2d(),
color: [color[0], color[1], color[2], 1.0],
position: position.extend(0.0).into(),
};

View File

@ -3,7 +3,7 @@ use super::{
directional_lighting_system::DirectionalLightingSystem,
point_lighting_system::PointLightingSystem,
};
use cgmath::{Matrix4, SquareMatrix, Vector3};
use glam::f32::{Mat4, Vec3};
use std::sync::Arc;
use vulkano::{
command_buffer::{
@ -258,7 +258,7 @@ impl FrameSystem {
&mut self,
before_future: F,
final_image_view: Arc<ImageView>,
world_to_framebuffer: Matrix4<f32>,
world_to_framebuffer: Mat4,
) -> Frame
where
F: GpuFuture + 'static,
@ -400,7 +400,7 @@ pub struct Frame<'a> {
// The command buffer builder that will be built during the lifetime of this object.
command_buffer_builder: Option<RecordingCommandBuffer>,
// Matrix that was passed to `frame()`.
world_to_framebuffer: Matrix4<f32>,
world_to_framebuffer: Mat4,
}
impl<'a> Frame<'a> {
@ -506,7 +506,7 @@ impl<'f, 's: 'f> DrawPass<'f, 's> {
/// Returns the 4x4 matrix that turns world coordinates into 2D coordinates on the framebuffer.
#[allow(dead_code)]
pub fn world_to_framebuffer_matrix(&self) -> Matrix4<f32> {
pub fn world_to_framebuffer_matrix(&self) -> Mat4 {
self.frame.world_to_framebuffer
}
}
@ -538,7 +538,7 @@ impl<'f, 's: 'f> LightingPass<'f, 's> {
///
/// All the objects will be colored with an intensity varying between `[0, 0, 0]` and `color`,
/// depending on the dot product of their normal and `direction`.
pub fn directional_light(&mut self, direction: Vector3<f32>, color: [f32; 3]) {
pub fn directional_light(&mut self, direction: Vec3, color: [f32; 3]) {
let command_buffer = self.frame.system.directional_lighting_system.draw(
self.frame.framebuffer.extent(),
self.frame.system.diffuse_buffer.clone(),
@ -559,14 +559,14 @@ impl<'f, 's: 'f> LightingPass<'f, 's> {
/// All the objects will be colored with an intensity varying between `[0, 0, 0]` and `color`,
/// depending on their distance with `position`. Objects that aren't facing `position` won't
/// receive any light.
pub fn point_light(&mut self, position: Vector3<f32>, color: [f32; 3]) {
pub fn point_light(&mut self, position: Vec3, color: [f32; 3]) {
let command_buffer = {
self.frame.system.point_lighting_system.draw(
self.frame.framebuffer.extent(),
self.frame.system.diffuse_buffer.clone(),
self.frame.system.normals_buffer.clone(),
self.frame.system.depth_buffer.clone(),
self.frame.world_to_framebuffer.invert().unwrap(),
self.frame.world_to_framebuffer.inverse(),
position,
color,
)

View File

@ -20,7 +20,7 @@ use crate::{
frame::{FrameSystem, Pass},
triangle_draw_system::TriangleDrawSystem,
};
use cgmath::{Matrix4, SquareMatrix, Vector3};
use glam::f32::{Mat4, Vec3};
use std::{error::Error, sync::Arc};
use vulkano::{
command_buffer::allocator::{
@ -240,7 +240,7 @@ fn main() -> Result<(), impl Error> {
let mut frame = frame_system.frame(
future,
images[image_index as usize].clone(),
Matrix4::identity(),
Mat4::IDENTITY,
);
let mut after_future = None;
while let Some(pass) = frame.next_pass() {
@ -251,11 +251,10 @@ fn main() -> Result<(), impl Error> {
}
Pass::Lighting(mut lighting) => {
lighting.ambient_light([0.1, 0.1, 0.1]);
lighting
.directional_light(Vector3::new(0.2, -0.1, -0.7), [0.6, 0.6, 0.6]);
lighting.point_light(Vector3::new(0.5, -0.5, -0.1), [1.0, 0.0, 0.0]);
lighting.point_light(Vector3::new(-0.9, 0.2, -0.15), [0.0, 1.0, 0.0]);
lighting.point_light(Vector3::new(0.0, 0.5, -0.05), [0.0, 0.0, 1.0]);
lighting.directional_light(Vec3::new(0.2, -0.1, -0.7), [0.6, 0.6, 0.6]);
lighting.point_light(Vec3::new(0.5, -0.5, -0.1), [1.0, 0.0, 0.0]);
lighting.point_light(Vec3::new(-0.9, 0.2, -0.15), [0.0, 1.0, 0.0]);
lighting.point_light(Vec3::new(0.0, 0.5, -0.05), [0.0, 0.0, 1.0]);
}
Pass::Finished(af) => {
after_future = Some(af);

View File

@ -12,7 +12,7 @@ bench = false
doc = false
[dependencies]
cgmath = { workspace = true }
glam = { workspace = true }
rand = { workspace = true }
vulkano = { workspace = true, features = ["macros"] }
vulkano-shaders = { workspace = true }

View File

@ -1,7 +1,7 @@
use crate::{
fractal_compute_pipeline::FractalComputePipeline, place_over_frame::RenderPassPlaceOverFrame,
};
use cgmath::Vector2;
use glam::f32::Vec2;
use std::{sync::Arc, time::Instant};
use vulkano::{
command_buffer::allocator::{
@ -35,11 +35,11 @@ pub struct FractalApp {
/// Toggle that stops the movement on Julia.
is_c_paused: bool,
/// C is a constant input to Julia escape time algorithm (mouse position).
c: Vector2<f32>,
c: Vec2,
/// Our zoom level.
scale: Vector2<f32>,
scale: Vec2,
/// Our translation on the complex plane.
translation: Vector2<f32>,
translation: Vec2,
/// How long the escape time algorithm should run (higher = less performance, more accurate
/// image).
pub max_iters: u32,
@ -90,9 +90,9 @@ impl FractalApp {
),
is_julia: false,
is_c_paused: false,
c: Vector2::new(0.0, 0.0),
scale: Vector2::new(4.0, 4.0),
translation: Vector2::new(0.0, 0.0),
c: Vec2::new(0.0, 0.0),
scale: Vec2::new(4.0, 4.0),
translation: Vec2::new(0.0, 0.0),
max_iters: MAX_ITERS_INIT,
time: Instant::now(),
dt: 0.0,
@ -174,16 +174,16 @@ Usage:
// Panning.
if self.input_state.pan_up {
self.translation += Vector2::new(0.0, move_speed);
self.translation += Vec2::new(0.0, move_speed);
}
if self.input_state.pan_down {
self.translation += Vector2::new(0.0, -move_speed);
self.translation += Vec2::new(0.0, -move_speed);
}
if self.input_state.pan_right {
self.translation += Vector2::new(move_speed, 0.0);
self.translation += Vec2::new(move_speed, 0.0);
}
if self.input_state.pan_left {
self.translation += Vector2::new(-move_speed, 0.0);
self.translation += Vec2::new(-move_speed, 0.0);
}
// Toggle between Julia and Mandelbrot.
@ -199,7 +199,7 @@ Usage:
// Update c.
if !self.is_c_paused {
// Scale normalized mouse pos between -1.0 and 1.0.
let mouse_pos = self.input_state.normalized_mouse_pos() * 2.0 - Vector2::new(1.0, 1.0);
let mouse_pos = self.input_state.normalized_mouse_pos() * 2.0 - Vec2::new(1.0, 1.0);
// Scale by our zoom (scale) level so when zooming in the movement on Julia is not so
// drastic.
self.c = mouse_pos * self.scale.x;
@ -268,7 +268,7 @@ struct InputState {
pub toggle_c: bool,
pub should_quit: bool,
pub scroll_delta: f32,
pub mouse_pos: Vector2<f32>,
pub mouse_pos: Vec2,
}
impl InputState {
@ -290,12 +290,12 @@ impl InputState {
toggle_c: false,
should_quit: false,
scroll_delta: 0.0,
mouse_pos: Vector2::new(0.0, 0.0),
mouse_pos: Vec2::new(0.0, 0.0),
}
}
fn normalized_mouse_pos(&self) -> Vector2<f32> {
Vector2::new(
fn normalized_mouse_pos(&self) -> Vec2 {
Vec2::new(
(self.mouse_pos.x / self.window_size[0]).clamp(0.0, 1.0),
(self.mouse_pos.y / self.window_size[1]).clamp(0.0, 1.0),
)
@ -358,7 +358,7 @@ impl InputState {
/// Update mouse position
fn on_cursor_moved_event(&mut self, pos: &PhysicalPosition<f64>) {
self.mouse_pos = Vector2::new(pos.x as f32, pos.y as f32);
self.mouse_pos = Vec2::new(pos.x as f32, pos.y as f32);
}
/// Update toggle julia state (if right mouse is clicked)

View File

@ -1,4 +1,4 @@
use cgmath::Vector2;
use glam::f32::Vec2;
use rand::Rng;
use std::sync::Arc;
use vulkano::{
@ -128,9 +128,9 @@ impl FractalComputePipeline {
pub fn compute(
&self,
image_view: Arc<ImageView>,
c: Vector2<f32>,
scale: Vector2<f32>,
translation: Vector2<f32>,
c: Vec2,
scale: Vec2,
translation: Vec2,
max_iters: u32,
is_julia: bool,
) -> Box<dyn GpuFuture> {

View File

@ -12,7 +12,7 @@ bench = false
doc = false
[dependencies]
cgmath = { workspace = true }
glam = { workspace = true }
rand = { workspace = true }
vulkano = { workspace = true, features = ["macros"] }
vulkano-shaders = { workspace = true }

View File

@ -1,5 +1,5 @@
use crate::app::App;
use cgmath::Vector2;
use glam::IVec2;
use rand::Rng;
use std::sync::Arc;
use vulkano::{
@ -114,7 +114,7 @@ impl GameOfLifeComputePipeline {
self.image.clone()
}
pub fn draw_life(&self, pos: Vector2<i32>) {
pub fn draw_life(&self, pos: IVec2) {
let mut life_in = self.life_in.write().unwrap();
let extent = self.image.image().extent();
if pos.y < 0 || pos.y >= extent[1] as i32 || pos.x < 0 || pos.x >= extent[0] as i32 {

View File

@ -13,7 +13,7 @@ mod pixels_draw;
mod render_pass;
use crate::app::{App, RenderPipeline};
use cgmath::Vector2;
use glam::{f32::Vec2, IVec2};
use std::{error::Error, time::Instant};
use vulkano_util::renderer::VulkanoWindowRenderer;
use winit::{
@ -39,7 +39,7 @@ fn main() -> Result<(), impl Error> {
// Time & inputs...
let mut time = Instant::now();
let mut cursor_pos = Vector2::new(0.0, 0.0);
let mut cursor_pos = Vec2::ZERO;
// An extremely crude way to handle input state... but works for this example.
let mut mouse_is_pressed_w1 = false;
@ -84,7 +84,7 @@ fn main() -> Result<(), impl Error> {
pub fn process_event(
event: &Event<()>,
app: &mut App,
cursor_pos: &mut Vector2<f32>,
cursor_pos: &mut Vec2,
mouse_pressed_w1: &mut bool,
mouse_pressed_w2: &mut bool,
) -> bool {
@ -109,7 +109,7 @@ pub fn process_event(
}
// Handle mouse position events.
WindowEvent::CursorMoved { position, .. } => {
*cursor_pos = Vector2::new(position.x as f32, position.y as f32)
*cursor_pos = Vec2::new(position.x as f32, position.y as f32)
}
// Handle mouse button events.
WindowEvent::MouseInput { state, button, .. } => {
@ -134,7 +134,7 @@ pub fn process_event(
fn draw_life(
app: &mut App,
cursor_pos: Vector2<f32>,
cursor_pos: Vec2,
mouse_is_pressed_w1: bool,
mouse_is_pressed_w2: bool,
) {
@ -149,7 +149,7 @@ fn draw_life(
let window_size = window.window_size();
let compute_pipeline = &mut app.pipelines.get_mut(id).unwrap().compute;
let mut normalized_pos = Vector2::new(
let mut normalized_pos = Vec2::new(
(cursor_pos.x / window_size[0]).clamp(0.0, 1.0),
(cursor_pos.y / window_size[1]).clamp(0.0, 1.0),
);
@ -157,7 +157,7 @@ fn draw_life(
// Flip y.
normalized_pos.y = 1.0 - normalized_pos.y;
let image_extent = compute_pipeline.color_image().image().extent();
compute_pipeline.draw_life(Vector2::new(
compute_pipeline.draw_life(IVec2::new(
(image_extent[0] as f32 * normalized_pos.x) as i32,
(image_extent[1] as f32 * normalized_pos.y) as i32,
))

View File

@ -12,7 +12,7 @@ bench = false
doc = false
[dependencies]
cgmath = { workspace = true }
glam = { workspace = true }
vulkano = { workspace = true, features = ["macros"] }
vulkano-shaders = { workspace = true }
winit = { workspace = true }

View File

@ -1,5 +1,8 @@
use self::model::{Normal, Position, INDICES, NORMALS, POSITIONS};
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
use glam::{
f32::{Mat3, Vec3},
Mat4,
};
use std::{error::Error, sync::Arc, time::Instant};
use vulkano::{
buffer::{
@ -311,29 +314,30 @@ fn main() -> Result<(), impl Error> {
let elapsed = rotation_start.elapsed();
let rotation =
elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
let rotation = Matrix3::from_angle_y(Rad(rotation as f32));
let rotation = Mat3::from_rotation_y(rotation as f32);
// NOTE: This teapot was meant for OpenGL where the origin is at the lower left
// instead the origin is at the upper left in Vulkan, so we reverse the Y axis.
let aspect_ratio =
swapchain.image_extent()[0] as f32 / swapchain.image_extent()[1] as f32;
let proj = cgmath::perspective(
Rad(std::f32::consts::FRAC_PI_2),
let proj = Mat4::perspective_rh_gl(
std::f32::consts::FRAC_PI_2,
aspect_ratio,
0.01,
100.0,
);
let view = Matrix4::look_at_rh(
Point3::new(0.3, 0.3, 1.0),
Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, -1.0, 0.0),
let view = Mat4::look_at_rh(
Vec3::new(0.3, 0.3, 1.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, -1.0, 0.0),
);
let scale = Matrix4::from_scale(0.01);
let scale = Mat4::from_scale(Vec3::splat(0.01));
let uniform_data = vs::Data {
world: Matrix4::from(rotation).into(),
view: (view * scale).into(),
proj: proj.into(),
world: Mat4::from_mat3(rotation).to_cols_array_2d(),
view: (view * scale).to_cols_array_2d(),
proj: proj.to_cols_array_2d(),
};
let subbuffer = uniform_buffer.allocate_sized().unwrap();

View File

@ -51,6 +51,7 @@ struct FormatMember {
type_std_array: Option<TokenStream>,
type_cgmath: Option<TokenStream>,
type_glam: Option<TokenStream>,
type_nalgebra: Option<TokenStream>,
}
@ -249,6 +250,18 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
})
},
);
let type_for_format_glam_items = members.iter().filter_map(
|FormatMember {
name,
type_std_array,
type_glam,
..
}| {
(type_glam.as_ref().or(type_std_array.as_ref())).map(|ty| {
quote! { (glam, #name) => { #ty }; }
})
},
);
let type_for_format_nalgebra_items = members.iter().filter_map(
|FormatMember {
name,
@ -561,6 +574,13 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
/// pixel = cgmath::Vector4::new(1.0f32, 0.0, 0.0, 1.0);
/// ```
///
/// For [`glam`]:
///
/// ```ignore
/// let pixel: type_for_format!(glam, R32G32B32A32_SFLOAT);
/// pixel = glam::Vec4::new(1.0f32, 0.0, 0.0, 1.0);
/// ```
///
/// For [`nalgebra`]:
///
/// ```ignore
@ -569,11 +589,13 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
/// ```
///
/// [`cgmath`]: https://crates.io/crates/cgmath
/// [`glam`]: https://crates.io/crates/glam
/// [`nalgebra`]: https://crates.io/crates/nalgebra
#[macro_export]
macro_rules! type_for_format {
#(#type_for_format_items)*
#(#type_for_format_cgmath_items)*
#(#type_for_format_glam_items)*
#(#type_for_format_nalgebra_items)*
}
}
@ -614,6 +636,7 @@ fn formats_members(
type_std_array: None,
type_cgmath: None,
type_glam: None,
type_nalgebra: None,
}
).chain(
@ -663,6 +686,7 @@ fn formats_members(
type_std_array: None,
type_cgmath: None,
type_glam: None,
type_nalgebra: None,
};
@ -777,7 +801,7 @@ fn formats_members(
_ => unreachable!(),
};
let bits = member.components[0];
let component_type = format_ident!("{}{}", prefix, bits);
let component_type: Ident = format_ident!("{}{}", prefix, bits);
let component_count = if member.components[1] == 2 * bits {
// 422 format with repeated G component
@ -809,6 +833,23 @@ fn formats_members(
member.type_cgmath = Some(quote! { cgmath::#ty<#component_type> });
}
// glam only has 2, 3 and 4-component vector types. And a limited set of component types.
if matches!(component_count, 2..=4) {
let ty = match (prefix, bits) {
("f", 32) => Some(format!("Vec{}", component_count)),
("f", 64) => Some(format!("DVec{}", component_count)),
("i", 16) => Some(format!("I16Vec{}", component_count)),
("i", 32) => Some(format!("IVec{}", component_count)),
("i", 64) => Some(format!("I64Vec{}", component_count)),
("u", 16) => Some(format!("U16Vec{}", component_count)),
("u", 32) => Some(format!("UVec{}", component_count)),
("u", 64) => Some(format!("U64Vec{}", component_count)),
_ => None,
}.map(|ty| format_ident!("{}", ty));
member.type_glam = ty.map(|ty|quote! { glam::#component_type::#ty });
}
member.type_nalgebra = Some(quote! {
nalgebra::base::SVector<#component_type, #component_count>
});