mod cpp;
pub use cpp::PixelMode;
pub use cpp::V2d;
pub use cpp::Vi2d;
pub use cpp::Vf2d;
pub use cpp::Pixel;
pub use cpp::HWButton;
pub use cpp::Key;
pub use cpp::SpriteMode;
pub use cpp::SpriteFlip;
use std::ffi::CString;
use std::fmt;
use std::ops;
struct Binding<'a> {
app: &'a mut dyn Application
}
#[no_mangle]
extern "C" fn onUserCreate(binding: *mut cpp::c_void) -> bool {
let b = unsafe { Box::from_raw(binding as *mut Binding) };
let res = match b.app.on_user_create() {
Err(err) => {
println!("ERROR: {}", err);
false
},
Ok(_) => true
};
Box::leak(b);
res
}
#[no_mangle]
extern "C" fn onUserUpdate(binding: *mut cpp::c_void, elapsed_time: cpp::c_float) -> bool {
let b = unsafe { Box::from_raw(binding as *mut Binding) };
let res = match b.app.on_user_update(elapsed_time) {
Err(err) => {
println!("ERROR: {}", err);
false
},
Ok(_) => true
};
Box::leak(b);
res
}
#[no_mangle]
extern "C" fn onUserDestroy(binding: *mut cpp::c_void) -> bool {
let b = unsafe { Box::from_raw(binding as *mut Binding) };
match b.app.on_user_destroy() {
Err(err) => println!("ERROR: {}", err),
Ok(_) => {}
}
true
}
impl<T> cpp::V2d<T> {
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl Vi2d {
#[inline]
pub fn mag(&self) -> i32 { (self.mag2() as f32).sqrt() as i32 }
#[inline]
pub fn mag2(&self) -> i32 { self.x * self.x + self.y * self.y }
#[inline]
pub fn norm(&self) -> Self { let r = 1 / self.mag(); Self { x: self.x * r, y: self.y * r } }
#[inline]
pub fn perp(&self) -> Self { Self { x: -self.y, y: self.x } }
#[inline]
pub fn dot(&self, rhs: Vi2d) -> i32 { self.x * rhs.x + self.y * rhs.y }
#[inline]
pub fn cross(&self, rhs: Vi2d) -> i32 { self.x * rhs.y - self.y * rhs.x }
}
impl Vf2d {
#[inline]
pub fn mag(&self) -> f32 { self.mag2().sqrt() }
#[inline]
pub fn mag2(&self) -> f32 { self.x * self.x + self.y * self.y }
#[inline]
pub fn norm(&self) -> Self { let r = 1.0 / self.mag(); Self { x: self.x * r, y: self.y * r } }
#[inline]
pub fn perp(&self) -> Self { Self { x: -self.y, y: self.x } }
#[inline]
pub fn dot(&self, rhs: Vf2d) -> f32 { self.x * rhs.x + self.y * rhs.y }
#[inline]
pub fn cross(&self, rhs: Vf2d) -> f32 { self.x * rhs.y - self.y * rhs.x }
}
impl<T> From<(T, T)> for cpp::V2d<T> {
fn from(tuple: (T, T)) -> Self {
Self { x: tuple.0, y: tuple.1 }
}
}
impl<T: ops::Add<Output = T>> ops::Add for cpp::V2d<T> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self { x: self.x + other.x, y: self.y + other.y }
}
}
impl<T: ops::AddAssign> ops::AddAssign for cpp::V2d<T> {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
}
}
impl<T: ops::Sub<Output = T>> ops::Sub for cpp::V2d<T> {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self { x: self.x - other.x, y: self.y - other.y }
}
}
impl<T: ops::SubAssign> ops::SubAssign for cpp::V2d<T> {
fn sub_assign(&mut self, other: Self) {
self.x -= other.x;
self.y -= other.y;
}
}
impl<T: ops::Mul<Output = T>> ops::Mul for cpp::V2d<T> {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Self { x: self.x * other.x, y: self.y * other.y }
}
}
impl<T: ops::MulAssign> ops::MulAssign for cpp::V2d<T> {
fn mul_assign(&mut self, other: Self) {
self.x *= other.x;
self.y *= other.y;
}
}
impl<T: ops::Div<Output = T>> ops::Div for cpp::V2d<T> {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Self { x: self.x / other.x, y: self.y / other.y }
}
}
impl<T: ops::DivAssign> ops::DivAssign for cpp::V2d<T> {
fn div_assign(&mut self, other: Self) {
self.x /= other.x;
self.y /= other.y;
}
}
impl<T: fmt::Display + fmt::Debug> fmt::Display for cpp::V2d<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:?}, {:?})", self.x, self.y)
}
}
impl Pixel {
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b, a: 0xFF }
}
}
impl fmt::Display for Pixel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(R: {} G: {} B: {} A: {})", self.r, self.g, self.b, self.a)
}
}
#[derive(Debug)]
pub struct Sprite {
inner: cpp::Sprite
}
impl Sprite {
pub fn new() -> Self {
let inner = unsafe { cpp::SpriteNullConstructor() };
Self { inner }
}
pub fn with_dims(width: i32, height: i32) -> Self {
let inner = unsafe { cpp::SpriteConstructor(width, height) };
Self { inner }
}
pub fn from_image(path: &str) -> Result<Self, Error> {
let image = CString::new(path)?;
let inner = unsafe { cpp::SpriteConstructor(0, 0) };
let res = unsafe { cpp::SpriteLoadFromFile(&inner, image.as_ptr()) };
match res {
cpp::RCode::FAIL =>
Err(Error { msg: format!("Failed to load the sprite") }),
cpp::RCode::NO_FILE =>
Err(Error { msg: format!("Failed to load the sprite: No such file '{}'", path) }),
cpp::RCode::OK => {
Ok(Self { inner })
}
}
}
pub fn width(&self) -> i32 {
unsafe { cpp::SpriteWidth(&self.inner) }
}
pub fn height(&self) -> i32 {
unsafe { cpp::SpriteHeight(&self.inner) }
}
pub fn has_data(&self) -> bool {
unsafe { cpp::SpriteHasData(&self.inner) }
}
pub fn sample_mode(&self) -> SpriteMode {
unsafe { cpp::SpriteGetSampleMode(&self.inner) }
}
pub fn set_sample_mode(&mut self, mode: SpriteMode) {
unsafe { cpp::SpriteSetSampleMode(&self.inner, mode) }
}
pub fn get_pixel(&self, x: i32, y: i32) -> Pixel {
unsafe { cpp::SpriteGetPixel(&self.inner, x, y) }
}
pub fn set_pixel(&mut self, x: i32, y: i32, p: Pixel) -> bool {
unsafe { cpp::SpriteSetPixel(&self.inner, x, y, p) }
}
pub fn sample(&self, x: f32, y: f32) -> Pixel {
unsafe { cpp::SpriteSample(&self.inner, x, y) }
}
pub fn sample_bl(&self, u: f32, v: f32) -> Pixel {
unsafe { cpp::SpriteSampleBL(&self.inner, u, v) }
}
}
impl fmt::Display for Sprite {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "sprite {}x{}, mode: {:?}, has_data: {}",
self.width(), self.height(), self.sample_mode(), self.has_data())
}
}
impl Drop for Sprite {
fn drop(&mut self) {
unsafe {
cpp::SpriteDestructor(&self.inner);
}
}
}
#[derive(Debug)]
pub struct Decal {
inner: cpp::Decal,
sprite: Sprite
}
impl Decal {
pub fn new(sprite: Sprite) -> Self {
let inner = unsafe { cpp::DecalConstructor(&sprite.inner) };
Self { inner, sprite }
}
pub fn id(&self) -> i32 {
unsafe { cpp::DecalId(&self.inner) }
}
pub fn scale(&self) -> Vf2d {
unsafe { cpp::DecalScale(&self.inner) }
}
pub fn sprite(&self) -> &Sprite {
&self.sprite
}
}
impl fmt::Display for Decal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "decal id {}, scale {:?}, {}", self.id(), self.scale(), self.sprite())
}
}
impl Drop for Decal {
fn drop(&mut self) {
unsafe {
cpp::DecalDestructor(&self.inner);
}
}
}
#[derive(Clone, Debug)]
pub struct Error {
msg: String
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.msg)
}
}
impl From<std::ffi::NulError> for Error {
fn from(error: std::ffi::NulError) -> Self {
Self { msg: format!("{}", error) }
}
}
pub trait Application {
fn on_user_create(&mut self) -> Result<(), Error>;
fn on_user_update(&mut self, elapsed_time: f32) -> Result<(), Error>;
fn on_user_destroy(&mut self) -> Result<(), Error>;
}
pub fn start(
name: &str,
app: &mut dyn Application,
screen_width: i32,
screen_height: i32,
pixel_width: i32,
pixel_height: i32
) -> Result<(), Error>
{
start_with_full_screen_and_vsync(
name, app, screen_width, screen_height, pixel_width, pixel_height, false, false)
}
pub fn start_with_full_screen_and_vsync(
name: &str,
app: &mut dyn Application,
screen_width: i32,
screen_height: i32,
pixel_width: i32,
pixel_height: i32,
full_screen: bool,
vsync: bool
) -> Result<(), Error>
{
let name = CString::new(name)?;
let binding = Binding { app };
let res = unsafe {
cpp::start(
name.as_ptr(),
Box::into_raw(Box::new(binding)) as *mut cpp::c_void,
screen_width,
screen_height,
pixel_width,
pixel_height,
full_screen,
vsync
)
};
match res {
cpp::RCode::FAIL =>
Err(Error { msg: format!("Failed to start the application: FAIL") }),
cpp::RCode::NO_FILE =>
Err(Error { msg: format!("Failed to start the application: NO_FILE") }),
cpp::RCode::OK =>
Ok(())
}
}
pub fn c_rand() -> i32 {
unsafe { cpp::c_rand() }
}
pub const GREY: Pixel = Pixel::rgb(192, 192, 192);
pub const DARK_GREY: Pixel = Pixel::rgb(128, 128, 128);
pub const VERY_DARK_GREY: Pixel = Pixel::rgb(64, 64, 64);
pub const RED: Pixel = Pixel::rgb(255, 0, 0);
pub const DARK_RED: Pixel = Pixel::rgb(128, 0, 0);
pub const VERY_DARK_RED: Pixel = Pixel::rgb(64, 0, 0);
pub const YELLOW: Pixel = Pixel::rgb(255, 255, 0);
pub const DARK_YELLOW: Pixel = Pixel::rgb(128, 128, 0);
pub const VERY_DARK_YELLOW: Pixel = Pixel::rgb(64, 64, 0);
pub const GREEN: Pixel = Pixel::rgb(0, 255, 0);
pub const DARK_GREEN: Pixel = Pixel::rgb(0, 128, 0);
pub const VERY_DARK_GREEN: Pixel = Pixel::rgb(0, 64, 0);
pub const CYAN: Pixel = Pixel::rgb(0, 255, 255);
pub const DARK_CYAN: Pixel = Pixel::rgb(0, 128, 128);
pub const VERY_DARK_CYAN: Pixel = Pixel::rgb(0, 64, 64);
pub const BLUE: Pixel = Pixel::rgb(0, 0, 255);
pub const DARK_BLUE: Pixel = Pixel::rgb(0, 0, 128);
pub const VERY_DARK_BLUE: Pixel = Pixel::rgb(0, 0, 64);
pub const MAGENTA: Pixel = Pixel::rgb(255, 0, 255);
pub const DARK_MAGENTA: Pixel = Pixel::rgb(128, 0, 128);
pub const VERY_DARK_MAGENTA: Pixel = Pixel::rgb(64, 0, 64);
pub const WHITE: Pixel = Pixel::rgb(255, 255, 255);
pub const BLACK: Pixel = Pixel::rgb(0, 0, 0);
pub const BLANK: Pixel = Pixel::rgba(0, 0, 0, 0);
pub fn is_focused() -> bool {
unsafe { cpp::IsFocused() }
}
pub fn get_key(k: Key) -> HWButton {
unsafe { cpp::GetKey(k) }
}
pub fn get_mouse(b: u32) -> HWButton {
unsafe { cpp::GetMouse(b) }
}
pub fn get_mouse_x() -> i32 {
unsafe { cpp::GetMouseX() }
}
pub fn get_mouse_y() -> i32 {
unsafe { cpp::GetMouseY() }
}
pub fn get_mouse_wheel() -> i32 {
unsafe { cpp::GetMouseWheel() }
}
pub fn screen_width() -> i32 {
unsafe { cpp::ScreenWidth() }
}
pub fn screen_height() -> i32 {
unsafe { cpp::ScreenHeight() }
}
pub fn get_draw_target_width() -> i32 {
unsafe { cpp::GetDrawTargetWidth() }
}
pub fn get_draw_target_height() -> i32 {
unsafe { cpp::GetDrawTargetHeight() }
}
pub fn set_screen_size(w: i32, h: i32) {
unsafe { cpp::SetScreenSize(w, h) }
}
pub fn get_fps() -> u32 {
unsafe { cpp::GetFPS() }
}
pub fn set_draw_target(layer: u8) {
unsafe { cpp::SetDrawTarget(layer) }
}
pub fn enable_layer(layer: u8, b: bool) {
unsafe { cpp::EnableLayer(layer, b) }
}
pub fn set_layer_offset(layer: u8, x: f32, y: f32) {
unsafe { cpp::SetLayerOffset(layer, x, y) }
}
pub fn set_layer_scale(layer: u8, x: f32, y: f32) {
unsafe { cpp::SetLayerScale(layer, x, y) }
}
pub fn set_layer_tint(layer: u8, tint: Pixel) {
unsafe { cpp::SetLayerTint(layer, tint) }
}
pub fn create_layer() -> u8 {
let layer = unsafe { cpp::CreateLayer() };
layer as u8
}
pub fn set_pixel_mode(m: PixelMode) {
unsafe { cpp::SetPixelMode(m) }
}
pub fn get_pixel_mode() -> PixelMode {
unsafe { cpp::GetPixelMode() }
}
pub fn set_pixel_blend(blend: f32) {
unsafe { cpp::SetPixelBlend(blend) }
}
pub fn draw(x: i32, y: i32, p: Pixel) -> bool {
unsafe { cpp::Draw(x, y, p) }
}
#[inline]
pub fn draw_line(x1: i32, y1: i32, x2: i32, y2: i32, p: Pixel) {
draw_line_with_pattern(x1, y1, x2, y2, p, 0xFFFFFFFF)
}
pub fn draw_line_with_pattern(x1: i32, y1: i32, x2: i32, y2: i32, p: Pixel, pattern: u32) {
unsafe { cpp::DrawLine(x1, y1, x2, y2, p, pattern) }
}
#[inline]
pub fn draw_circle(x: i32, y: i32, radius: i32, p: Pixel) {
draw_circle_with_mask(x, y, radius, p, 0xFF)
}
pub fn draw_circle_with_mask(x: i32, y: i32, radius: i32, p: Pixel, mask: u8) {
unsafe { cpp::DrawCircle(x, y, radius, p, mask) }
}
pub fn fill_circle(x: i32, y: i32, radius: i32, p: Pixel) {
unsafe { cpp::FillCircle(x, y, radius, p) }
}
pub fn draw_rect(x: i32, y: i32, w: i32, h: i32, p: Pixel) {
unsafe { cpp::DrawRect(x, y, w, h, p) }
}
pub fn fill_rect(x: i32, y: i32, w: i32, h: i32, p: Pixel) {
unsafe { cpp::FillRect(x, y, w, h, p) }
}
pub fn draw_triangle(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32, p: Pixel) {
unsafe { cpp::DrawTriangle(x1, y1, x2, y2, x3, y3, p) }
}
pub fn fill_triangle(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32, p: Pixel) {
unsafe { cpp::FillTriangle(x1, y1, x2, y2, x3, y3, p) }
}
#[inline]
pub fn draw_sprite(x: i32, y: i32, sprite: &Sprite) {
draw_sprite_ext(x, y, sprite, 1, SpriteFlip::NONE)
}
pub fn draw_sprite_ext(x: i32, y: i32, sprite: &Sprite, scale: u32, flip: SpriteFlip) {
unsafe { cpp::DrawSprite(x, y, &sprite.inner, scale, flip) }
}
#[inline]
pub fn draw_partial_sprite(x: i32, y: i32, sprite: &Sprite, ox: i32, oy: i32, w: i32, h: i32) {
draw_partial_sprite_ext(x, y, sprite, ox, oy, w, h, 1, SpriteFlip::NONE)
}
pub fn draw_partial_sprite_ext(x: i32, y: i32, sprite: &Sprite, ox: i32, oy: i32, w: i32, h: i32, scale: u32, flip: SpriteFlip) {
unsafe { cpp::DrawPartialSprite(x, y, &sprite.inner, ox, oy, w, h, scale, flip) }
}
#[inline]
pub fn draw_decal(pos: &Vf2d, decal: &Decal) {
draw_decal_ext(pos, decal, &Vf2d::new(1.0, 1.0), &WHITE)
}
pub fn draw_decal_ext(pos: &Vf2d, decal: &Decal, scale: &Vf2d, tint: &Pixel) {
unsafe { cpp::DrawDecal(pos, &decal.inner, scale, tint) }
}
#[inline]
pub fn draw_partial_decal(pos: &Vf2d, decal: &Decal, source_pos: &Vf2d, source_size: &Vf2d) {
draw_partial_decal_ext(pos, decal, source_pos, source_size, &Vf2d::new(1.0, 1.0), &WHITE)
}
pub fn draw_partial_decal_ext(pos: &Vf2d, decal: &Decal, source_pos: &Vf2d, source_size: &Vf2d, scale: &Vf2d, tint: &Pixel) {
unsafe { cpp::DrawPartialDecal(pos, &decal.inner, source_pos, source_size, scale, tint) }
}
#[inline]
pub fn draw_warped_decal(decal: &Decal, pos: &[Vf2d]) {
draw_warped_decal_ext(decal, pos, &WHITE)
}
pub fn draw_warped_decal_ext(decal: &Decal, pos: &[Vf2d], tint: &Pixel) {
assert_eq!(pos.len(), 4, "Expected 4 positions, received {}", pos.len());
let pos_ptr = pos.as_ptr();
unsafe { cpp::DrawWarpedDecal(&decal.inner, pos_ptr, tint) }
}
#[inline]
pub fn draw_partial_warped_decal(decal: &Decal, pos: &[Vf2d], source_pos: &Vf2d, source_size: &Vf2d) {
draw_partial_warped_decal_ext(decal, pos, source_pos, source_size, &WHITE)
}
pub fn draw_partial_warped_decal_ext(decal: &Decal, pos: &[Vf2d], source_pos: &Vf2d, source_size: &Vf2d, tint: &Pixel) {
assert_eq!(pos.len(), 4, "Expected 4 positions, received {}", pos.len());
let pos_ptr = pos.as_ptr();
unsafe { cpp::DrawPartialWarpedDecal(&decal.inner, pos_ptr, source_pos, source_size, tint) }
}
#[inline]
pub fn draw_rotated_decal(pos: &Vf2d, decal: &Decal, angle: f32) {
draw_rotated_decal_ext(pos, decal, angle, &Vf2d::new(0.0, 0.0), &Vf2d::new(1.0, 1.0), &WHITE);
}
pub fn draw_rotated_decal_ext(pos: &Vf2d, decal: &Decal, angle: f32, center: &Vf2d, scale: &Vf2d, tint: &Pixel) {
unsafe { cpp::DrawRotatedDecal(pos, &decal.inner, angle, center, scale, tint) }
}
#[inline]
pub fn draw_partial_rotated_decal(pos: &Vf2d, decal: &Decal, angle: f32, center: &Vf2d, source_pos: &Vf2d, source_size: &Vf2d) {
draw_partial_rotated_decal_ext(pos, decal, angle, center, source_pos, source_size, &Vf2d::new(1.0, 1.0), &WHITE);
}
pub fn draw_partial_rotated_decal_ext(pos: &Vf2d, decal: &Decal, angle: f32, center: &Vf2d, source_pos: &Vf2d, source_size: &Vf2d, scale: &Vf2d, tint: &Pixel) {
unsafe { cpp::DrawPartialRotatedDecal(pos, &decal.inner, angle, center, source_pos, source_size, scale, tint) }
}
#[inline]
pub fn draw_string_decal(pos: &Vf2d, text: &str) -> Result<(), Error> {
draw_string_decal_ext(pos, text, WHITE, &Vf2d::new(1.0, 1.0))
}
pub fn draw_string_decal_ext(pos: &Vf2d, text: &str, col: Pixel, scale: &Vf2d) -> Result<(), Error> {
let ctext = CString::new(text)?;
unsafe { cpp::DrawStringDecal(pos, ctext.as_ptr(), col, scale) }
Ok(())
}
#[inline]
pub fn draw_string(x: i32, y: i32, text: &str, col: Pixel) -> Result<(), Error> {
draw_string_with_scale(x, y, text, col, 1)
}
pub fn draw_string_with_scale(x: i32, y: i32, text: &str, col: Pixel, scale: u32) -> Result<(), Error> {
let ctext = CString::new(text)?;
unsafe { cpp::DrawString(x, y, ctext.as_ptr(), col, scale) }
Ok(())
}
pub fn clear(p: Pixel) {
unsafe { cpp::Clear(p) }
}
pub fn clear_buffer(p: Pixel, depth: bool) {
unsafe { cpp::ClearBuffer(p, depth) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pixel_display() {
let p = Pixel::rgba(1, 2, 3, 4);
assert_eq!(&format!("{}", p), "(R: 1 G: 2 B: 3 A: 4)");
}
#[test]
fn test_vi2d_create() {
let a = Vi2d { x: 1, y: 2 };
let b: Vi2d = (1i32, 2i32).into();
let c = Vi2d::new(1, 2);
assert_eq!(a, b);
assert_eq!(a, c);
}
#[test]
fn test_vi2d_display() {
let a = Vi2d::new(2, 3);
assert_eq!(&format!("{}", a), "(2, 3)");
}
#[test]
fn test_vi2d_add() {
let mut res = Vi2d::new(1, 2) + Vi2d::new(3, 4);
assert_eq!(res, Vi2d::new(4, 6));
res += Vi2d::new(1, 1);
assert_eq!(res, Vi2d::new(5, 7));
}
#[test]
fn test_vi2d_sub() {
let mut res = Vi2d::new(4, 5) - Vi2d::new(3, 4);
assert_eq!(res, Vi2d::new(1, 1));
res -= Vi2d::new(1, 1);
assert_eq!(res, Vi2d::new(0, 0));
}
#[test]
fn test_vi2d_mul() {
let mut res = Vi2d::new(4, 5) * Vi2d::new(3, 4);
assert_eq!(res, Vi2d::new(12, 20));
res *= Vi2d::new(2, 3);
assert_eq!(res, Vi2d::new(24, 60));
}
#[test]
fn test_vi2d_div() {
let mut res = Vi2d::new(8, 6) / Vi2d::new(2, 3);
assert_eq!(res, Vi2d::new(4, 2));
res /= Vi2d::new(2, 2);
assert_eq!(res, Vi2d::new(2, 1));
}
#[test]
fn test_vf2d_create() {
let a = Vf2d { x: 1.0, y: 2.0 };
let b: Vf2d = (1.0f32, 2.0f32).into();
let c = Vf2d::new(1.0, 2.0);
assert_eq!(a, b);
assert_eq!(a, c);
}
#[test]
fn test_vf2d_display() {
let a = Vf2d::new(2.0, 3.0);
assert_eq!(&format!("{}", a), "(2.0, 3.0)");
let a = Vf2d::new(2.1, 3.1);
assert_eq!(&format!("{}", a), "(2.1, 3.1)");
}
#[test]
fn test_vf2d_add() {
let mut res = Vf2d::new(1.0, 2.0) + Vf2d::new(3.0, 4.0);
assert_eq!(res, Vf2d::new(4.0, 6.0));
res += Vf2d::new(1.0, 1.0);
assert_eq!(res, Vf2d::new(5.0, 7.0));
}
#[test]
fn test_vf2d_sub() {
let mut res = Vf2d::new(4.0, 5.0) - Vf2d::new(3.0, 4.0);
assert_eq!(res, Vf2d::new(1.0, 1.0));
res -= Vf2d::new(1.0, 1.0);
assert_eq!(res, Vf2d::new(0.0, 0.0));
}
#[test]
fn test_vf2d_mul() {
let mut res = Vf2d::new(4.0, 5.0) * Vf2d::new(3.0, 4.0);
assert_eq!(res, Vf2d::new(12.0, 20.0));
res *= Vf2d::new(2.0, 3.0);
assert_eq!(res, Vf2d::new(24.0, 60.0));
}
#[test]
fn test_vf2d_div() {
let mut res = Vf2d::new(8.0, 6.0) / Vf2d::new(2.0, 3.0);
assert_eq!(res, Vf2d::new(4.0, 2.0));
res /= Vf2d::new(2.0, 2.0);
assert_eq!(res, Vf2d::new(2.0, 1.0));
}
}