Initial commit
This commit is contained in:
commit
73943b299d
15 changed files with 801 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Cargo.lock
|
||||||
|
target/
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.background": "#551A02",
|
||||||
|
"titleBar.activeBackground": "#772503",
|
||||||
|
"titleBar.activeForeground": "#FFF9F6"
|
||||||
|
}
|
||||||
|
}
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "utilities"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["hodasemi <michaelh.95@t-online.de>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cgmath = { version = "0.18.0", features = ["swizzle"] }
|
||||||
|
rand = "0.8.5"
|
||||||
|
backtrace = "0.3.67"
|
||||||
|
assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
|
||||||
|
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||||
|
|
||||||
|
# networking
|
||||||
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
|
|
||||||
|
|
59
src/arc_unique_vec.rs
Normal file
59
src/arc_unique_vec.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Wrapper around a `Vec` if `Rc`,
|
||||||
|
/// that ensures pointer uniqueness of its elements
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct ArcUniqueVec<T> {
|
||||||
|
data: Vec<Arc<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ArcUniqueVec<T> {
|
||||||
|
/// Creates an empty `RcUniqueVec`
|
||||||
|
pub fn new() -> ArcUniqueVec<T> {
|
||||||
|
ArcUniqueVec { data: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for pointer collision while inserting.
|
||||||
|
/// Returns the index for the position of the inserted element.
|
||||||
|
pub fn insert(&mut self, element: Arc<T>) -> usize {
|
||||||
|
match self.data.iter().position(|t| Arc::ptr_eq(t, &element)) {
|
||||||
|
Some(index) => index,
|
||||||
|
None => {
|
||||||
|
let index = self.data.len();
|
||||||
|
self.data.push(element);
|
||||||
|
index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the given element is in the vector, then returns true,
|
||||||
|
/// otherwise false.
|
||||||
|
pub fn remove(&mut self, element: &Arc<T>) -> bool {
|
||||||
|
match self.data.iter().position(|t| Arc::ptr_eq(t, element)) {
|
||||||
|
Some(index) => {
|
||||||
|
self.data.remove(index);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if that element is in this `RcUniqueVec`
|
||||||
|
/// and returns its index if possible
|
||||||
|
pub fn get_index(&self, element: &Arc<T>) -> Option<usize> {
|
||||||
|
match self.data.iter().position(|t| Arc::ptr_eq(t, element)) {
|
||||||
|
Some(index) => Some(index),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears all elements from this vector
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the reference to the internal vector
|
||||||
|
pub fn as_vec(&self) -> &Vec<Arc<T>> {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
92
src/asyncthread.rs
Normal file
92
src/asyncthread.rs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//! Asynchronous thread to check if result is returned (non-blocking)
|
||||||
|
|
||||||
|
use std::sync::{mpsc, RwLock};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
/// Asynchronous thread handle
|
||||||
|
pub struct AsyncThread<T: Send + Sync + 'static> {
|
||||||
|
receiver: mpsc::Receiver<T>,
|
||||||
|
result: RwLock<Option<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send + Sync + 'static> AsyncThread<T> {
|
||||||
|
/// Spawns a thread
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// `f` is a function to be executed in a separate thread
|
||||||
|
pub fn spawn<F>(f: F) -> AsyncThread<T>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
F: Send + 'static,
|
||||||
|
{
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
if let Err(err) = sender.send((f)()) {
|
||||||
|
panic!("sending failed! ({})", err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AsyncThread {
|
||||||
|
receiver,
|
||||||
|
result: RwLock::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the thread is already returned
|
||||||
|
/// Returns the Some(result) if the thread has finished its work,
|
||||||
|
/// otherwise None
|
||||||
|
pub fn check(&self) -> Result<bool, anyhow::Error> {
|
||||||
|
let mut result = self
|
||||||
|
.result
|
||||||
|
.write()
|
||||||
|
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||||
|
|
||||||
|
match result.as_ref() {
|
||||||
|
Some(_) => Ok(true),
|
||||||
|
None => match self.receiver.try_recv() {
|
||||||
|
Ok(res) => {
|
||||||
|
*result = Some(res);
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
Err(_) => Ok(false),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// consumes the result
|
||||||
|
pub fn take(&self) -> Result<T, anyhow::Error> {
|
||||||
|
let mut result = self
|
||||||
|
.result
|
||||||
|
.write()
|
||||||
|
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||||
|
|
||||||
|
if result.is_some() {
|
||||||
|
// actually safe to not panic, since we just checked
|
||||||
|
let res = result.take().unwrap();
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::Error::msg("Asyncthread: Result not present"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send + Sync + 'static> AsyncThread<T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
pub fn get(&self) -> Result<T, anyhow::Error> {
|
||||||
|
let result = self
|
||||||
|
.result
|
||||||
|
.read()
|
||||||
|
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||||
|
|
||||||
|
match result.as_ref() {
|
||||||
|
Some(res) => Ok(res.clone()),
|
||||||
|
None => Err(anyhow::Error::msg("Asyncthread: Result not present")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
src/closures.rs
Normal file
83
src/closures.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
// !!!!!!!!!!! very unstable, use at your own risk !!!!!!!!!!!!!!!!!
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
use super::prelude::*;
|
||||||
|
use std::ops::Fn;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const void: () = ();
|
||||||
|
|
||||||
|
pub struct Callback {
|
||||||
|
function: FunctionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Callback {
|
||||||
|
pub fn new<F, Args>(function: F) -> Callback
|
||||||
|
where
|
||||||
|
F: Fn(Args) -> (),
|
||||||
|
F: 'static,
|
||||||
|
FunctionType: FunctionTypeCreator<F, Args>,
|
||||||
|
{
|
||||||
|
Callback {
|
||||||
|
function: FunctionType::new(function),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute<Args>(&self, arguments: Args)
|
||||||
|
where
|
||||||
|
FunctionType: FunctionTypeExecutorOneArg<Args>,
|
||||||
|
{
|
||||||
|
display_error!(self.function.execute(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FunctionTypeCreator<F: Fn(Args) -> () + 'static, Args> {
|
||||||
|
fn new(function: F) -> FunctionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FunctionTypeExecutorOneArg<Args> {
|
||||||
|
fn execute(&self, execute: Args) -> VerboseResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! build_function_type {
|
||||||
|
($struct_name: ident, $($ty: ty, $name: ident), *) => {
|
||||||
|
pub enum $struct_name {
|
||||||
|
$($name(Box<dyn Fn($ty)>)),*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl<F: Fn($ty) -> () + 'static> FunctionTypeCreator<F, $ty> for $struct_name {
|
||||||
|
fn new(function: F) -> FunctionType {
|
||||||
|
$struct_name::$name(Box::new(function))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionTypeExecutorOneArg<$ty> for $struct_name {
|
||||||
|
fn execute(&self, args: $ty) -> VerboseResult<()> {
|
||||||
|
match self {
|
||||||
|
FunctionType::$name(ref function) => {
|
||||||
|
(function)(args);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
create_error!("wrong argument type for this callback");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) *
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
build_function_type!(
|
||||||
|
FunctionType,
|
||||||
|
String, String,
|
||||||
|
i32, I32,
|
||||||
|
u32, U32,
|
||||||
|
f32, F32,
|
||||||
|
(), Void
|
||||||
|
);
|
167
src/color.rs
Normal file
167
src/color.rs
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::MulAssign;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::{convert::TryFrom, ops::Mul};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// `TextColor` describes the color of the text
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
|
pub enum Color {
|
||||||
|
White,
|
||||||
|
Black,
|
||||||
|
Red,
|
||||||
|
Blue,
|
||||||
|
Green,
|
||||||
|
Orange,
|
||||||
|
Yellow,
|
||||||
|
Custom(u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<[f32; 3]> for Color {
|
||||||
|
fn into(self) -> [f32; 3] {
|
||||||
|
match self {
|
||||||
|
Color::White => [1.0, 1.0, 1.0],
|
||||||
|
Color::Black => [0.0, 0.0, 0.0],
|
||||||
|
Color::Red => [1.0, 0.0, 0.0],
|
||||||
|
Color::Blue => [0.0, 0.0, 1.0],
|
||||||
|
Color::Green => [0.0, 1.0, 0.0],
|
||||||
|
Color::Orange => [1.0, 0.65, 0.0],
|
||||||
|
Color::Yellow => [1.0, 1.0, 0.0],
|
||||||
|
Color::Custom(r, g, b) => [r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<[u8; 3]> for Color {
|
||||||
|
fn into(self) -> [u8; 3] {
|
||||||
|
match self {
|
||||||
|
Color::White => [255, 255, 255],
|
||||||
|
Color::Black => [0, 0, 0],
|
||||||
|
Color::Red => [255, 0, 0],
|
||||||
|
Color::Blue => [0, 0, 255],
|
||||||
|
Color::Green => [0, 255, 0],
|
||||||
|
Color::Orange => [255, 166, 0],
|
||||||
|
Color::Yellow => [255, 255, 0],
|
||||||
|
Color::Custom(r, g, b) => [r, g, b],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Color {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
let values: [f32; 3] = self.into();
|
||||||
|
|
||||||
|
let r = (values[0] * rhs).min(1.0);
|
||||||
|
let g = (values[1] * rhs).min(1.0);
|
||||||
|
let b = (values[2] * rhs).min(1.0);
|
||||||
|
|
||||||
|
Color::from([r, g, b])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign<f32> for Color {
|
||||||
|
fn mul_assign(&mut self, rhs: f32) {
|
||||||
|
*self = *self * rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; 3]> for Color {
|
||||||
|
fn from(array: [u8; 3]) -> Self {
|
||||||
|
Self::Custom(array[0], array[1], array[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[f32; 3]> for Color {
|
||||||
|
fn from(array: [f32; 3]) -> Self {
|
||||||
|
Self::Custom(
|
||||||
|
(array[0] * 255.0).min(255.0) as u8,
|
||||||
|
(array[1] * 255.0).min(255.0) as u8,
|
||||||
|
(array[2] * 255.0).min(255.0) as u8,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Color {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(text: &str) -> Result<Color, Self::Error> {
|
||||||
|
// check if color is a hex value
|
||||||
|
if text.starts_with("#") {
|
||||||
|
let without_prefix = text.trim_start_matches("#");
|
||||||
|
|
||||||
|
if without_prefix.len() != 6 {
|
||||||
|
return Err(anyhow::Error::msg(format!(
|
||||||
|
"Hex color format has wrong format: {}",
|
||||||
|
without_prefix
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = u8::from_str_radix(&without_prefix[0..2], 16)?;
|
||||||
|
let g = u8::from_str_radix(&without_prefix[2..4], 16)?;
|
||||||
|
let b = u8::from_str_radix(&without_prefix[4..6], 16)?;
|
||||||
|
|
||||||
|
return Ok(Color::Custom(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
match text {
|
||||||
|
"white" => Ok(Color::White),
|
||||||
|
"black" => Ok(Color::Black),
|
||||||
|
"red" => Ok(Color::Red),
|
||||||
|
"blue" => Ok(Color::Blue),
|
||||||
|
"green" => Ok(Color::Green),
|
||||||
|
"orange" => Ok(Color::Orange),
|
||||||
|
"yellow" => Ok(Color::Yellow),
|
||||||
|
_ => Err(anyhow::Error::msg(format!("Unknown color: {}", text))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Color {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Color::White => write!(f, "white"),
|
||||||
|
Color::Black => write!(f, "black"),
|
||||||
|
Color::Red => write!(f, "red"),
|
||||||
|
Color::Blue => write!(f, "blue"),
|
||||||
|
Color::Green => write!(f, "green"),
|
||||||
|
Color::Orange => write!(f, "orange"),
|
||||||
|
Color::Yellow => write!(f, "yellow"),
|
||||||
|
Color::Custom(r, g, b) => write!(f, "#{:X?}{:X?}{:X?}", r, g, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Color {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::try_from(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Color {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Black
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_color_conversion() {
|
||||||
|
let color = Color::try_from("white").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(color, Color::White);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hex_color_conversion() {
|
||||||
|
let color = Color::try_from("#FFFFFF").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(color, Color::Custom(255, 255, 255));
|
||||||
|
|
||||||
|
let string = format!("{}", color);
|
||||||
|
|
||||||
|
assert_eq!(string, "#FFFFFF");
|
||||||
|
}
|
36
src/future.rs
Normal file
36
src/future.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use std::cell::{Ref, RefCell};
|
||||||
|
use std::thread::{spawn, JoinHandle};
|
||||||
|
|
||||||
|
pub struct Future<T: Send + 'static> {
|
||||||
|
thread: RefCell<Option<JoinHandle<T>>>,
|
||||||
|
data: RefCell<Option<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send + 'static> Future<T> {
|
||||||
|
pub fn new<F>(f: F) -> Future<T>
|
||||||
|
where
|
||||||
|
F: Fn() -> T,
|
||||||
|
F: Send + 'static,
|
||||||
|
{
|
||||||
|
let thread = spawn(f);
|
||||||
|
|
||||||
|
Future {
|
||||||
|
thread: RefCell::new(Some(thread)),
|
||||||
|
data: RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> Ref<'_, Option<T>> {
|
||||||
|
let mut thread_opt = self.thread.borrow_mut();
|
||||||
|
|
||||||
|
if thread_opt.is_some() {
|
||||||
|
let thread_tmp = thread_opt.take();
|
||||||
|
let thread = thread_tmp.unwrap();
|
||||||
|
if let Ok(data) = thread.join() {
|
||||||
|
self.data.replace(Some(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data.borrow()
|
||||||
|
}
|
||||||
|
}
|
142
src/helperfunctions.rs
Normal file
142
src/helperfunctions.rs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
//! Basic helper functions
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
use assetpath::AssetPath;
|
||||||
|
use cgmath;
|
||||||
|
use cgmath::One;
|
||||||
|
|
||||||
|
pub fn erase_by_ptr<T>(vector: &mut Vec<T>, object: &T) -> bool {
|
||||||
|
match vector
|
||||||
|
.iter()
|
||||||
|
.position(|t| t as *const T == object as *const T)
|
||||||
|
{
|
||||||
|
Some(i) => {
|
||||||
|
vector.remove(i);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase_arc<T: ?Sized>(vector: &mut Vec<Arc<T>>, object: &Arc<T>) -> Option<Arc<T>> {
|
||||||
|
match vector.iter().position(|t| Arc::ptr_eq(t, object)) {
|
||||||
|
Some(i) => Some(vector.remove(i)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase_rc<T: ?Sized>(vector: &mut Vec<Rc<T>>, object: &Rc<T>) -> Option<Rc<T>> {
|
||||||
|
match vector.iter().position(|t| Rc::ptr_eq(t, object)) {
|
||||||
|
Some(i) => Some(vector.remove(i)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ortho(
|
||||||
|
left: f32,
|
||||||
|
right: f32,
|
||||||
|
bottom: f32,
|
||||||
|
top: f32,
|
||||||
|
z_near: f32,
|
||||||
|
z_far: f32,
|
||||||
|
) -> cgmath::Matrix4<f32> {
|
||||||
|
let mut mat = cgmath::Matrix4::one();
|
||||||
|
|
||||||
|
mat[0][0] = 2.0 / (right - left);
|
||||||
|
mat[1][1] = -2.0 / (top - bottom);
|
||||||
|
mat[2][2] = -2.0 / (z_far - z_near);
|
||||||
|
mat[3][0] = -(right + left) / (right - left);
|
||||||
|
mat[3][1] = -(top + bottom) / (top - bottom);
|
||||||
|
mat[3][2] = -(z_far + z_near) / (z_far - z_near);
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search_dir_recursively(
|
||||||
|
base_dir: &str,
|
||||||
|
suffix: &str,
|
||||||
|
) -> Result<Vec<AssetPath>, std::io::Error> {
|
||||||
|
let mut files = Vec::new();
|
||||||
|
|
||||||
|
// simply return an empty result when the path could not be found
|
||||||
|
// or the user has a lack of permissions
|
||||||
|
let dir_content = match fs::read_dir(base_dir) {
|
||||||
|
Ok(dir) => dir,
|
||||||
|
Err(err) => match err.kind() {
|
||||||
|
ErrorKind::NotFound | ErrorKind::PermissionDenied => return Ok(files),
|
||||||
|
_ => return Err(err),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for fs_object in dir_content {
|
||||||
|
let obj = fs_object?;
|
||||||
|
|
||||||
|
let path = obj.path();
|
||||||
|
|
||||||
|
if path.is_file() {
|
||||||
|
if let Some(os_str) = path.file_name() {
|
||||||
|
if let Some(string) = os_str.to_str() {
|
||||||
|
if string.ends_with(suffix) {
|
||||||
|
files.push(AssetPath::from((base_dir, string)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(string) = path.to_str() {
|
||||||
|
let more_files = search_dir_recursively(string, suffix)?;
|
||||||
|
files.extend(more_files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(files)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn c_char_to_string(cchar: *const c_char) -> String {
|
||||||
|
CStr::from_ptr(cchar).to_str().unwrap().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> cgmath::Matrix4<f32> {
|
||||||
|
debug_assert!(z_near != 0.0);
|
||||||
|
|
||||||
|
let zero = 0.0;
|
||||||
|
let one = 1.0;
|
||||||
|
let two = 2.0;
|
||||||
|
let q = one / (fov_y / two).tan();
|
||||||
|
let a = q / aspect;
|
||||||
|
let b = (z_near + z_far) / (z_near - z_far);
|
||||||
|
let c = (two * z_near * z_far) / (z_near - z_far);
|
||||||
|
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
cgmath::Matrix4::new(
|
||||||
|
a, zero, zero, zero,
|
||||||
|
zero, -q, zero, zero,
|
||||||
|
zero, zero, b, zero - one,
|
||||||
|
zero, zero, c, zero,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn rotate_z(v: cgmath::Vector3<f32>, angle: f32) -> cgmath::Vector3<f32> {
|
||||||
|
let mut result = v;
|
||||||
|
let cos = angle.cos();
|
||||||
|
let sin = angle.sin();
|
||||||
|
|
||||||
|
result.x = v.x * cos - v.y * sin;
|
||||||
|
result.y = v.x * sin + v.y * cos;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn almost_eq(f1: f32, f2: f32) -> bool {
|
||||||
|
(f1 - f2).abs() <= std::f32::EPSILON
|
||||||
|
}
|
17
src/lib.rs
Normal file
17
src/lib.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#![deny(rust_2018_idioms)]
|
||||||
|
|
||||||
|
pub mod asyncthread;
|
||||||
|
pub mod random;
|
||||||
|
//pub mod hashvector;
|
||||||
|
pub mod color;
|
||||||
|
pub mod future;
|
||||||
|
pub mod helperfunctions;
|
||||||
|
pub mod prelude;
|
||||||
|
//pub mod closures;
|
||||||
|
|
||||||
|
pub mod try_lock_guard;
|
||||||
|
|
||||||
|
pub mod arc_unique_vec;
|
||||||
|
pub mod rc_unique_vec;
|
||||||
|
|
||||||
|
pub mod unsafe_life_time;
|
29
src/prelude.rs
Normal file
29
src/prelude.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// crates
|
||||||
|
pub use cgmath;
|
||||||
|
|
||||||
|
// functions
|
||||||
|
pub use crate::helperfunctions::*;
|
||||||
|
|
||||||
|
// async thread
|
||||||
|
pub use crate::asyncthread::AsyncThread;
|
||||||
|
|
||||||
|
pub use crate::future::Future;
|
||||||
|
|
||||||
|
// Coin
|
||||||
|
pub use crate::random::{Coin, Random};
|
||||||
|
|
||||||
|
// Unique vectors
|
||||||
|
pub use crate::arc_unique_vec::ArcUniqueVec;
|
||||||
|
pub use crate::rc_unique_vec::RcUniqueVec;
|
||||||
|
|
||||||
|
// rand crate
|
||||||
|
pub use rand;
|
||||||
|
|
||||||
|
// color
|
||||||
|
pub use crate::color::*;
|
||||||
|
|
||||||
|
// TryLockGuard
|
||||||
|
pub use crate::try_lock_guard::TryLockGuard;
|
||||||
|
|
||||||
|
// unsafe life time trickery
|
||||||
|
pub use crate::unsafe_life_time::*;
|
43
src/random.rs
Normal file
43
src/random.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
pub struct Coin;
|
||||||
|
|
||||||
|
impl Coin {
|
||||||
|
pub fn flip(probability: f32) -> bool {
|
||||||
|
if probability >= 1.0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if probability <= 0.0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let random_number = Self::raw();
|
||||||
|
|
||||||
|
probability > random_number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw() -> f32 {
|
||||||
|
rand::thread_rng().gen_range(0.0..1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Random;
|
||||||
|
|
||||||
|
impl Random {
|
||||||
|
pub fn range(low: u32, high: u32) -> u32 {
|
||||||
|
if low == high {
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
rand::thread_rng().gen_range(low..high)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn range_f32(low: f32, high: f32) -> f32 {
|
||||||
|
if low == high {
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
rand::thread_rng().gen_range(low..high)
|
||||||
|
}
|
||||||
|
}
|
59
src/rc_unique_vec.rs
Normal file
59
src/rc_unique_vec.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Wrapper around a `Vec` if `Rc`,
|
||||||
|
/// that ensures pointer uniqueness of its elements
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct RcUniqueVec<T> {
|
||||||
|
data: Vec<Rc<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RcUniqueVec<T> {
|
||||||
|
/// Creates an empty `RcUniqueVec`
|
||||||
|
pub fn new() -> RcUniqueVec<T> {
|
||||||
|
RcUniqueVec { data: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for pointer collision while inserting.
|
||||||
|
/// Returns the index for the position of the inserted element.
|
||||||
|
pub fn insert(&mut self, element: Rc<T>) -> usize {
|
||||||
|
match self.data.iter().position(|t| Rc::ptr_eq(t, &element)) {
|
||||||
|
Some(index) => index,
|
||||||
|
None => {
|
||||||
|
let index = self.data.len();
|
||||||
|
self.data.push(element);
|
||||||
|
index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the given element is in the vector, then returns true,
|
||||||
|
/// otherwise false.
|
||||||
|
pub fn remove(&mut self, element: &Rc<T>) -> bool {
|
||||||
|
match self.data.iter().position(|t| Rc::ptr_eq(t, element)) {
|
||||||
|
Some(index) => {
|
||||||
|
self.data.remove(index);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if that element is in this `RcUniqueVec`
|
||||||
|
/// and returns its index if possible
|
||||||
|
pub fn get_index(&self, element: &Rc<T>) -> Option<usize> {
|
||||||
|
match self.data.iter().position(|t| Rc::ptr_eq(t, element)) {
|
||||||
|
Some(index) => Some(index),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears all elements from this vector
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the reference to the internal vector
|
||||||
|
pub fn as_vec(&self) -> &Vec<Rc<T>> {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
41
src/try_lock_guard.rs
Normal file
41
src/try_lock_guard.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use std::sync::{LockResult, Mutex, MutexGuard, PoisonError, TryLockError};
|
||||||
|
|
||||||
|
pub enum TryLockGuard<'a, T> {
|
||||||
|
Lock(MutexGuard<'a, T>),
|
||||||
|
WouldBlock(&'a Mutex<T>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> TryLockGuard<'a, T> {
|
||||||
|
pub fn try_lock(
|
||||||
|
d: &'a Mutex<T>,
|
||||||
|
) -> Result<TryLockGuard<'a, T>, PoisonError<MutexGuard<'a, T>>> {
|
||||||
|
match d.try_lock() {
|
||||||
|
Ok(lock) => Ok(TryLockGuard::Lock(lock)),
|
||||||
|
Err(try_lock_error) => match try_lock_error {
|
||||||
|
TryLockError::Poisoned(poison_error) => Err(poison_error),
|
||||||
|
TryLockError::WouldBlock => Ok(TryLockGuard::WouldBlock(d)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn would_block(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Lock(_) => false,
|
||||||
|
Self::WouldBlock(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn guard(self) -> Option<MutexGuard<'a, T>> {
|
||||||
|
match self {
|
||||||
|
Self::Lock(guard) => Some(guard),
|
||||||
|
Self::WouldBlock(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lock(self) -> LockResult<MutexGuard<'a, T>> {
|
||||||
|
match self {
|
||||||
|
Self::Lock(guard) => Ok(guard),
|
||||||
|
Self::WouldBlock(mutex) => Ok(mutex.lock()?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/unsafe_life_time.rs
Normal file
7
src/unsafe_life_time.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
pub unsafe fn remove_life_time_mut<'a, 'b, T>(t: &'a mut T) -> &'b mut T {
|
||||||
|
std::mem::transmute(t as *mut T)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn remove_life_time<'a, 'b, T>(t: &'a T) -> &'b T {
|
||||||
|
std::mem::transmute(t as *const T)
|
||||||
|
}
|
Loading…
Reference in a new issue