104 changed files with 79 additions and 11244 deletions
-
14.gitignore
-
0Cargo.toml
-
69README.md
-
6branches/Cargo.lock
-
9branches/Cargo.toml
-
31branches/src/main.rs
-
BINfractional/.swp
-
12fractional/Cargo.toml
-
BINfractional/notes/09e-textures.pdf
-
1fractional/notes/frontier-map.url
-
7fractional/notes/html5
-
1fractional/notes/math.url
-
BINfractional/notes/polyhedra.pdf
-
BINfractional/notes/texmap.pdf
-
15fractional/notes/texture-mapping.url
-
115fractional/src/continuous.rs
-
252fractional/src/fractional.rs
-
376fractional/src/geometry.rs
-
35fractional/src/lib.rs
-
427fractional/src/main.rs
-
280fractional/src/trigonometry.rs
-
272fractional/src/xcb.rs
-
6functions/Cargo.lock
-
9functions/Cargo.toml
-
12functions/src/main.rs
-
91guessing_game/Cargo.lock
-
8guessing_game/Cargo.toml
-
36guessing_game/src/main.rs
-
6hello/Cargo.lock
-
7hello/Cargo.toml
-
3hello/src/main.rs
-
83interesting.md
-
6loops/Cargo.lock
-
9loops/Cargo.toml
-
64loops/src/main.rs
-
6ownership/Cargo.lock
-
9ownership/Cargo.toml
-
183ownership/src/main.rs
-
9rectangles/Cargo.toml
-
90rectangles/src/main.rs
-
9recursion/Cargo.toml
-
51recursion/src/main.rs
-
9restaurant/Cargo.toml
-
27restaurant/src/front_of_house.rs
-
23restaurant/src/front_of_house/hosting.rs
-
93restaurant/src/lib.rs
-
0src/easel.rs
-
0src/geometry.rs
-
0src/lib.rs
-
0src/transform.rs
-
0src/trigonometry.rs
-
0src/utils.rs
-
0src/vector.rs
-
0tests/web.rs
-
7tutorial/wasm-game-of-life/.gitignore
-
69tutorial/wasm-game-of-life/README.md
-
3tutorial/wasm-game-of-life/package-lock.json
-
520tutorial/wasm-game-of-life/src/easel.rs
-
186tutorial/wasm-game-of-life/src/transform.rs
-
139tutorial/wasm-game-of-life/src/vector.rs
-
6variables/Cargo.lock
-
9variables/Cargo.toml
-
6variables/src/main.rs
-
11wasm-game-of-life/.appveyor.yml
-
0wasm-game-of-life/.cargo-ok
-
3wasm-game-of-life/.gitignore
-
69wasm-game-of-life/.travis.yml
-
34wasm-game-of-life/Cargo.toml
-
176wasm-game-of-life/LICENSE_APACHE
-
25wasm-game-of-life/LICENSE_MIT
-
69wasm-game-of-life/README.md
-
3wasm-game-of-life/package-lock.json
-
19wasm-game-of-life/src/lib.rs
-
10wasm-game-of-life/src/utils.rs
-
13wasm-game-of-life/tests/web.rs
-
24wasm-game-of-life/www/.bin/create-wasm-app.js
-
2wasm-game-of-life/www/.gitignore
-
5wasm-game-of-life/www/.travis.yml
-
201wasm-game-of-life/www/LICENSE-APACHE
-
25wasm-game-of-life/www/LICENSE-MIT
-
67wasm-game-of-life/www/README.md
-
5wasm-game-of-life/www/bootstrap.js
-
11wasm-game-of-life/www/index.html
-
3wasm-game-of-life/www/index.js
-
5859wasm-game-of-life/www/package-lock.json
-
37wasm-game-of-life/www/package.json
-
14wasm-game-of-life/www/webpack.config.js
-
0www/.bin/create-wasm-app.js
-
0www/.gitignore
-
0www/README.md
-
0www/bootstrap.js
-
0www/index.html
-
0www/index.js
-
0www/package-lock.json
-
0www/package.json
-
0www/webpack.config.js
-
2xcb-test/.gitignore
-
11xcb-test/Cargo.toml
-
12xcb-test/Makefile
-
132xcb-test/alternatives/info.rs
@ -1,4 +1,10 @@ |
|||||
**/target |
|
||||
**/*.rs.bk |
|
||||
**/.cargo/* |
|
||||
**/Cargo.lock |
|
||||
|
# .cargo/* |
||||
|
|
||||
|
*.rs.bk |
||||
|
Cargo.lock |
||||
|
wasm-pack.log |
||||
|
|
||||
|
target/ |
||||
|
bin/ |
||||
|
pkg/ |
||||
|
wasm-pack/ |
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "branches" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "branches" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,31 +0,0 @@ |
|||||
//
|
|
||||
// Control Flow Examples
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
fn main() {
|
|
||||
let condition = true;
|
|
||||
let number = if condition {
|
|
||||
5
|
|
||||
} else {
|
|
||||
6
|
|
||||
};
|
|
||||
|
|
||||
println!("The value of number is: {}", number);
|
|
||||
}
|
|
||||
@ -1,12 +0,0 @@ |
|||||
[package] |
|
||||
name = "fractional" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
[dependencies] |
|
||||
lazy_static = "1.4.0" |
|
||||
libc = "0.2" |
|
||||
gl = "0.5.2" |
|
||||
x11 = { version = "2.3", features = ["glx"] } |
|
||||
xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] } |
|
||||
@ -1 +0,0 @@ |
|||||
http://www.jongware.com/galaxy1.html |
|
||||
@ -1,7 +0,0 @@ |
|||||
I really would like to see a HTML5 canvas as canvas for the 3D code. |
|
||||
|
|
||||
Some URLs: |
|
||||
- https://stackoverflow.com/questions/42806037/modify-canvas-from-wasm |
|
||||
- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.HtmlCanvasElement.html |
|
||||
- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.CanvasRenderingContext2d.html |
|
||||
- https://stackoverflow.com/questions/49935207/editing-canvas-pixel-data-in-webassembly-rust |
|
||||
@ -1 +0,0 @@ |
|||||
https://www.themathpage.com/Alg/reciprocals.htm |
|
||||
@ -1,15 +0,0 @@ |
|||||
https://en.wikipedia.org/wiki/Texture_mapping |
|
||||
http://www.gamers.org/dEngine/quake/papers/checker_texmap.html |
|
||||
https://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/TextureMapping.html |
|
||||
http://www.decew.net/OSS/References/chapter_2_texture_mapping.pdf |
|
||||
|
|
||||
# example affine texture mapping |
|
||||
http://archive.gamedev.net/archive/reference/articles/article852.html |
|
||||
|
|
||||
|
|
||||
http://www.lysator.liu.se/~mikaelk/doc/perspectivetexture/ |
|
||||
|
|
||||
# Shader... This also describes z-Buffer... :) |
|
||||
https://people.ece.cornell.edu/land/OldStudentProjects/cs490-95to96/GUO/report.html |
|
||||
https://software.intel.com/en-us/articles/the-basics-of-the-art-of-lighting-part-3-lighting-and-shaders/ |
|
||||
https://docs.unity3d.com/Manual/Lighting.html |
|
||||
@ -1,115 +0,0 @@ |
|||||
//
|
|
||||
// A «continued fraction» is a representation of a fraction as a vector
|
|
||||
// of integrals… Irrational fractions will result in infinite most of the
|
|
||||
// time repetitive vectors. They can be used to get a resonable approximation
|
|
||||
// for sqrt on fractionals.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use crate::Fractional;
|
|
||||
|
|
||||
#[derive(Debug)]
|
|
||||
pub struct Continuous (Vec<i64>);
|
|
||||
|
|
||||
impl Continuous {
|
|
||||
// calculate a sqrt as continued fraction sequence. Taken from:
|
|
||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#
|
|
||||
// Continued_fraction_expansion
|
|
||||
pub fn sqrt(x :i64, a0 :i64) -> Self {
|
|
||||
fn inner(v :&mut [i64], x :i64, a0 :i64, mn :i64, dn :i64, an :i64) {
|
|
||||
let mn_1 = dn * an - mn;
|
|
||||
let dn_1 = (x - mn_1 * mn_1) / dn;
|
|
||||
let an_1 = (a0 + mn_1) / dn_1;
|
|
||||
|
|
||||
v[0] = an;
|
|
||||
// The convergence criteria „an_1 == 2 * a0“ is not good for
|
|
||||
// very small x thus I decided to break the iteration at constant
|
|
||||
// time. Which is the 5 below.
|
|
||||
if v.len() > 1 {
|
|
||||
inner(&mut v[1..], x, a0, mn_1, dn_1, an_1);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
let mut v :Vec<i64> = vec!(0; 5);
|
|
||||
inner(&mut v, x, a0, 0, 1, a0);
|
|
||||
Continuous(v)
|
|
||||
}
|
|
||||
|
|
||||
// general continous fraction form of a fractional...
|
|
||||
pub fn from_prec(f :&Fractional, prec :Option<usize>) -> Self {
|
|
||||
fn inner(v :&mut Vec<i64>, f :Fractional, prec :Option<usize>) {
|
|
||||
let mut process = |prec :Option<usize>| {
|
|
||||
let Fractional(n, d) = f;
|
|
||||
let a = n / d;
|
|
||||
let Fractional(_n, _d) = f.noreduce_sub(a.into());
|
|
||||
|
|
||||
v.push(a);
|
|
||||
match _n {
|
|
||||
1 => v.push(_d),
|
|
||||
0 => {},
|
|
||||
_ => inner(v, Fractional(_d, _n), prec),
|
|
||||
}
|
|
||||
};
|
|
||||
|
|
||||
match prec {
|
|
||||
Some(0) => {},
|
|
||||
None => process(None),
|
|
||||
Some(p) => process(Some(p - 1)),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
let mut v = match prec {
|
|
||||
None => Vec::with_capacity(100),
|
|
||||
Some(p) => Vec::with_capacity(p + 1),
|
|
||||
};
|
|
||||
|
|
||||
inner(&mut v, *f, prec);
|
|
||||
Continuous(v)
|
|
||||
}
|
|
||||
|
|
||||
pub fn into_prec(&self, prec :Option<usize>) -> Fractional {
|
|
||||
let Continuous(c) = self;
|
|
||||
let p = match prec {
|
|
||||
Some(p) => if p <= c.len() { p } else { c.len() },
|
|
||||
None => c.len(),
|
|
||||
};
|
|
||||
|
|
||||
let to_frac = |acc :Fractional, x :&i64| {
|
|
||||
let Fractional(an, ad) = acc.noreduce_add((*x).into());
|
|
||||
Fractional(ad, an)
|
|
||||
};
|
|
||||
|
|
||||
let Fractional(n, d) = c[..p]
|
|
||||
. into_iter()
|
|
||||
. rev()
|
|
||||
. fold(Fractional(0, 1), to_frac);
|
|
||||
Fractional(d, n)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl From<&Fractional> for Continuous {
|
|
||||
fn from(x :&Fractional) -> Self {
|
|
||||
Self::from_prec(x, None)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Into<Fractional> for &Continuous {
|
|
||||
fn into(self) -> Fractional {
|
|
||||
(&self).into_prec(None)
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,252 +0,0 @@ |
|||||
//
|
|
||||
// Some code to support fractional numbers for full precision rational number
|
|
||||
// calculations. (At least for the standard operations.)
|
|
||||
// This also implements a sqrt on fractional numbers, which can not be precise
|
|
||||
// because of the irrational nature of most sqare roots.
|
|
||||
// Fractions can only represent rational numbers precise.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::cmp::Ordering;
|
|
||||
use std::convert::{TryFrom, TryInto};
|
|
||||
use std::fmt::{Formatter, Display};
|
|
||||
use std::num::TryFromIntError;
|
|
||||
use std::ops::{Add,Sub,Neg,Mul,Div};
|
|
||||
|
|
||||
use crate::continuous::Continuous;
|
|
||||
|
|
||||
#[derive(Debug, Eq, Clone, Copy)]
|
|
||||
pub struct Fractional (pub i64, pub i64);
|
|
||||
|
|
||||
#[inline]
|
|
||||
fn hcf(x :i64, y :i64) -> i64 {
|
|
||||
match y {
|
|
||||
0 => x,
|
|
||||
_ => hcf(y, x % y),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
pub fn from_vector(xs: &Vec<i64>) -> Vec<Fractional> {
|
|
||||
xs.iter().map(|x| Fractional(*x, 1)).collect()
|
|
||||
}
|
|
||||
|
|
||||
impl Fractional {
|
|
||||
#[inline]
|
|
||||
pub fn gcd(self, other: Self) -> i64 {
|
|
||||
let Fractional(_, d1) = self;
|
|
||||
let Fractional(_, d2) = other;
|
|
||||
(d1 * d2) / hcf(d1, d2)
|
|
||||
}
|
|
||||
|
|
||||
#[inline]
|
|
||||
pub fn reduce(self) -> Self {
|
|
||||
let Fractional(n, d) = self;
|
|
||||
let (_n, _d) = if n > d { (n, d) } else { (d, n) };
|
|
||||
|
|
||||
// if the difference from _n % _d to _n is very big we are close to
|
|
||||
// a whole number and can ignore the fractional part... this reduces
|
|
||||
// the precision but ensures smaller numbers for numerator and
|
|
||||
// denominator.
|
|
||||
if _d > 1 && (_n % _d) * 10000000 < _n {
|
|
||||
if n == _n {
|
|
||||
Self(_n / _d, 1)
|
|
||||
} else {
|
|
||||
Self(1, _n / _d)
|
|
||||
}
|
|
||||
} else {
|
|
||||
// Self(n / hcf(n, d), d / hcf(n, d))
|
|
||||
// The above reduces prcisely but results in very large numerator
|
|
||||
// or denominator occasionally. The below is less precise but
|
|
||||
// keeps the numbers small… the bad point is, that it is not very
|
|
||||
// fast.
|
|
||||
let cont = Continuous::from_prec(&self, Some(5));
|
|
||||
(&cont).into()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
pub fn noreduce_add(self, other: Self) -> Self {
|
|
||||
let Fractional(n1, d1) = self;
|
|
||||
let Fractional(n2, d2) = other;
|
|
||||
let n = n1 * (self.gcd(other) / d1) + n2 * (self.gcd(other) / d2);
|
|
||||
Self(n, self.gcd(other))
|
|
||||
}
|
|
||||
|
|
||||
pub fn noreduce_sub(self, other: Self) -> Self {
|
|
||||
self.noreduce_add(other.noreduce_neg())
|
|
||||
}
|
|
||||
|
|
||||
pub fn noreduce_neg(self) -> Self {
|
|
||||
let Fractional(n, d) = self;
|
|
||||
Self(-n, d)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl From<i64> for Fractional {
|
|
||||
fn from(x: i64) -> Self {
|
|
||||
Self(x, 1)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl From<i32> for Fractional {
|
|
||||
fn from(x: i32) -> Self {
|
|
||||
Self(x as i64, 1)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl TryFrom<usize> for Fractional {
|
|
||||
type Error = &'static str;
|
|
||||
|
|
||||
fn try_from(x: usize) -> Result<Self, Self::Error> {
|
|
||||
let v = i64::try_from(x);
|
|
||||
match v {
|
|
||||
Err(_) => Err("Conversion from usize to i32 failed"),
|
|
||||
Ok(_v) => Ok(Self(_v, 1)),
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl TryInto<f64> for Fractional {
|
|
||||
type Error = TryFromIntError;
|
|
||||
|
|
||||
fn try_into(self) -> Result<f64, Self::Error> {
|
|
||||
let n :i32 = self.0.try_into()?;
|
|
||||
let d :i32 = self.1.try_into()?;
|
|
||||
Ok(f64::from(n) / f64::from(d))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl TryInto<(i32, i32)> for Fractional {
|
|
||||
type Error = TryFromIntError;
|
|
||||
|
|
||||
fn try_into(self) -> Result<(i32, i32), Self::Error> {
|
|
||||
let a :i32 = (self.0 / self.1).try_into()?;
|
|
||||
let b :i32 = (self.0 % self.1).try_into()?;
|
|
||||
Ok((a, b))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Display for Fractional {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||
write!(f, "({}/{})", self.0, self.1)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl PartialEq for Fractional {
|
|
||||
fn eq(&self, other: &Self) -> bool {
|
|
||||
let Fractional(n1, d1) = self;
|
|
||||
let Fractional(n2, d2) = other;
|
|
||||
n1 * (self.gcd(*other) / d1) == n2 * (self.gcd(*other) / d2)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl PartialOrd for Fractional {
|
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||
Some(self.cmp(other))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Ord for Fractional {
|
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||
let Fractional(n1, d1) = self;
|
|
||||
let Fractional(n2, d2) = other;
|
|
||||
let x = n1 * (self.gcd(*other) / d1);
|
|
||||
let y = n2 * (self.gcd(*other) / d2);
|
|
||||
x.cmp(&y)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Add for Fractional {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn add(self, other: Self) -> Self {
|
|
||||
self.noreduce_add(other).reduce()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Sub for Fractional {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn sub(self, other: Self) -> Self {
|
|
||||
self + -other
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Neg for Fractional {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn neg(self) -> Self {
|
|
||||
let Fractional(n, d) = self;
|
|
||||
Self(-n, d)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Mul for Fractional {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn mul(self, other :Self) -> Self {
|
|
||||
let Fractional(n1, d1) = self;
|
|
||||
let Fractional(n2, d2) = other;
|
|
||||
Self(n1 * n2, d1 * d2).reduce()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Div for Fractional {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn div(self, other: Self) -> Self {
|
|
||||
let Fractional(n, d) = other;
|
|
||||
self * Fractional(d, n)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
/* some stuff that could be tested...
|
|
||||
let x = Fractional(1, 3);
|
|
||||
let y = Fractional(1, 6);
|
|
||||
|
|
||||
println!(
|
|
||||
"Greatest common denominator of {} and {}: {}", x, y, x.gcd(y));
|
|
||||
println!("Numerator of {}: {}", x, x.numerator());
|
|
||||
println!("Denominator of {}: {}", x, x.denominator());
|
|
||||
assert_eq!(Fractional(1, 3), Fractional(2, 6));
|
|
||||
assert_eq!(Fractional(1, 3), Fractional(1, 3));
|
|
||||
assert_eq!(y < x, true);
|
|
||||
assert_eq!(y > x, false);
|
|
||||
assert_eq!(x == y, false);
|
|
||||
assert_eq!(x == x, true);
|
|
||||
assert_eq!(x + y, Fractional(1, 2));
|
|
||||
println!("{} + {} = {}", x, y, x + y);
|
|
||||
assert_eq!(x - y, Fractional(1, 6));
|
|
||||
println!("{} - {} = {}", x, y, x - y);
|
|
||||
assert_eq!(y - x, Fractional(-1, 6));
|
|
||||
println!("{} - {} = {}", y, x, y - x);
|
|
||||
assert_eq!(-x, Fractional(-1, 3));
|
|
||||
println!("-{} = {}", x, -x);
|
|
||||
assert_eq!(x * y, Fractional(1, 18));
|
|
||||
println!("{} * {} = {}", x, y, x * y);
|
|
||||
assert_eq!(x / y, Fractional(2, 1));
|
|
||||
println!("{} / {} = {}", x, y, x / y);
|
|
||||
assert_eq!(y / x, Fractional(1, 2));
|
|
||||
println!("{} / {} = {}", y, x, y / x);
|
|
||||
|
|
||||
println!("Fractional from 3: {}", Fractional::from(3));
|
|
||||
let z :f64 = Fractional::into(x);
|
|
||||
println!("Floating point of {}: {}", x, z);
|
|
||||
let (d, r) = Fractional::into(x);
|
|
||||
println!("(div, rest) of {}: ({}, {})", x, d, r);
|
|
||||
*/
|
|
||||
|
|
||||
@ -1,376 +0,0 @@ |
|||||
//
|
|
||||
// Basic geometric things...
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::convert::{From, Into};
|
|
||||
use std::ops::{Add,Sub,Neg,Mul,Div};
|
|
||||
use std::fmt::Debug;
|
|
||||
|
|
||||
use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};
|
|
||||
use crate::transform::{TMatrix, Transformable};
|
|
||||
use crate::trigonometry::Trig;
|
|
||||
use crate::vector::Vector;
|
|
||||
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct Face<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
|
|
||||
corners :Vec<usize>,
|
|
||||
normal :Option<Vector<T>>,
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||
pub struct Point<T>(pub Vector<T>, T)
|
|
||||
where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig;
|
|
||||
|
|
||||
impl<T> Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy + From<i32> {
|
|
||||
pub fn new(x :T, y :T, z :T) -> Self {
|
|
||||
Self(Vector(x, y, z), 1.into())
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Add for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn add(self, other :Self) -> Self {
|
|
||||
let Point(v1, w1) = self;
|
|
||||
let Point(v2, w2) = other;
|
|
||||
Self(v1 + v2, w1 + w2)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Neg for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn neg(self) -> Self {
|
|
||||
let Point(v, w) = self;
|
|
||||
Self(-v, -w)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Sub for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn sub(self, other :Self) -> Self {
|
|
||||
self + -other
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Mul for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy + From<i32> {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn mul(self, other :Self) -> Self {
|
|
||||
let a :Vector<T> = self.into();
|
|
||||
let b :Vector<T> = other.into();
|
|
||||
|
|
||||
Point(a * b, 1.into())
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> From<Vector<T>> for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy + From<i32> {
|
|
||||
fn from(v :Vector<T>) -> Self {
|
|
||||
Point(v, 1.into())
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Into<Vector<T>> for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Trig + Copy + From<i32> {
|
|
||||
fn into(self) -> Vector<T> {
|
|
||||
let Point(v, w) = self;
|
|
||||
|
|
||||
if w == 0.into() {
|
|
||||
v
|
|
||||
} else {
|
|
||||
v.mul(&w.recip())
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Transformable<T> for Point<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Debug + Trig + Copy + From<i32> {
|
|
||||
fn transform(&self, m :&TMatrix<T>) -> Self {
|
|
||||
let Point(v, w) = *self;
|
|
||||
let (v, w) = m.apply(&v, w);
|
|
||||
|
|
||||
if w == 0.into() {
|
|
||||
v.into()
|
|
||||
} else {
|
|
||||
v.mul(&w.recip()).into()
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug)]
|
|
||||
pub struct Polyeder<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
|
|
||||
points :Vec<Point<T>>,
|
|
||||
faces :Vec<Face<T>>,
|
|
||||
}
|
|
||||
|
|
||||
pub trait Primitives<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
|
|
||||
fn transform(&self, m :&TMatrix<T>) -> Self;
|
|
||||
fn project( &self
|
|
||||
, camera :&Camera<T>
|
|
||||
, light :&DirectLight<T>
|
|
||||
, col :u32 ) -> Vec<(Polygon<T>, u32)>;
|
|
||||
}
|
|
||||
|
|
||||
pub struct Camera<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
|
|
||||
width :T,
|
|
||||
height :T,
|
|
||||
distance :T,
|
|
||||
project :TMatrix<T>,
|
|
||||
}
|
|
||||
|
|
||||
pub struct DirectLight<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
|
|
||||
direction: Vector<T>,
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Camera<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Debug + Copy + Trig + From<i32> {
|
|
||||
// This code assumes that the size of the viewport is always
|
|
||||
// equal to the size of the physical screen… e.g. window/canvas thus some
|
|
||||
// effects can't be done. See book for examples with different viewport
|
|
||||
// and screen sizes.
|
|
||||
pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {
|
|
||||
let width :T = (c.width() as i32).into();
|
|
||||
let height :T = (c.height() as i32).into();
|
|
||||
let d :T = 1.into();
|
|
||||
let fov = T::cot(angle) * width;
|
|
||||
let wh = width / 2.into();
|
|
||||
let hh = height / 2.into();
|
|
||||
|
|
||||
Camera { width: width
|
|
||||
, height: height
|
|
||||
, distance: d
|
|
||||
, project: TMatrix::new(
|
|
||||
( fov, 0.into(), wh, 0.into())
|
|
||||
, (0.into(), fov, hh, 0.into())
|
|
||||
, (0.into(), 0.into(), d, 1.into())
|
|
||||
, (0.into(), 0.into(), 1.into(), 0.into()) ) }
|
|
||||
}
|
|
||||
|
|
||||
pub fn get_distance(&self) -> T {
|
|
||||
self.distance
|
|
||||
}
|
|
||||
|
|
||||
pub fn get_projection(&self) -> TMatrix<T> {
|
|
||||
self.project
|
|
||||
}
|
|
||||
|
|
||||
pub fn project(&self, p :Point<T>) -> Point<T> {
|
|
||||
p.transform(&self.project)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> DirectLight<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + Trig + From<i32> {
|
|
||||
pub fn new(v :Vector<T>) -> Self {
|
|
||||
DirectLight{ direction: v }
|
|
||||
}
|
|
||||
|
|
||||
pub fn dir(&self) -> Vector<T> {
|
|
||||
self.direction
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Face<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Debug + Copy + Trig + From<i32> {
|
|
||||
fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
|
|
||||
let mut f = Face{ corners: corners, normal: None };
|
|
||||
f.update_normal(ps);
|
|
||||
f
|
|
||||
}
|
|
||||
|
|
||||
fn update_normal(&mut self, ps :&[Point<T>]) {
|
|
||||
let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
|
|
||||
let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
|
|
||||
self.normal = Some(edge10 * edge12);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Polyeder<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ PartialEq + Debug + Copy + Trig + From<i32> {
|
|
||||
fn update_normals(&mut self) {
|
|
||||
for f in self.faces.iter_mut() {
|
|
||||
f.update_normal(&self.points);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
// construct via cube, see polyhedra.pdf
|
|
||||
pub fn tetrahedron(a :T) -> Polyeder<T> {
|
|
||||
let f2 :T = 2.into();
|
|
||||
let ch = a / (f2 * T::sqrt(f2).unwrap());
|
|
||||
|
|
||||
let ps = vec!( Point::new(-ch, -ch, ch) // A
|
|
||||
, Point::new(-ch, ch, -ch) // C
|
|
||||
, Point::new( ch, -ch, -ch) // E
|
|
||||
, Point::new( ch, ch, ch) ); // G
|
|
||||
|
|
||||
// bottom: 1, 2, 3
|
|
||||
let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom
|
|
||||
, Face::new(vec!(3, 2, 0), &ps)
|
|
||||
, Face::new(vec!(0, 1, 3), &ps)
|
|
||||
, Face::new(vec!(1, 2, 3), &ps) );
|
|
||||
//let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom
|
|
||||
// , Face::new(vec!(0, 2, 3), &ps)
|
|
||||
// , Face::new(vec!(3, 1, 0), &ps)
|
|
||||
// , Face::new(vec!(3, 2, 1), &ps) );
|
|
||||
|
|
||||
Polyeder{ points: ps, faces: fs }
|
|
||||
}
|
|
||||
|
|
||||
pub fn triangle(a :T) -> Polyeder<T> {
|
|
||||
let f0 :T = 0.into();
|
|
||||
let f3 :T = 3.into();
|
|
||||
let f6 :T = 6.into();
|
|
||||
let zi :T = T::sqrt(f3).unwrap() / f6 * a;
|
|
||||
let zc :T = T::sqrt(f3).unwrap() / f3 * a;
|
|
||||
let ah :T = a / 2.into();
|
|
||||
|
|
||||
let ps = vec!( Point::new(-ah, f0, -zi)
|
|
||||
, Point::new( f0, f0, zc)
|
|
||||
, Point::new( ah, f0, -zi) );
|
|
||||
|
|
||||
let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
|
|
||||
|
|
||||
Polyeder{ points: ps, faces: fs }
|
|
||||
}
|
|
||||
|
|
||||
pub fn cube(a :T) -> Polyeder<T> {
|
|
||||
let ah :T = a / From::<i32>::from(2);
|
|
||||
|
|
||||
let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
|
|
||||
, Point::new(-ah, -ah, -ah) // 1 => front 2
|
|
||||
, Point::new( ah, -ah, -ah) // 2 => front 3
|
|
||||
, Point::new( ah, ah, -ah) // 3 => front 4
|
|
||||
, Point::new(-ah, ah, ah) // 4 => back 1
|
|
||||
, Point::new(-ah, -ah, ah) // 5 => back 2
|
|
||||
, Point::new( ah, -ah, ah) // 6 => back 3
|
|
||||
, Point::new( ah, ah, ah) ); // 7 => back 4
|
|
||||
|
|
||||
let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
|
|
||||
, Face::new(vec!(7, 6, 5, 4), &ps) // back
|
|
||||
, Face::new(vec!(1, 5, 6, 2), &ps) // top
|
|
||||
, Face::new(vec!(0, 3, 7, 4), &ps) // bottom
|
|
||||
, Face::new(vec!(0, 4, 5, 1), &ps) // left
|
|
||||
, Face::new(vec!(2, 6, 7, 3), &ps) ); // right
|
|
||||
|
|
||||
Polyeder{ points: ps, faces: fs }
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Primitives<T> for Polyeder<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + Trig + From<i32> + PartialOrd {
|
|
||||
// TODO Maybe this should also be an instance of Transformable…
|
|
||||
fn transform(&self, m :&TMatrix<T>) -> Self {
|
|
||||
let Polyeder{ points: ps, faces: fs } = self;
|
|
||||
|
|
||||
let mut p = Polyeder{
|
|
||||
points: ps.iter().map(|p| p.transform(m)).collect()
|
|
||||
, faces: fs.to_vec()
|
|
||||
};
|
|
||||
|
|
||||
// TODO alternatively we could rotate the normals too, but this cannot
|
|
||||
// done with the original matrix… the question is, what is faster.
|
|
||||
p.update_normals();
|
|
||||
p
|
|
||||
}
|
|
||||
|
|
||||
fn project( &self
|
|
||||
, camera :&Camera<T>
|
|
||||
, light :&DirectLight<T>
|
|
||||
, color :u32 ) -> Vec<(Polygon<T>, u32)> {
|
|
||||
// Helper to create a Polygon from Coordinates…
|
|
||||
// TODO probably there needs to be a Polygon constructor for this.
|
|
||||
fn polygon<I, T>(c :I) -> Polygon<T>
|
|
||||
where I: Iterator<Item = Coordinate<T>> {
|
|
||||
Polygon(Coordinates(c.collect()))
|
|
||||
}
|
|
||||
|
|
||||
// this one does the projection... as the projection was the last
|
|
||||
// matrix we do not need to do it here.
|
|
||||
let to_coord = |p :&usize| {
|
|
||||
let Point(v, _) = camera.project(self.points[*p]);
|
|
||||
Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())
|
|
||||
};
|
|
||||
let to_poly = |f :&Face<T>| {
|
|
||||
let pg = polygon(f.corners.iter().map(to_coord));
|
|
||||
let mut r :T = (((color >> 16) & 0xFF) as i32).into();
|
|
||||
let mut g :T = (((color >> 8) & 0xFF) as i32).into();
|
|
||||
let mut b :T = (((color ) & 0xFF) as i32).into();
|
|
||||
let lf :T = match f.normal {
|
|
||||
None => 1.into(),
|
|
||||
Some(n) => n.dot(light.dir())
|
|
||||
/ (n.mag() * light.dir().mag()),
|
|
||||
};
|
|
||||
|
|
||||
// this "if" represents a first simple backface culling
|
|
||||
// approach. We only return face that face towards us.
|
|
||||
if lf < 0.into() {
|
|
||||
r = r * -lf;
|
|
||||
g = g * -lf;
|
|
||||
b = b * -lf;
|
|
||||
|
|
||||
let c :u32 = (r.round() as u32) << 16
|
|
||||
| (g.round() as u32) << 8
|
|
||||
| (b.round() as u32);
|
|
||||
|
|
||||
Some((pg, c))
|
|
||||
} else {
|
|
||||
None
|
|
||||
}};
|
|
||||
|
|
||||
self.faces.iter().filter_map(to_poly).collect()
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,35 +0,0 @@ |
|||||
//
|
|
||||
// Lib for fractional calculations.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
extern crate lazy_static;
|
|
||||
|
|
||||
pub type Error = &'static str;
|
|
||||
|
|
||||
pub mod continuous;
|
|
||||
pub mod easel;
|
|
||||
pub mod fractional;
|
|
||||
pub mod transform;
|
|
||||
pub mod trigonometry;
|
|
||||
pub mod vector;
|
|
||||
pub mod xcb;
|
|
||||
pub mod geometry;
|
|
||||
|
|
||||
use fractional::Fractional;
|
|
||||
use vector::Vector;
|
|
||||
@ -1,427 +0,0 @@ |
|||||
//
|
|
||||
// Test our fractional crate / module...
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::convert::{TryFrom, TryInto, Into};
|
|
||||
use std::f64::consts::PI as FPI;
|
|
||||
use std::fmt::{Debug, Display};
|
|
||||
use std::marker::Send;
|
|
||||
use std::num::TryFromIntError;
|
|
||||
use std::ops::{Add,Sub,Neg,Mul,Div};
|
|
||||
use std::sync::mpsc;
|
|
||||
use std::thread;
|
|
||||
use std::time::{Duration, Instant};
|
|
||||
|
|
||||
use fractional::continuous::Continuous;
|
|
||||
use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
|
|
||||
, Polygon, Canvas, Fillable };
|
|
||||
use fractional::fractional::{Fractional, from_vector};
|
|
||||
use fractional::trigonometry::Trig;
|
|
||||
use fractional::vector::Vector;
|
|
||||
use fractional::transform::{TMatrix, Transformable};
|
|
||||
use fractional::xcb::XcbEasel;
|
|
||||
use fractional::geometry::{Camera, DirectLight, Polyeder, Primitives};
|
|
||||
|
|
||||
fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
|
|
||||
let r = v.iter().fold(0, |acc, x| acc + x);
|
|
||||
let l = i64::try_from(v.len())?;
|
|
||||
Ok(Fractional(r, l))
|
|
||||
}
|
|
||||
|
|
||||
fn common_fractional() {
|
|
||||
let a = vec![3, 6, 1, 9];
|
|
||||
let b = from_vector(&a);
|
|
||||
let c = mean(&a).unwrap(); // This might fail if the len of the
|
|
||||
// vector (usize) does not fit into i32.
|
|
||||
let cr :f64 = c.try_into().unwrap();
|
|
||||
|
|
||||
println!(" [i32] : {:?}", a);
|
|
||||
println!(" [Fractional] : {:?}", b);
|
|
||||
println!(" mean of [i32] : {}" , c);
|
|
||||
println!(" as f64 : {}" , cr);
|
|
||||
println!(" again as f64 : {}" , TryInto::<f64>::try_into(c).unwrap());
|
|
||||
}
|
|
||||
|
|
||||
fn continuous() {
|
|
||||
let d = Fractional(45, 16);
|
|
||||
let e = Fractional(16, 45);
|
|
||||
|
|
||||
let dc :Continuous = (&d).into();
|
|
||||
let ec :Continuous = (&e).into();
|
|
||||
|
|
||||
println!("cont frac of d : {} => {:?}", d, dc);
|
|
||||
println!("cont frac of e : {} => {:?}", e, ec);
|
|
||||
println!(" reverted dc : {:?} {}", dc, Into::<Fractional>::into(&dc));
|
|
||||
println!(" reverted ec : {:?} {}", ec, Into::<Fractional>::into(&ec));
|
|
||||
}
|
|
||||
|
|
||||
fn sqrt() {
|
|
||||
let f = Fractional(-9, 4);
|
|
||||
let fr :f64 = f.try_into().unwrap();
|
|
||||
let sq = f.sqrt();
|
|
||||
let _sq = fr.sqrt();
|
|
||||
|
|
||||
println!("{:>14} : {:?} / {}", format!("sqrt {}", f), sq, _sq);
|
|
||||
|
|
||||
for f in [ Fractional(9, 4)
|
|
||||
, Fractional(45, 16)
|
|
||||
, Fractional(16, 45)
|
|
||||
, Fractional(9, 3) ].iter() {
|
|
||||
let fr :f64 = (*f).try_into().unwrap();
|
|
||||
let sq = f.sqrt().unwrap();
|
|
||||
let sqr :f64 = sq.try_into().unwrap();
|
|
||||
let _sqr = fr.sqrt();
|
|
||||
|
|
||||
println!("{:>14} : {} {} / {}", format!("sqrt {}", f), sq, sqr, _sqr);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn pi() {
|
|
||||
let pi = Fractional::pi();
|
|
||||
let pir :f64 = pi.try_into().unwrap();
|
|
||||
let pit :(i32, i32) = pi.try_into().unwrap();
|
|
||||
let pi2r :f64 = (pi * pi).try_into().unwrap();
|
|
||||
|
|
||||
println!(" Rust π : {}" , FPI);
|
|
||||
println!(" π : {} {}" , pi, pir);
|
|
||||
println!(" π as tuple : {:?}" , pit);
|
|
||||
println!(" Rust π² : {}" , FPI * FPI);
|
|
||||
println!(" π² : {} {}" , pi * pi, pi2r);
|
|
||||
}
|
|
||||
|
|
||||
fn _sin() {
|
|
||||
for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
|
|
||||
, 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
|
|
||||
let s = Fractional::sin(*d as i32);
|
|
||||
let sr :f64 = s.try_into().unwrap();
|
|
||||
let _s = f64::sin(*d as f64 * FPI / 180.0);
|
|
||||
|
|
||||
println!("{:>14} : {} {} / {}", format!("sin {}", d), s, sr, _s);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn _tan() {
|
|
||||
for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
|
|
||||
, 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
|
|
||||
let t = Fractional::tan(*d as i32);
|
|
||||
let tr :f64 = t.try_into().unwrap();
|
|
||||
let _t = f64::tan(*d as f64 * FPI / 180.0);
|
|
||||
|
|
||||
println!("{:>14} : {} {} / {}", format!("tan {}", d), t, tr, _t);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn _cos() {
|
|
||||
for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
|
|
||||
, 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
|
|
||||
let c = Fractional::cos(*d as i32);
|
|
||||
let cr :f64 = c.try_into().unwrap();
|
|
||||
let _c = f64::cos(*d as f64 * FPI / 180.0);
|
|
||||
|
|
||||
println!("{:>14} : {} {} / {}", format!("cos {}", d), c, cr, _c);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn _vector1() {
|
|
||||
let v1 = Vector(1.into(), 2.into(), 3.into());
|
|
||||
let v2 = Vector(2.into(), 2.into(), 3.into());
|
|
||||
let s :Fractional = 3.into();
|
|
||||
|
|
||||
_vector(v1, v2, s);
|
|
||||
}
|
|
||||
|
|
||||
fn _vector2() {
|
|
||||
let v1 = Vector(1.0, 2.0, 3.0);
|
|
||||
let v2 = Vector(2.0, 2.0, 3.0);
|
|
||||
let s = 3.0;
|
|
||||
|
|
||||
_vector(v1, v2, s);
|
|
||||
}
|
|
||||
|
|
||||
fn _vector<T>(v1 :Vector<T>, v2 :Vector<T>, s :T)
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy + Display {
|
|
||||
println!("{:>14} : {}", "Vector v1", v1);
|
|
||||
println!("{:>14} : {}", "Vector v2", v2);
|
|
||||
println!("{:>14} : {}", "magnitude v1", v1.mag());
|
|
||||
println!("{:>14} : {}", "-v1", -v1);
|
|
||||
println!("{:>14} : {}", "v1 + v1", v1 + v1);
|
|
||||
println!("{:>14} : {}", "v1 - v1", v1 - v1);
|
|
||||
println!("{:>14} : {}", "v2 - v1", v2 - v1);
|
|
||||
println!("{:>14} : {}", format!("v1 * {}", s), v1.mul(&s));
|
|
||||
println!("{:>14} : {}", "norm v1", v1.norm());
|
|
||||
println!("{:>14} : {}", "magnitude norm v1", v1.norm().mag());
|
|
||||
println!("{:>14} : {}", "magnitude v1", v1.mag());
|
|
||||
println!("{:>14} : {}", "norm * magnitude", v1.norm().mul(&v1.mag()));
|
|
||||
println!("{:>14} : {}", "distance v1 v2", v1.distance(v2));
|
|
||||
println!("{:>14} : {}", "distance v2 v1", v2.distance(v1));
|
|
||||
println!("{:>14} : {}", "v1 dot v2", v1.dot(v2));
|
|
||||
println!("{:>14} : {}", "v2 dot v1", v2.dot(v1));
|
|
||||
println!("{:>14} : {}", "v1 * v2", v1 * v2);
|
|
||||
println!("{:>14} : {}", "v2 * v1", v2 * v1);
|
|
||||
}
|
|
||||
|
|
||||
fn _transform1() {
|
|
||||
let v = Vector(Fractional(1,1), Fractional(1,1), Fractional(1,1));
|
|
||||
let v1 = Vector(Fractional(1,1), Fractional(2,1), Fractional(3,1));
|
|
||||
let v2 = Vector(Fractional(1,1), Fractional(1,1), Fractional(0,1));
|
|
||||
let v3 = Vector(Fractional(1,1), Fractional(0,1), Fractional(1,1));
|
|
||||
|
|
||||
_transform(v, v1, v2, v3);
|
|
||||
}
|
|
||||
|
|
||||
fn _transform2() {
|
|
||||
let v = Vector(1.0, 1.0, 1.0);
|
|
||||
let v1 = Vector(1.0, 2.0, 3.0);
|
|
||||
let v2 = Vector(1.0, 1.0, 0.0);
|
|
||||
let v3 = Vector(1.0, 0.0, 1.0);
|
|
||||
|
|
||||
_transform(v, v1, v2, v3);
|
|
||||
}
|
|
||||
|
|
||||
fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig
|
|
||||
+ Debug + From<i32> + Copy + Display {
|
|
||||
|
|
||||
println!("{:>14} : {}", "Vector v1", v1);
|
|
||||
println!( "{:>14} : {}", "translate v1"
|
|
||||
, v.transform(&TMatrix::translate(v)));
|
|
||||
println!();
|
|
||||
|
|
||||
fn _rot<T>( o :&str , n :&str , v :&Vector<T>
|
|
||||
, fs :&[&dyn Fn(i32) -> TMatrix<T>] )
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig
|
|
||||
+ Debug + From<i32> + Copy + Display {
|
|
||||
|
|
||||
for d in [ 30, 45, 60, 90, 120, 135, 150, 180
|
|
||||
, 210, 225, 240, 270, 300, 315, 330 ].iter() {
|
|
||||
let mi = fs.iter().map(|f| f(*d as i32));
|
|
||||
println!( "{:>14} : {}"
|
|
||||
, format!("{} {} {}", o, d, n)
|
|
||||
, v.transform(&TMatrix::combine(mi)) );
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
println!("{:>14} : {}", "Vector v2", v2);
|
|
||||
_rot("rot_x", "v2", &v2, &[&TMatrix::rotate_x]);
|
|
||||
println!();
|
|
||||
_rot("rot_y", "v2", &v2, &[&TMatrix::rotate_y]);
|
|
||||
println!();
|
|
||||
_rot("rot_xy", "v2", &v2, &[&TMatrix::rotate_x, &TMatrix::rotate_y]);
|
|
||||
println!();
|
|
||||
println!("{:>14} : {}", "Vector v3", v3);
|
|
||||
_rot("rot_z", "v3", &v3, &[&TMatrix::rotate_z]);
|
|
||||
println!();
|
|
||||
|
|
||||
for d in [ 30, 45, 60, 90, 120, 135, 150, 180
|
|
||||
, 210, 225, 240, 270, 300, 315, 330 ].iter() {
|
|
||||
println!( "{:>14} : {}"
|
|
||||
, format!("rot_v {} v2", d)
|
|
||||
, v2.transform(&TMatrix::rotate_v(&v, *d as i32)) );
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn _line() {
|
|
||||
let a = (Coordinate(0, 1, 0.0), Coordinate(6, 4, 0.0));
|
|
||||
let b = (Coordinate(0, 4, 0.0), Coordinate(6, 1, 0.0));
|
|
||||
let c = (Coordinate(1, 0, 0.0), Coordinate(6, 8, 0.0));
|
|
||||
let d = (Coordinate(1, 8, 0.0), Coordinate(6, 0, 0.0));
|
|
||||
|
|
||||
for i in [a, b, c, d].iter() {
|
|
||||
println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot());
|
|
||||
println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot());
|
|
||||
}
|
|
||||
|
|
||||
println!();
|
|
||||
let pl = Polyline(
|
|
||||
Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1)));
|
|
||||
println!("{:>14} : {}", pl, pl.plot());
|
|
||||
|
|
||||
println!();
|
|
||||
let pg = Polygon(
|
|
||||
Coordinates(vec!( Coordinate( 0, -10, 0.0)
|
|
||||
, Coordinate( 10, 10, 0.0)
|
|
||||
, Coordinate(-10, 10, 0.0) )));
|
|
||||
println!("{:>14} : {}", pg, pg.plot());
|
|
||||
|
|
||||
let i = Vector(Fractional( 0,1), Fractional(-30,1), Fractional(0,1));
|
|
||||
let j = Vector(Fractional( 30,1), Fractional( 30,1), Fractional(0,1));
|
|
||||
let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1));
|
|
||||
|
|
||||
let rot :TMatrix<Fractional> = TMatrix::rotate_z(20);
|
|
||||
let Vector(ix, iy, _) = i.transform(&rot);
|
|
||||
let Vector(jx, jy, _) = j.transform(&rot);
|
|
||||
let Vector(kx, ky, _) = k.transform(&rot);
|
|
||||
|
|
||||
fn to_i32(x :Fractional) -> i32 {
|
|
||||
let Fractional(n, d) = x;
|
|
||||
(n / d + if (n % d).abs() < (n / 2).abs() { 0 } else { 1 }) as i32
|
|
||||
}
|
|
||||
|
|
||||
println!();
|
|
||||
let pg = Polygon(
|
|
||||
Coordinates(vec!( Coordinate(to_i32(ix) + 100, to_i32(iy) + 100, 0.0)
|
|
||||
, Coordinate(to_i32(jx) + 100, to_i32(jy) + 100, 0.0)
|
|
||||
, Coordinate(to_i32(kx) + 100, to_i32(ky) + 100, 0.0) )));
|
|
||||
println!("{:>14} : {}", pg, pg.plot());
|
|
||||
|
|
||||
let i = Vector( 0.0, -30.0, 0.0);
|
|
||||
let j = Vector( 30.0, 30.0, 0.0);
|
|
||||
let k = Vector(-30.0, 30.0, 0.0);
|
|
||||
|
|
||||
let rot :TMatrix<f64> = TMatrix::rotate_z(20);
|
|
||||
let Vector(ix, iy, _) = i.transform(&rot);
|
|
||||
let Vector(jx, jy, _) = j.transform(&rot);
|
|
||||
let Vector(kx, ky, _) = k.transform(&rot);
|
|
||||
|
|
||||
fn to_i32_2(x :f64) -> i32 {
|
|
||||
x.round() as i32
|
|
||||
}
|
|
||||
|
|
||||
println!();
|
|
||||
let pg = Polygon(
|
|
||||
Coordinates(vec!( Coordinate(to_i32_2(ix) + 100, to_i32_2(iy) + 100, 0.0)
|
|
||||
, Coordinate(to_i32_2(jx) + 100, to_i32_2(jy) + 100, 0.0)
|
|
||||
, Coordinate(to_i32_2(kx) + 100, to_i32_2(ky) + 100, 0.0) )));
|
|
||||
println!("{:>14} : {}", pg, pg.plot());
|
|
||||
}
|
|
||||
|
|
||||
fn _democanvas<T>( xcb :&XcbEasel
|
|
||||
, title :&'static str
|
|
||||
, tx :mpsc::Sender<i32>
|
|
||||
, _triangle :Polyeder<T>
|
|
||||
, tetrahedron :Polyeder<T>
|
|
||||
, cube :Polyeder<T>
|
|
||||
, light :DirectLight<T> )
|
|
||||
where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + Trig + Send + From<i32> + PartialOrd {
|
|
||||
|
|
||||
let mut canvas = xcb.canvas(151, 151).unwrap();
|
|
||||
let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle
|
|
||||
// was 50.
|
|
||||
|
|
||||
canvas.set_title(title);
|
|
||||
canvas.init_events();
|
|
||||
canvas.start_events(tx.clone());
|
|
||||
|
|
||||
thread::spawn(move || {
|
|
||||
let start = Instant::now();
|
|
||||
let step = Duration::from_millis(25);
|
|
||||
let mut last = Instant::now();
|
|
||||
|
|
||||
let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));
|
|
||||
|
|
||||
loop {
|
|
||||
let deg = ((start.elapsed() / 25).as_millis() % 360) as i32;
|
|
||||
|
|
||||
let rz = TMatrix::rotate_z(deg);
|
|
||||
let rx = TMatrix::rotate_x(-deg*2);
|
|
||||
let ry = TMatrix::rotate_y(-deg*2);
|
|
||||
|
|
||||
let rot1 = TMatrix::combine(vec!(rz, rx, t));
|
|
||||
let rot2 = TMatrix::combine(vec!(rz, ry, t));
|
|
||||
|
|
||||
let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)
|
|
||||
, ( cube.transform(&rot2), 0x0000FF) );
|
|
||||
//let objects = vec!( ( cube.transform(&rot2), 0x0000FF) );
|
|
||||
//let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) );
|
|
||||
//let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );
|
|
||||
|
|
||||
canvas.clear();
|
|
||||
|
|
||||
for (o, color) in objects {
|
|
||||
for (pg, c) in o.project(&camera, &light, color) {
|
|
||||
//canvas.draw(&pg, Coordinate(0, 0, 0.into()), c);
|
|
||||
(&pg).fill(&mut canvas, c);
|
|
||||
//(&pg).debug();
|
|
||||
//println!("\n");
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
let passed = Instant::now() - last;
|
|
||||
let f = (passed.as_nanos() / step.as_nanos()) as u32;
|
|
||||
|
|
||||
if f > 1 {
|
|
||||
println!("{} !!! Detected frame drop", title);
|
|
||||
}
|
|
||||
|
|
||||
last = last + step*(f + 1);
|
|
||||
canvas.put_text( Coordinate(10, 15, 0.into())
|
|
||||
, &format!( "sleep: {:?}"
|
|
||||
, last - Instant::now() ));
|
|
||||
canvas.show();
|
|
||||
thread::sleep(last - Instant::now());
|
|
||||
}
|
|
||||
});
|
|
||||
}
|
|
||||
|
|
||||
fn main() {
|
|
||||
common_fractional();
|
|
||||
println!();
|
|
||||
continuous();
|
|
||||
println!();
|
|
||||
sqrt();
|
|
||||
println!();
|
|
||||
pi();
|
|
||||
println!();
|
|
||||
_sin();
|
|
||||
println!();
|
|
||||
_cos();
|
|
||||
println!();
|
|
||||
_tan();
|
|
||||
println!();
|
|
||||
_vector1();
|
|
||||
println!();
|
|
||||
_vector2();
|
|
||||
println!();
|
|
||||
_transform1();
|
|
||||
println!();
|
|
||||
_transform2();
|
|
||||
println!();
|
|
||||
_line();
|
|
||||
|
|
||||
let xcb = XcbEasel::new().unwrap();
|
|
||||
let (tx, rx) = mpsc::channel();
|
|
||||
|
|
||||
|
|
||||
_democanvas( &xcb, "Something...(f64)", tx.clone()
|
|
||||
, Polyeder::triangle(60.0)
|
|
||||
, Polyeder::tetrahedron(100.0)
|
|
||||
, Polyeder::cube(56.25)
|
|
||||
, DirectLight::new(Vector(0.0, 0.0, 1.0)) );
|
|
||||
/*
|
|
||||
_democanvas( &xcb, "Something...(Fractional)", tx.clone()
|
|
||||
, Polyeder::triangle(Fractional(60,1))
|
|
||||
, Polyeder::tetrahedron(Fractional(80,1))
|
|
||||
, Polyeder::cube(Fractional(55,1))
|
|
||||
, DirectLight::new(Vector( Fractional(0,1)
|
|
||||
, Fractional(0,1)
|
|
||||
, Fractional(1,1) )) );
|
|
||||
*/
|
|
||||
|
|
||||
for x in rx {
|
|
||||
match x {
|
|
||||
1 => break,
|
|
||||
_ => {},
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,280 +0,0 @@ |
|||||
//
|
|
||||
// Some trigonometic functions with Fractions results.
|
|
||||
// Currently only sin, cos and tan are implemented.
|
|
||||
// As I was unable to find a really good integral approximation for them I
|
|
||||
// implement them as a table which is predefined using the floating point
|
|
||||
// function f64::sin and then transformed into a fraction of a given
|
|
||||
// PRECISION.
|
|
||||
// These approximations are quite good and for a few edge cases
|
|
||||
// even better than the floating point implementations.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::cmp::Ordering;
|
|
||||
use std::ops::Div;
|
|
||||
use std::ops::Neg;
|
|
||||
use std::marker::Sized;
|
|
||||
use crate::{Fractional, Error};
|
|
||||
use crate::continuous::Continuous;
|
|
||||
|
|
||||
pub trait Trig {
|
|
||||
fn pi() -> Self;
|
|
||||
fn recip(self) -> Self;
|
|
||||
fn round(&self) -> i32;
|
|
||||
fn sqrt(self) -> Result<Self, Error> where Self: Sized;
|
|
||||
fn sintab() -> Vec<Self> where Self: Sized;
|
|
||||
fn tantab() -> Vec<Self> where Self: Sized;
|
|
||||
|
|
||||
fn sin(d :i32) -> Self
|
|
||||
where Self: Sized + Neg<Output = Self> + Copy {
|
|
||||
match d {
|
|
||||
0 ..=90 => Self::sintab()[d as usize],
|
|
||||
91 ..=180 => Self::sintab()[180 - d as usize],
|
|
||||
181..=270 => -Self::sintab()[d as usize - 180],
|
|
||||
271..=359 => -Self::sintab()[360 - d as usize],
|
|
||||
_ => {
|
|
||||
Self::sin(if d < 0 { d % 360 + 360 } else { d % 360 })
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn cos(d :i32) -> Self
|
|
||||
where Self: Sized + Neg<Output = Self> + Copy {
|
|
||||
match d {
|
|
||||
0 ..=90 => Self::sintab()[90 - d as usize],
|
|
||||
91 ..=180 => -Self::sintab()[90 - (180 - d as usize)],
|
|
||||
181..=270 => -Self::sintab()[90 - (d as usize - 180)],
|
|
||||
271..=359 => Self::sintab()[90 - (360 - d as usize)],
|
|
||||
_ => {
|
|
||||
Self::cos(if d < 0 { d % 360 + 360 } else { d % 360 })
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn tan(d :i32) -> Self where Self: Sized + Copy {
|
|
||||
match d {
|
|
||||
0 ..=179 => Self::tantab()[d as usize],
|
|
||||
180..=359 => Self::tantab()[d as usize - 180],
|
|
||||
_ => {
|
|
||||
Self::tan(if d < 0 { d % 360 + 360 } else { d % 360 })
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn cot(d :i32) -> Self
|
|
||||
where Self: Sized + Copy + From<i32> + Div<Output = Self> {
|
|
||||
Into::<Self>::into(1) / Self::tan(d)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
// Try to keep precision as high as possible while having a denominator
|
|
||||
// as small as possible. The values are taken by try and error.
|
|
||||
const PRECISION :i64 = 1000000;
|
|
||||
const MAX_DENOMINATOR :i64 = 7000;
|
|
||||
|
|
||||
// This is a really close fractional approximation for pi.
|
|
||||
impl Trig for Fractional {
|
|
||||
fn pi() -> Self {
|
|
||||
Fractional(355, 113)
|
|
||||
}
|
|
||||
|
|
||||
fn recip(self) -> Self {
|
|
||||
let Fractional(n, d) = self;
|
|
||||
Fractional(d, n)
|
|
||||
}
|
|
||||
|
|
||||
fn round(&self) -> i32 {
|
|
||||
let Fractional(n, d) = self;
|
|
||||
(n / d) as i32
|
|
||||
}
|
|
||||
|
|
||||
// This is a really bad approximation of sqrt for a fractional...
|
|
||||
// for (9/3) it will result 3 which if way to far from the truth,
|
|
||||
// which is ~1.7320508075
|
|
||||
// BUT we can use this value as starting guess for creating a
|
|
||||
// continous fraction for the sqrt... and create a much better
|
|
||||
// fractional representation of the sqrt.
|
|
||||
// So, if inner converges, but is not a perfect square (does not
|
|
||||
// end up in an Ordering::Equal - which is the l > h case)
|
|
||||
// we use the l - 1 as starting guess for sqrt_cfrac.
|
|
||||
// taken from:
|
|
||||
// https://www.geeksforgeeks.org/square-root-of-an-integer/
|
|
||||
fn sqrt(self) -> Result<Self, Error> {
|
|
||||
// find the sqrt of x in O(log x/2).
|
|
||||
// This stops if a perfect sqare was found. Else it passes
|
|
||||
// the found value as starting guess to the continous fraction
|
|
||||
// sqrt function.
|
|
||||
fn floor_sqrt(x :i64) -> Fractional {
|
|
||||
fn inner(l :i64, h :i64, x :i64) -> Fractional {
|
|
||||
if l > h {
|
|
||||
(&Continuous::sqrt(x, l - 1)).into()
|
|
||||
} else {
|
|
||||
let m = (l + h) / 2;
|
|
||||
match x.cmp(&(m * m)) {
|
|
||||
Ordering::Equal => m.into(),
|
|
||||
Ordering::Less => inner(l, m - 1, x),
|
|
||||
Ordering::Greater => inner(m + 1, h, x),
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
match x {
|
|
||||
0 => 0.into(),
|
|
||||
1 => 1.into(),
|
|
||||
_ => inner(1, x / 2, x),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
let Fractional(n, d) = self;
|
|
||||
|
|
||||
let n = match n.cmp(&0) {
|
|
||||
Ordering::Equal => 0.into(),
|
|
||||
Ordering::Less => return Err("sqrt on negative undefined"),
|
|
||||
Ordering::Greater => floor_sqrt(n),
|
|
||||
};
|
|
||||
|
|
||||
let d = match d.cmp(&0) {
|
|
||||
Ordering::Equal => 0.into(),
|
|
||||
Ordering::Less => return Err("sqrt on negative undefined"),
|
|
||||
Ordering::Greater => floor_sqrt(d),
|
|
||||
};
|
|
||||
|
|
||||
Ok(n / d)
|
|
||||
}
|
|
||||
|
|
||||
fn sintab() -> Vec<Self> {
|
|
||||
// hold sin Fractionals from 0 to 89 ...
|
|
||||
// luckily with a bit of index tweeking this can also be used for
|
|
||||
// cosine values.
|
|
||||
lazy_static::lazy_static! {
|
|
||||
static ref SINTAB :Vec<Fractional> =
|
|
||||
(0..=90).map(|x| _sin(x)).collect();
|
|
||||
}
|
|
||||
|
|
||||
// fractional sin from f64 sin. (From 0° to 90°)
|
|
||||
fn _sin(d: u32) -> Fractional {
|
|
||||
match d {
|
|
||||
0 => Fractional(0, 1),
|
|
||||
90 => Fractional(1, 1),
|
|
||||
_ => generate(d, PRECISION, &f64::sin),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
SINTAB.to_vec()
|
|
||||
}
|
|
||||
|
|
||||
fn tantab() -> Vec<Self> {
|
|
||||
// This table exists only because the sin(α) / cos(α) method
|
|
||||
// yields very large unreducable denominators in a lot of cases.
|
|
||||
lazy_static::lazy_static! {
|
|
||||
static ref TANTAB :Vec<Fractional> =
|
|
||||
(0..180).map(|x| _tan(x)).collect();
|
|
||||
}
|
|
||||
|
|
||||
// fractional tan from f64 tan. (From 0° to 179°)
|
|
||||
fn _tan(d: u32) -> Fractional {
|
|
||||
match d {
|
|
||||
0 => Fractional(0, 1),
|
|
||||
45 => Fractional(1, 1),
|
|
||||
90 => Fractional(1, 0), // although they are both inf and -inf.
|
|
||||
135 => -Fractional(1, 1),
|
|
||||
_ => generate(d, PRECISION, &f64::tan),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
TANTAB.to_vec()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
// search for a fraction with a denominator less than MAX_DENOMINATOR that
|
|
||||
// provides the minimal PRECISION criteria.
|
|
||||
// !! With f = &f64::tan and d close to the inf boundarys of tan
|
|
||||
// we get very large numerators because the numerator becomes a
|
|
||||
// multiple of the denominator.
|
|
||||
fn generate(d :u32, p :i64, f :&dyn Fn(f64) -> f64) -> Fractional {
|
|
||||
// This is undefined behaviour for very large f64, but our f64
|
|
||||
// is always between 0.0 and 1000000.0 which should be fine.
|
|
||||
let s = (f((d as f64).to_radians()) * p as f64).round() as i64;
|
|
||||
let Fractional(n, dn) = Fractional(s, p).reduce();
|
|
||||
match dn.abs().cmp(&MAX_DENOMINATOR) {
|
|
||||
Ordering::Less => Fractional(n, dn),
|
|
||||
_ => generate(d, p + 1, f),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Trig for f64 {
|
|
||||
fn pi() -> Self {
|
|
||||
std::f64::consts::PI
|
|
||||
}
|
|
||||
|
|
||||
fn recip(self) -> Self {
|
|
||||
self.recip()
|
|
||||
}
|
|
||||
|
|
||||
fn round(&self) -> i32 {
|
|
||||
f64::round(*self) as i32
|
|
||||
}
|
|
||||
|
|
||||
fn sqrt(self) -> Result<Self, Error> {
|
|
||||
let x = self.sqrt();
|
|
||||
match x.is_nan() {
|
|
||||
true => Err("sqrt on negative undefined"),
|
|
||||
false => Ok(x),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn sintab() -> Vec<Self> {
|
|
||||
lazy_static::lazy_static! {
|
|
||||
static ref SINTAB :Vec<f64> =
|
|
||||
(0..=90).map(|x| _sin(x)).collect();
|
|
||||
}
|
|
||||
|
|
||||
// f64 sin. (From 0° to 90°)
|
|
||||
fn _sin(d: u32) -> f64 {
|
|
||||
match d {
|
|
||||
0 => 0.0,
|
|
||||
90 => 1.0,
|
|
||||
_ => (d as f64).to_radians().sin(),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
SINTAB.to_vec()
|
|
||||
}
|
|
||||
|
|
||||
fn tantab() -> Vec<Self> {
|
|
||||
// This table exists only because the sin(α) / cos(α) method
|
|
||||
// yields very large unreducable denominators in a lot of cases.
|
|
||||
lazy_static::lazy_static! {
|
|
||||
static ref TANTAB :Vec<f64> =
|
|
||||
(0..180).map(|x| _tan(x)).collect();
|
|
||||
}
|
|
||||
|
|
||||
// fractional tan from f64 tan. (From 0° to 179°)
|
|
||||
fn _tan(d: u32) -> f64 {
|
|
||||
match d {
|
|
||||
0 => 0.0,
|
|
||||
45 => 1.0,
|
|
||||
90 => std::f64::INFINITY,
|
|
||||
135 => -1.0,
|
|
||||
_ => (d as f64).to_radians().tan(),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
TANTAB.to_vec()
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,272 +0,0 @@ |
|||||
//
|
|
||||
// XCB implementation for drawing some stuff...
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
extern crate xcb;
|
|
||||
|
|
||||
use std::sync::Arc;
|
|
||||
use std::ptr; //::{null, null_mut};
|
|
||||
use std::thread;
|
|
||||
use std::sync::mpsc;
|
|
||||
use std::ops::{Add, Sub, Div};
|
|
||||
|
|
||||
use crate::easel::{Easel, Canvas, Drawable, Coordinate, Coordinates};
|
|
||||
|
|
||||
#[derive(Clone)]
|
|
||||
pub struct XcbEasel (Arc<xcb::Connection>, i32);
|
|
||||
|
|
||||
pub struct XcbCanvas<'a, T> { conn :Arc<xcb::Connection>
|
|
||||
, width :u16 |
|
||||
, height :u16 |
|
||||
, window :u32 |
|
||||
, pixmap :u32 |
|
||||
, gc :u32 |
|
||||
, zbuf :Vec<T>
|
|
||||
, shm :Box<&'a mut [u32]> }
|
|
||||
|
|
||||
impl XcbEasel {
|
|
||||
pub fn new() -> Result<XcbEasel, xcb::ConnError> {
|
|
||||
let (conn, num) = xcb::Connection::connect(None)?;
|
|
||||
|
|
||||
Ok(XcbEasel(Arc::new(conn), num))
|
|
||||
}
|
|
||||
|
|
||||
pub fn setup(&self) -> xcb::Setup {
|
|
||||
let XcbEasel(conn, _) = self;
|
|
||||
conn.get_setup()
|
|
||||
}
|
|
||||
|
|
||||
pub fn screen(&self) -> Option<xcb::Screen> {
|
|
||||
let XcbEasel(_, num) = self;
|
|
||||
self.setup().roots().nth(*num as usize)
|
|
||||
}
|
|
||||
|
|
||||
pub fn canvas<'a, T>( &self
|
|
||||
, width :u16 |
|
||||
, height :u16) -> Option<XcbCanvas<'a, T>>
|
|
||||
where T: Clone + From<i32> {
|
|
||||
let Self(conn, _) = self;
|
|
||||
let conn = conn.clone();
|
|
||||
let screen = match self.screen() {
|
|
||||
None => return None,
|
|
||||
Some(screen) => screen,
|
|
||||
};
|
|
||||
|
|
||||
println!("root depth: {}", screen.root_depth());
|
|
||||
|
|
||||
let shmseg = conn.generate_id();
|
|
||||
let gc = conn.generate_id();
|
|
||||
let pixmap = conn.generate_id();
|
|
||||
let window = conn.generate_id();
|
|
||||
|
|
||||
xcb::create_window( &conn, xcb::COPY_FROM_PARENT as u8, window
|
|
||||
, screen.root(), 0, 0, width, width, 0
|
|
||||
, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16
|
|
||||
, screen.root_visual()
|
|
||||
, &[(xcb::CW_BACK_PIXEL, screen.black_pixel())] );
|
|
||||
|
|
||||
xcb::create_gc( &conn, gc, screen.root()
|
|
||||
, &[ (xcb::GC_FOREGROUND, screen.white_pixel())
|
|
||||
, (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
|
|
||||
|
|
||||
let zbuf :Vec<T> = vec!(0.into(); (width * height) as usize);
|
|
||||
let (shmid, shm) = getshm((width * height) as usize);
|
|
||||
xcb::shm::attach(&conn, shmseg, shmid as u32, false);
|
|
||||
unsafe { libc::shmctl(shmid, libc::IPC_RMID, ptr::null_mut()); }
|
|
||||
|
|
||||
xcb::shm::create_pixmap( &conn, pixmap, window, width, height
|
|
||||
, screen.root_depth(), shmseg, 0 );
|
|
||||
|
|
||||
xcb::map_window(&conn, window);
|
|
||||
conn.flush();
|
|
||||
|
|
||||
Some(XcbCanvas{ conn: conn
|
|
||||
, width: width
|
|
||||
, height: height
|
|
||||
, window: window
|
|
||||
, pixmap: pixmap
|
|
||||
, gc: gc
|
|
||||
, zbuf: zbuf
|
|
||||
, shm: Box::new(shm) } )
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<'a, T> XcbCanvas<'a, T> {
|
|
||||
pub fn set_title(&self, title :&str) {
|
|
||||
let c = xcb::change_property_checked( &self.conn
|
|
||||
, xcb::PROP_MODE_REPLACE as u8
|
|
||||
, self.window
|
|
||||
, xcb::ATOM_WM_NAME
|
|
||||
, xcb::ATOM_STRING
|
|
||||
, 8
|
|
||||
, title.as_bytes() );
|
|
||||
if self.conn.has_error().is_err() || c.request_check().is_err() {
|
|
||||
println!("Error setting title");
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) {
|
|
||||
use std::slice::from_raw_parts_mut;
|
|
||||
|
|
||||
unsafe {
|
|
||||
let id = libc::shmget( libc::IPC_PRIVATE
|
|
||||
, size * 4
|
|
||||
, libc::IPC_CREAT | 0o744 );
|
|
||||
let ptr = libc::shmat(id, ptr::null(), 0);
|
|
||||
(id as i32, from_raw_parts_mut(ptr as *mut u32, size))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl Easel for XcbEasel {}
|
|
||||
|
|
||||
impl<'a, T> Canvas<T> for XcbCanvas<'a, T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Copy + From<i32> + PartialOrd {
|
|
||||
fn init_events(&self) {
|
|
||||
let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
|
|
||||
| xcb::EVENT_MASK_KEY_PRESS
|
|
||||
| xcb::EVENT_MASK_STRUCTURE_NOTIFY
|
|
||||
| xcb::EVENT_MASK_PROPERTY_CHANGE )];
|
|
||||
xcb::change_window_attributes(&self.conn, self.window, &mask);
|
|
||||
self.conn.flush();
|
|
||||
}
|
|
||||
|
|
||||
fn start_events(&self, tx :mpsc::Sender<i32>) {
|
|
||||
let conn = self.conn.clone();
|
|
||||
let window = self.window;
|
|
||||
let pixmap = self.pixmap;
|
|
||||
let gc = self.gc;
|
|
||||
let width = self.width;
|
|
||||
let height = self.height;
|
|
||||
|
|
||||
thread::spawn(move || {
|
|
||||
loop {
|
|
||||
let event = conn.wait_for_event();
|
|
||||
|
|
||||
match event {
|
|
||||
None => break,
|
|
||||
Some(event) => {
|
|
||||
match event.response_type() & !0x80 {
|
|
||||
xcb::PROPERTY_NOTIFY => {
|
|
||||
let prop_notify :&xcb::PropertyNotifyEvent
|
|
||||
= unsafe { xcb::cast_event(&event) };
|
|
||||
|
|
||||
if prop_notify.atom() == xcb::ATOM_WM_NAME {
|
|
||||
// retrieving title
|
|
||||
let cookie
|
|
||||
= xcb::get_property( &conn
|
|
||||
, false
|
|
||||
, window
|
|
||||
, xcb::ATOM_WM_NAME
|
|
||||
, xcb::ATOM_STRING
|
|
||||
, 0, 1024 );
|
|
||||
|
|
||||
if let Ok(reply) = cookie.get_reply() {
|
|
||||
let r = reply.value();
|
|
||||
let r = std::str::from_utf8(r).unwrap();
|
|
||||
|
|
||||
println!("title changed to: {}", r);
|
|
||||
}
|
|
||||
}
|
|
||||
},
|
|
||||
|
|
||||
xcb::EXPOSE => {
|
|
||||
xcb::copy_area( &conn, pixmap, window, gc
|
|
||||
, 0, 0, 0, 0
|
|
||||
, width, height );
|
|
||||
conn.flush();
|
|
||||
},
|
|
||||
|
|
||||
xcb::KEY_PRESS => {
|
|
||||
let key_press: &xcb::KeyPressEvent
|
|
||||
= unsafe { xcb::cast_event(&event) };
|
|
||||
|
|
||||
println!( "Key '{}' pressed"
|
|
||||
, key_press.detail() );
|
|
||||
|
|
||||
// Q (on qwerty)
|
|
||||
if key_press.detail() == 0x18 {
|
|
||||
tx.send(1).unwrap();
|
|
||||
break;
|
|
||||
}
|
|
||||
},
|
|
||||
|
|
||||
_ => {},
|
|
||||
}
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
});
|
|
||||
}
|
|
||||
|
|
||||
fn width(&self) -> u16 {
|
|
||||
self.width
|
|
||||
}
|
|
||||
|
|
||||
fn height(&self) -> u16 {
|
|
||||
self.height
|
|
||||
}
|
|
||||
|
|
||||
fn clear(&mut self) {
|
|
||||
self.zbuf = vec!(0.into(); self.zbuf.len());
|
|
||||
unsafe {
|
|
||||
let ptr = self.shm.as_mut_ptr();
|
|
||||
ptr::write_bytes( ptr, 0
|
|
||||
, self.width as usize * self.height as usize);
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn draw(&mut self, d :&dyn Drawable<T>, ofs :Coordinate<T>, color: u32) {
|
|
||||
let Coordinates(c) = d.plot();
|
|
||||
let Coordinate(xofs, yofs, _) = ofs;
|
|
||||
|
|
||||
for Coordinate(x, y, zr) in c {
|
|
||||
let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize;
|
|
||||
if self.zbuf[idx] < zr {
|
|
||||
self.zbuf[idx] = zr;
|
|
||||
self.shm[idx] = color;
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn put_text(&self, ofs :Coordinate<T>, s :&str) {
|
|
||||
let Coordinate(xofs, yofs, _) = ofs;
|
|
||||
xcb::xproto::image_text_8( &self.conn, self.pixmap, self.gc
|
|
||||
, xofs as i16, yofs as i16, s );
|
|
||||
self.conn.flush();
|
|
||||
}
|
|
||||
|
|
||||
fn set_pixel(&mut self, c :Coordinate<T>, color :u32) {
|
|
||||
let Coordinate(x, y, zr) = c;
|
|
||||
let idx :usize = (y * (self.width as i32) + x) as usize;
|
|
||||
|
|
||||
if self.zbuf[idx] < zr {
|
|
||||
self.zbuf[idx] = zr;
|
|
||||
self.shm[idx] = color;
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn show(&self) {
|
|
||||
xcb::copy_area( &self.conn, self.pixmap, self.window, self.gc
|
|
||||
, 0, 0, 0, 0
|
|
||||
, self.width, self.height );
|
|
||||
self.conn.flush();
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "functions" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "functions" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,12 +0,0 @@ |
|||||
fn main() {
|
|
||||
another_function(5, add_five(6));
|
|
||||
}
|
|
||||
|
|
||||
fn another_function(x: i32, y: i32) {
|
|
||||
println!("The value of x id: {}", x);
|
|
||||
println!("The value of y id: {}", y);
|
|
||||
}
|
|
||||
|
|
||||
fn add_five(x: i32) -> i32 {
|
|
||||
x + 5
|
|
||||
}
|
|
||||
@ -1,91 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "fuchsia-cprng" |
|
||||
version = "0.1.1" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
|
|
||||
[[package]] |
|
||||
name = "guessing_game" |
|
||||
version = "0.1.0" |
|
||||
dependencies = [ |
|
||||
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "libc" |
|
||||
version = "0.2.65" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
|
|
||||
[[package]] |
|
||||
name = "rand" |
|
||||
version = "0.3.23" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
dependencies = [ |
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "rand" |
|
||||
version = "0.4.6" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
dependencies = [ |
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "rand_core" |
|
||||
version = "0.3.1" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
dependencies = [ |
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "rand_core" |
|
||||
version = "0.4.2" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
|
|
||||
[[package]] |
|
||||
name = "rdrand" |
|
||||
version = "0.4.0" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
dependencies = [ |
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "winapi" |
|
||||
version = "0.3.8" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
dependencies = [ |
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
||||
] |
|
||||
|
|
||||
[[package]] |
|
||||
name = "winapi-i686-pc-windows-gnu" |
|
||||
version = "0.4.0" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
|
|
||||
[[package]] |
|
||||
name = "winapi-x86_64-pc-windows-gnu" |
|
||||
version = "0.4.0" |
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||
|
|
||||
[metadata] |
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" |
|
||||
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" |
|
||||
"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" |
|
||||
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" |
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" |
|
||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" |
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" |
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" |
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" |
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" |
|
||||
@ -1,8 +0,0 @@ |
|||||
[package] |
|
||||
name = "guessing_game" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
[dependencies] |
|
||||
rand = "0.3.14" |
|
||||
@ -1,36 +0,0 @@ |
|||||
use std::io;
|
|
||||
use std::cmp::Ordering;
|
|
||||
use rand::Rng;
|
|
||||
|
|
||||
fn main() {
|
|
||||
println!("Guess the number!");
|
|
||||
|
|
||||
let secret_number = rand::thread_rng()
|
|
||||
.gen_range(1, 101);
|
|
||||
|
|
||||
loop {
|
|
||||
println!("Please input your guess.");
|
|
||||
|
|
||||
let mut guess = String::new();
|
|
||||
|
|
||||
io::stdin()
|
|
||||
.read_line(&mut guess)
|
|
||||
.expect("Failed to read line");
|
|
||||
|
|
||||
let guess: u32 = match guess.trim().parse() {
|
|
||||
Ok(num) => num,
|
|
||||
Err(_) => continue,
|
|
||||
};
|
|
||||
|
|
||||
println!("You guessed: {}", guess);
|
|
||||
|
|
||||
match guess.cmp(&secret_number) {
|
|
||||
Ordering::Less => println!("Too small!"),
|
|
||||
Ordering::Greater => println!("Too big!"),
|
|
||||
Ordering::Equal => {
|
|
||||
println!("You win!");
|
|
||||
break;
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "hello" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,7 +0,0 @@ |
|||||
[package] |
|
||||
name = "hello" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,3 +0,0 @@ |
|||||
fn main() {
|
|
||||
println!("Hello, world!");
|
|
||||
}
|
|
||||
@ -1,83 +0,0 @@ |
|||||
# Here I collect some interesting links. |
|
||||
|
|
||||
## cargo environment |
|
||||
|
|
||||
Currently I always build all dependencies within th projects own .cargo subdir |
|
||||
by setting the environment variable CARGO_HOME. |
|
||||
|
|
||||
export CARGO_HOME=./.cargo |
|
||||
|
|
||||
Actually I am quite unsure if that is really a good idea because this results |
|
||||
in a lot of rebuilds for each new project. |
|
||||
|
|
||||
## Implement Monads with rust. |
|
||||
|
|
||||
Which is currently difficult through impossible, but might be feasible with |
|
||||
some small additions to the rust type system, namely |
|
||||
«(generic) associated traits.» |
|
||||
|
|
||||
[Read here](https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in-rust.html) |
|
||||
|
|
||||
### Is impl Trait what we needed? |
|
||||
|
|
||||
A new language feature which sounded a bit like the needed one for above is: |
|
||||
|
|
||||
[impl Trait](https://medium.com/@iopguy/impl-trait-in-rust-explanation-efde0d94946a) |
|
||||
|
|
||||
Crossreading it a bit seems to indicate that this is not like the above needed |
|
||||
language feature. |
|
||||
|
|
||||
## WASM ... on gentoo ... |
|
||||
|
|
||||
Right now rust is not really a first class citizen within the gentoo eco |
|
||||
system. For that reason at least when compiling rust with the `system-llvm` |
|
||||
use flag some manual preparations are needed. |
|
||||
|
|
||||
### general informations about Wasm from MDN ... |
|
||||
|
|
||||
[WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) |
|
||||
|
|
||||
### rustwasm tutorial |
|
||||
|
|
||||
[rustwasm](https://rustwasm.github.io/book/introduction.html) |
|
||||
|
|
||||
### location of rustlib ... |
|
||||
|
|
||||
`wasm-pack` expects the wasm runtime under /usr/lib/rustlib/ but a gentoo |
|
||||
installation puts it under /usr/lib/rust-1.39.0/rustlib/. To come around this |
|
||||
issue I just created a symlink. |
|
||||
|
|
||||
Maybe it would be best to send a patch for also settings this symlink to |
|
||||
upstream eselect-rust. |
|
||||
|
|
||||
### Missing lld |
|
||||
|
|
||||
Again `wasm-pack` searches for llvm-lld or rust-lld for the link phase. This |
|
||||
is currently not a dependency for llvm with WASM support, so I installed it |
|
||||
manually. Finally you have to tell rustc to use lld as linker via this |
|
||||
environment variable: |
|
||||
|
|
||||
export RUSTFLAGS="-C linker=lld" |
|
||||
|
|
||||
## Traits when, how & why |
|
||||
|
|
||||
A slightly old but still worthwhile post about rusts standard traits. |
|
||||
|
|
||||
[About traits](https://llogiq.github.io/2015/07/30/traits.html) |
|
||||
|
|
||||
# Side note... 3d math |
|
||||
[3d math primer](https://www.3dgep.com/3d-math-primer-for-game-programmers-vector-operations/) |
|
||||
[basic 3d math](https://matrix44.net/cms/notes/opengl-3d-graphics/basic-3d-math-vectors/) |
|
||||
[vector calculator](https://www.mathportal.org/calculators/matrices-calculators/vector-calculator.php) |
|
||||
[3d vector mathematics](https://vvvv.org/documentation/3d-vector-mathematics) |
|
||||
[sin appr. with fractions](https://dsp.stackexchange.com/questions/46629/finding-polynomial-approximations-of-a-sine-wave) |
|
||||
|
|
||||
# transformations within a coordinate system. |
|
||||
[migenius](https://www.migenius.com/articles/3d-transformations-part1-matrices) |
|
||||
[tutorialspoint](https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm) |
|
||||
|
|
||||
# more math... |
|
||||
|
|
||||
A whole lot of interesting stuff about continued fractions: |
|
||||
[continues fractions](http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfINTRO.html) |
|
||||
|
|
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "loops" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "loops" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,64 +0,0 @@ |
|||||
//
|
|
||||
// Loops examples.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
fn main() {
|
|
||||
// It seams that to use loops this way you absolutely need a mutable.
|
|
||||
// If I build it with a normal type and try to shadow it within the loop
|
|
||||
// the outer variable is always used as input for the shadow, thus it is
|
|
||||
// always the same.... that really sucks.
|
|
||||
let mut counter = 0;
|
|
||||
|
|
||||
let result = loop {
|
|
||||
counter = counter + 1;
|
|
||||
if counter == 10 {
|
|
||||
break counter * 2;
|
|
||||
}
|
|
||||
};
|
|
||||
|
|
||||
println!("The result is {}", result);
|
|
||||
|
|
||||
// The same is true with «while» ... which again sucks.
|
|
||||
let mut number = 3;
|
|
||||
|
|
||||
while number != 0 {
|
|
||||
println!("{}!", number);
|
|
||||
number = number - 1;
|
|
||||
}
|
|
||||
|
|
||||
println!("LIFTOFF!!!");
|
|
||||
|
|
||||
// apart from beeing frustrated about the above facts... lets continue.
|
|
||||
let a = [10, 20, 30, 40, 50];
|
|
||||
let mut index = 0;
|
|
||||
|
|
||||
while index < 5 {
|
|
||||
println!("the value is: {}", a[index]);
|
|
||||
index = index + 1;
|
|
||||
}
|
|
||||
|
|
||||
for element in a.iter() {
|
|
||||
println!("the value is still: {}", element);
|
|
||||
}
|
|
||||
|
|
||||
for number in (1..4).rev() {
|
|
||||
println!("for {}!", number);
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "ownership" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "ownership" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,183 +0,0 @@ |
|||||
//
|
|
||||
// Examples related to ownership, also introducing String.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
fn main() {
|
|
||||
concat();
|
|
||||
move_variable();
|
|
||||
clone_variable();
|
|
||||
|
|
||||
let s = String::from("hello"); // s comes into scope
|
|
||||
|
|
||||
take_ownership(s); // s's value moves into the function
|
|
||||
// … and so is no longer valid here.
|
|
||||
let x = 5; // x comes into scope
|
|
||||
|
|
||||
makes_copy(x); // the scalar value has the Copy trait and
|
|
||||
// lives on the stack and thus is still
|
|
||||
// valid here.
|
|
||||
|
|
||||
let _s1 = gives_ownership(); // move the return value into _s1
|
|
||||
let s2 = String::from("hello"); // s2 comes into scope
|
|
||||
let _s3 = takes_and_gives(s2); // s2 is moved into function, which in
|
|
||||
// turn moves the return value into _s3.
|
|
||||
|
|
||||
let s1 = String::from("hello"); // s1 comes into scope.
|
|
||||
let len = calculate_length(&s1); // A reference to s1 is given to a
|
|
||||
// calculate_length which effectively is
|
|
||||
// not s1 itself but another pointer to
|
|
||||
// s1… which is the reason that we still
|
|
||||
// can use it below.
|
|
||||
let _another_s = &s1; // again only a reference which does not
|
|
||||
// take ownership, thus s1 can still be
|
|
||||
// used below.
|
|
||||
println!("The length of '{}' is {}.", s1, len);
|
|
||||
|
|
||||
// Passing values as reference to a function is called borrowing. A
|
|
||||
// borrowed value can't be changed.
|
|
||||
change(&s1);
|
|
||||
|
|
||||
// but we can force this… which is probably not the best of ideas most
|
|
||||
// of the time…
|
|
||||
let mut s_mut = String::from("hello");
|
|
||||
change_mutable(&mut s_mut);
|
|
||||
|
|
||||
// but you can have only one mutable reference of a value in a single
|
|
||||
// scope. The following would fail with:
|
|
||||
// cannot borrow `s_mut` as mutable more than once at a time second
|
|
||||
// mutable borrow occurs here
|
|
||||
// let r1 = &mut s_mut;
|
|
||||
// let r2 = &mut s_mut;
|
|
||||
// println!("{}, {}", r1, r2);
|
|
||||
|
|
||||
// We also can't have an immutable reference while we have a mutable one.
|
|
||||
// Look on Page 98 for an explanation.
|
|
||||
|
|
||||
// The scope of references is not the whole block they are introduced in
|
|
||||
// but goes only until their last usage. Thus if you first have an
|
|
||||
// immutable reference but never use it after a mutable reference is
|
|
||||
// declared, that would be ok… At all this is kind of confusing and very
|
|
||||
// Mozzilaish. :D
|
|
||||
|
|
||||
// Now we demonstrate string slices…
|
|
||||
let s4 = String::from("hello world");
|
|
||||
let s_slice = first_word(&s4);
|
|
||||
|
|
||||
// working with an mutable reference like with s4.clear() will not
|
|
||||
// compile at this point because we already have and use later on an
|
|
||||
// immutable reference.
|
|
||||
|
|
||||
println!("The slice was: {}", s_slice);
|
|
||||
|
|
||||
// not that string literals are slices. They are immutable references of
|
|
||||
// the programs TEXT segment. Thats the reason why they are immutable.
|
|
||||
|
|
||||
// Thus try generic_first_word…
|
|
||||
println!("First word on literal: {}", generic_first_word("hello world"));
|
|
||||
println!("First word on String: {}", generic_first_word(&s4[..]));
|
|
||||
} // x and s go out of scope but nothing happens for s because this function
|
|
||||
// has no longer the ownership of s.
|
|
||||
// s3 goes out of scope and is dropped. s2 was moved and s1 is dropped.
|
|
||||
|
|
||||
fn concat() {
|
|
||||
let mut s = String::from("hello");
|
|
||||
s.push_str(", world!");
|
|
||||
println!("{}", s);
|
|
||||
}
|
|
||||
|
|
||||
fn move_variable() {
|
|
||||
let s1 = String::from("hello");
|
|
||||
let s2 = s1; // does not copy data but only the String structure.
|
|
||||
// when using s1 below we get an error that a moved value was borrowed.
|
|
||||
println!("{}, world!", s2);
|
|
||||
}
|
|
||||
|
|
||||
fn clone_variable() {
|
|
||||
let s1 = String::from("hello");
|
|
||||
let s2 = s1.clone();
|
|
||||
// this time both are valid.
|
|
||||
println!("s1 = {}, s2 = {}", s1, s2)
|
|
||||
}
|
|
||||
|
|
||||
fn take_ownership(some_string: String) { // some_string comes into scope
|
|
||||
println!("{}", some_string);
|
|
||||
} // some_string goes out of scope and «drop» is called, thus memory freed.
|
|
||||
|
|
||||
fn makes_copy(some_integer: i32) { // some integer comes into scope
|
|
||||
println!("{}", some_integer);
|
|
||||
} // Here, some_integer goes out of scope but because it was a copy and on the
|
|
||||
// stack nothing special happens… beside that stack space is freed.
|
|
||||
|
|
||||
fn gives_ownership() -> String { // this will move the return value into the
|
|
||||
// calling function.
|
|
||||
let some_string = String::from("hello"); // some_string comes into scope
|
|
||||
some_string
|
|
||||
}
|
|
||||
|
|
||||
fn takes_and_gives(a_string: String) -> String { // a_string comes into scope
|
|
||||
a_string // and is returned and moved
|
|
||||
// to the calling function.
|
|
||||
} // a_string goes out of scope but nothing happens as it is moved.
|
|
||||
|
|
||||
fn calculate_length(s: &String) -> usize { // s comes into scope. It is a
|
|
||||
// reference. References do not
|
|
||||
// take ownership of the underlying
|
|
||||
// value which is the String in
|
|
||||
// main.
|
|
||||
s.len()
|
|
||||
} // Here s goes out of scope but because it has no ownership of the String
|
|
||||
// nothing happens.
|
|
||||
|
|
||||
fn change(_some_string: &String) {
|
|
||||
// the following would give this error:
|
|
||||
// `_some_string` is a `&` reference, so the data it refers to cannot be
|
|
||||
// borrowed as mutable
|
|
||||
// _some_string.push_str(", world!");
|
|
||||
}
|
|
||||
|
|
||||
fn change_mutable(some_string: &mut String) {
|
|
||||
some_string.push_str(", world");
|
|
||||
}
|
|
||||
|
|
||||
fn first_word(s: &String) -> &str {
|
|
||||
let bytes = s.as_bytes();
|
|
||||
|
|
||||
for (i, &item) in bytes.iter().enumerate() {
|
|
||||
if item == b' ' {
|
|
||||
return &s[..i];
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
&s[..]
|
|
||||
}
|
|
||||
|
|
||||
// To make first_word work on either string literals (which are in fact string
|
|
||||
// slices, s.o.) one would write first_word like this…
|
|
||||
fn generic_first_word(s: &str) -> &str {
|
|
||||
let bytes = s.as_bytes();
|
|
||||
|
|
||||
for (i, &item) in bytes.iter().enumerate() {
|
|
||||
if item == b' ' {
|
|
||||
return &s[..i];
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
&s[..]
|
|
||||
}
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "rectangles" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,90 +0,0 @@ |
|||||
//
|
|
||||
// Examples related to structs…
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
#[derive(Debug)]
|
|
||||
struct Rectangle {
|
|
||||
width: u32,
|
|
||||
height: u32,
|
|
||||
}
|
|
||||
|
|
||||
impl Rectangle {
|
|
||||
fn area(&self) -> u32 {
|
|
||||
self.width * self.height
|
|
||||
}
|
|
||||
|
|
||||
fn can_hold(&self, inner: &Rectangle) -> bool {
|
|
||||
self.width >= inner.width && self.height >= inner.height
|
|
||||
}
|
|
||||
|
|
||||
fn square(size: u32) -> Rectangle {
|
|
||||
Rectangle { width: size, height: size }
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn main() {
|
|
||||
let width1 = 30;
|
|
||||
let height1 = 50;
|
|
||||
|
|
||||
println!(
|
|
||||
"The area of the rectangle ist {} square pixels.",
|
|
||||
area(width1, height1));
|
|
||||
|
|
||||
let rect1 = (30, 50);
|
|
||||
|
|
||||
println!(
|
|
||||
"The area of the rectangle ist {} square pixels.",
|
|
||||
_area(rect1));
|
|
||||
|
|
||||
let rect1 = Rectangle { width: 30, height: 50 };
|
|
||||
|
|
||||
println!(
|
|
||||
"The area of the rectangle ist {} square pixels.",
|
|
||||
__area(&rect1));
|
|
||||
|
|
||||
println!("_rect1 is {:?}", rect1);
|
|
||||
|
|
||||
println!(
|
|
||||
"The area of the rectangle ist {} square pixels.",
|
|
||||
rect1.area());
|
|
||||
|
|
||||
let rect2 = Rectangle { width: 10, height: 40};
|
|
||||
let rect3 = Rectangle { width: 60, height: 45};
|
|
||||
|
|
||||
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
|
|
||||
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
|
|
||||
|
|
||||
let square1 = Rectangle::square(32);
|
|
||||
|
|
||||
println!("Got the square rectange: {:?}", square1);
|
|
||||
}
|
|
||||
|
|
||||
fn area(width: u32, height: u32) -> u32 {
|
|
||||
width * height
|
|
||||
}
|
|
||||
|
|
||||
fn _area(dimensions: (u32, u32)) -> u32 {
|
|
||||
let (width, height) = dimensions;
|
|
||||
width * height
|
|
||||
}
|
|
||||
|
|
||||
fn __area(rectangle: &Rectangle) -> u32 {
|
|
||||
rectangle.width * rectangle.height
|
|
||||
}
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "recursion" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,51 +0,0 @@ |
|||||
//
|
|
||||
// Try some recursion with pattern matching... especially in
|
|
||||
// conjunction with match to get a similar behavious as in e.g.
|
|
||||
// haskell...
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
// Borrowing rules do not apply here because everything lives on the stack.
|
|
||||
fn faculty(x: u32) -> u32 {
|
|
||||
match x {
|
|
||||
0 => 1,
|
|
||||
_ => x * faculty(x - 1),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
// for a tail recursive version we need to pass the currently calculated
|
|
||||
// faculty to an inner tail recursive function.
|
|
||||
// This will probably be optimized better, because the compiler would be
|
|
||||
// able to unroll the complete recursion.
|
|
||||
fn tail_faculty(x: u32) -> u32 {
|
|
||||
fn faculty(x: u32, f: u32) -> u32 {
|
|
||||
match x {
|
|
||||
0 => f,
|
|
||||
_ => faculty(x - 1, x * f),
|
|
||||
}
|
|
||||
};
|
|
||||
faculty(x, 1)
|
|
||||
}
|
|
||||
|
|
||||
fn main() {
|
|
||||
for i in 0..10 {
|
|
||||
println!("Fakultät {} = {}", i, faculty(i));
|
|
||||
println!("tail recursive Fakultät {} = {}", i, tail_faculty(i));
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "restaurant" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,27 +0,0 @@ |
|||||
//
|
|
||||
// Move some restaurant stuff in a different file....
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
pub mod hosting;
|
|
||||
|
|
||||
mod serving {
|
|
||||
fn take_order() {}
|
|
||||
fn take_payment() {}
|
|
||||
}
|
|
||||
@ -1,23 +0,0 @@ |
|||||
//
|
|
||||
// Now also sepatate hosting....
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
pub fn add_to_waitlist() {}
|
|
||||
fn seat_at_table() {}
|
|
||||
@ -1,93 +0,0 @@ |
|||||
//
|
|
||||
// Restaurant lib for demontrating rust modules.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
|
|
||||
mod front_of_house;
|
|
||||
|
|
||||
fn serve_order() {}
|
|
||||
|
|
||||
mod back_of_house {
|
|
||||
pub struct Breakfast {
|
|
||||
pub toast: String,
|
|
||||
seasonal_fruit: String,
|
|
||||
}
|
|
||||
|
|
||||
impl Breakfast {
|
|
||||
pub fn summer(toast: &str) -> Breakfast {
|
|
||||
Breakfast {
|
|
||||
toast: String::from(toast),
|
|
||||
seasonal_fruit: String::from("peaches"),
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
pub enum Appetizer {
|
|
||||
Soup,
|
|
||||
Salad,
|
|
||||
}
|
|
||||
|
|
||||
fn fix_incorrect_order() {
|
|
||||
cook_order();
|
|
||||
super::serve_order();
|
|
||||
}
|
|
||||
|
|
||||
fn cook_order() {}
|
|
||||
}
|
|
||||
|
|
||||
// Either absolute:
|
|
||||
// use crate::front_of_house::hosting;
|
|
||||
// or relaive:
|
|
||||
use front_of_house::hosting;
|
|
||||
// we can also provide new names...
|
|
||||
use crate::front_of_house::hosting as host;
|
|
||||
// Public definitions braught into scope with use are
|
|
||||
// private in this scope except we use «pub use»
|
|
||||
pub use front_of_house::hosting as pubhost;
|
|
||||
|
|
||||
pub fn eat_at_restaurant() {
|
|
||||
// Absolute path
|
|
||||
crate::front_of_house::hosting::add_to_waitlist();
|
|
||||
|
|
||||
// Relative path
|
|
||||
front_of_house::hosting::add_to_waitlist();
|
|
||||
|
|
||||
// With use'd path
|
|
||||
hosting::add_to_waitlist();
|
|
||||
|
|
||||
// With renamed used path
|
|
||||
host::add_to_waitlist();
|
|
||||
|
|
||||
pubhost::add_to_waitlist();
|
|
||||
|
|
||||
// Order a breakfast in the summer with Rye toast
|
|
||||
let mut meal = back_of_house::Breakfast::summer("Rye");
|
|
||||
|
|
||||
// Change our mind about what bread we'd like
|
|
||||
meal.toast = String::from("Wheat");
|
|
||||
|
|
||||
println!("I'd like {} toast please", meal.toast);
|
|
||||
|
|
||||
// The next line won't compile if we uncomment it; we're not allowed
|
|
||||
// to see or modify the seasonal fruit that comes with the meal
|
|
||||
// meal.seasonal_fruit = String::from("blueberries");
|
|
||||
|
|
||||
let order1 = back_of_house::Appetizer::Soup;
|
|
||||
let order2 = back_of_house::Appetizer::Salad;
|
|
||||
}
|
|
||||
@ -1,7 +0,0 @@ |
|||||
/target |
|
||||
**/*.rs.bk |
|
||||
Cargo.lock |
|
||||
bin/ |
|
||||
pkg/ |
|
||||
wasm-pack/ |
|
||||
wasm-pack.log |
|
||||
@ -1,69 +0,0 @@ |
|||||
<div align="center"> |
|
||||
|
|
||||
<h1><code>wasm-pack-template</code></h1> |
|
||||
|
|
||||
<strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong> |
|
||||
|
|
||||
<p> |
|
||||
<a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a> |
|
||||
</p> |
|
||||
|
|
||||
<h3> |
|
||||
<a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a> |
|
||||
<span> | </span> |
|
||||
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a> |
|
||||
</h3> |
|
||||
|
|
||||
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub> |
|
||||
</div> |
|
||||
|
|
||||
## About |
|
||||
|
|
||||
[**📚 Read this template tutorial! 📚**][template-docs] |
|
||||
|
|
||||
This template is designed for compiling Rust libraries into WebAssembly and |
|
||||
publishing the resulting package to NPM. |
|
||||
|
|
||||
Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other |
|
||||
templates and usages of `wasm-pack`. |
|
||||
|
|
||||
[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html |
|
||||
[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html |
|
||||
|
|
||||
## 🚴 Usage |
|
||||
|
|
||||
### 🐑 Use `cargo generate` to Clone this Template |
|
||||
|
|
||||
[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) |
|
||||
|
|
||||
``` |
|
||||
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project |
|
||||
cd my-project |
|
||||
``` |
|
||||
|
|
||||
### 🛠️ Build with `wasm-pack build` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack build |
|
||||
``` |
|
||||
|
|
||||
### 🔬 Test in Headless Browsers with `wasm-pack test` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack test --headless --firefox |
|
||||
``` |
|
||||
|
|
||||
### 🎁 Publish to NPM with `wasm-pack publish` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack publish |
|
||||
``` |
|
||||
|
|
||||
## 🔋 Batteries Included |
|
||||
|
|
||||
* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating |
|
||||
between WebAssembly and JavaScript. |
|
||||
* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) |
|
||||
for logging panic messages to the developer console. |
|
||||
* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized |
|
||||
for small code size. |
|
||||
@ -1,3 +0,0 @@ |
|||||
{ |
|
||||
"lockfileVersion": 1 |
|
||||
} |
|
||||
@ -1,520 +0,0 @@ |
|||||
//
|
|
||||
// This is an abstraction over a drawing environment.
|
|
||||
// Future note: z-Buffer is described here:
|
|
||||
// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::cmp;
|
|
||||
use std::fmt::{Formatter, Debug, Display, Result};
|
|
||||
use std::ops::{Add, Sub, Div};
|
|
||||
use std::sync::mpsc;
|
|
||||
|
|
||||
pub trait Easel {
|
|
||||
//fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;
|
|
||||
}
|
|
||||
|
|
||||
pub trait Canvas<T> {
|
|
||||
fn init_events(&self);
|
|
||||
fn start_events(&self, tx :mpsc::Sender<i32>);
|
|
||||
|
|
||||
fn width(&self) -> u16;
|
|
||||
fn height(&self) -> u16;
|
|
||||
|
|
||||
fn clear(&mut self);
|
|
||||
fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);
|
|
||||
fn put_text(&self, ofs :Coordinate<T>, s :&str);
|
|
||||
fn set_pixel(&mut self, c :Coordinate<T>, color :u32);
|
|
||||
fn show(&self);
|
|
||||
}
|
|
||||
|
|
||||
pub trait Drawable<T> {
|
|
||||
fn plot(&self) -> Coordinates<T>;
|
|
||||
}
|
|
||||
|
|
||||
pub trait Fillable<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + From<i32> {
|
|
||||
fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
pub struct Coordinate<T>(pub i32, pub i32, pub T);
|
|
||||
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct Coordinates<T>(pub Vec<Coordinate<T>>);
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
pub struct LineIterator<T> where T: Debug {
|
|
||||
a :Option<Coordinate<T>>
|
|
||||
, b :Coordinate<T>
|
|
||||
, dx :i32 |
|
||||
, dy :i32 |
|
||||
, dz :T
|
|
||||
, sx :i32 |
|
||||
, sy :i32 |
|
||||
, err :i32 |
|
||||
, only_edges :bool |
|
||||
}
|
|
||||
|
|
||||
impl<T> Iterator for LineIterator<T>
|
|
||||
where T: Add<Output = T> + Debug + Copy + From<i32> {
|
|
||||
type Item = Coordinate<T>;
|
|
||||
|
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||
match self.a {
|
|
||||
None => None,
|
|
||||
Some(a) => {
|
|
||||
let Coordinate(ax, ay, az) = a;
|
|
||||
let Coordinate(bx, by, _) = self.b;
|
|
||||
|
|
||||
if ax != bx || ay != by {
|
|
||||
match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {
|
|
||||
(true, false) => {
|
|
||||
let r = self.a;
|
|
||||
self.a = Some(Coordinate( ax + self.sx
|
|
||||
, ay
|
|
||||
, az + self.dz ));
|
|
||||
self.err = self.err + self.dy;
|
|
||||
if self.only_edges { self.next() } else { r }
|
|
||||
},
|
|
||||
(false, true) => {
|
|
||||
let r = self.a;
|
|
||||
self.a = Some(Coordinate( ax
|
|
||||
, ay + self.sy
|
|
||||
, az + self.dz ));
|
|
||||
self.err = self.err + self.dx;
|
|
||||
r
|
|
||||
},
|
|
||||
_ => {
|
|
||||
let r = self.a;
|
|
||||
self.a = Some(Coordinate( ax + self.sx
|
|
||||
, ay + self.sy
|
|
||||
, az + self.dz ));
|
|
||||
self.err = self.err + self.dx + self.dy;
|
|
||||
r
|
|
||||
},
|
|
||||
}
|
|
||||
} else {
|
|
||||
self.a = None;
|
|
||||
Some(self.b)
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Coordinate<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Clone + Copy + From<i32> {
|
|
||||
fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {
|
|
||||
let Coordinate(ax, ay, az) = self;
|
|
||||
let Coordinate(bx, by, bz) = *b;
|
|
||||
|
|
||||
let dx = (bx - ax).abs();
|
|
||||
let dy = -(by - ay).abs();
|
|
||||
|
|
||||
LineIterator { a: Some(self)
|
|
||||
, b: *b
|
|
||||
, dx: dx
|
|
||||
, dy: dy
|
|
||||
, dz: (bz - az) / cmp::max(dx, -dy).into()
|
|
||||
, sx: if ax < bx { 1 } else { -1 }
|
|
||||
, sy: if ay < by { 1 } else { -1 }
|
|
||||
, err: dx + dy
|
|
||||
, only_edges: only_edges
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn line_iter(self, b :&Self) -> LineIterator<T> {
|
|
||||
self.iter(b, false)
|
|
||||
}
|
|
||||
|
|
||||
fn line(self, b :&Self) -> Vec<Self> {
|
|
||||
self.line_iter(b).collect()
|
|
||||
}
|
|
||||
|
|
||||
fn edge_iter(self, b :&Self) -> LineIterator<T> {
|
|
||||
self.iter(b, true)
|
|
||||
}
|
|
||||
|
|
||||
fn edge(self, b :&Self) -> Vec<Self> {
|
|
||||
self.edge_iter(b).collect()
|
|
||||
}
|
|
||||
|
|
||||
fn face(edges :&[Self]) -> Vec<Self> {
|
|
||||
edges.to_vec()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Coordinate<T> {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
write!(f, "<{},{}>", self.0, self.1)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Coordinates<T> where T: Copy {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
let Coordinates(is) = self;
|
|
||||
|
|
||||
let c = match is[..] {
|
|
||||
[] => String::from(""),
|
|
||||
[a] => format!("{}", a),
|
|
||||
_ => {
|
|
||||
let mut a = format!("{}", is[0]);
|
|
||||
for i in is[1..].iter() {
|
|
||||
a = a + &format!(",{}", i);
|
|
||||
}
|
|
||||
a
|
|
||||
}
|
|
||||
};
|
|
||||
|
|
||||
write!(f, "Coordinates[{}]", c)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
pub struct Point<T>(pub Coordinate<T>);
|
|
||||
|
|
||||
impl<T> Drawable<T> for Point<T> where T: Copy {
|
|
||||
fn plot(&self) -> Coordinates<T> {
|
|
||||
let Point(c) = *self;
|
|
||||
Coordinates(vec!(c))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Point<T> {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
let Point(p) = self;
|
|
||||
write!(f, "Point[{}]", p)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);
|
|
||||
|
|
||||
impl<T> Drawable<T> for Line<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Clone + Copy + From<i32> {
|
|
||||
fn plot(&self) -> Coordinates<T> {
|
|
||||
let Line(a, b) = *self;
|
|
||||
Coordinates(a.line(&b))
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Line<T> {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
let Line(a, b) = self;
|
|
||||
write!(f, "Line[{},{}]", a, b)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct Polyline<T>(pub Coordinates<T>);
|
|
||||
|
|
||||
impl<T> Drawable<T> for Polyline<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Clone + Copy + From<i32> {
|
|
||||
fn plot(&self) -> Coordinates<T> {
|
|
||||
let Polyline(Coordinates(cs)) = self;
|
|
||||
|
|
||||
match cs[..] {
|
|
||||
[] => Coordinates(Vec::<Coordinate<T>>::new()),
|
|
||||
[a] => Coordinates(vec!(a)),
|
|
||||
[a, b] => Coordinates(a.line(&b)),
|
|
||||
_ => {
|
|
||||
let (a, b) = (cs[0], cs[1]);
|
|
||||
let mut r = a.line(&b);
|
|
||||
let mut i = b;
|
|
||||
for j in cs[2..].iter() {
|
|
||||
r.append(&mut i.line(j)[1..].to_vec());
|
|
||||
i = *j;
|
|
||||
}
|
|
||||
Coordinates(r)
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Polyline<T> where T: Copy {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
let Polyline(a) = self;
|
|
||||
write!(f, "PLine[{}]", a)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
enum Direction { Left, Right }
|
|
||||
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct Polygon<T>(pub Coordinates<T>);
|
|
||||
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
enum VertexIteratorMode { Vertex, Edge }
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct VertexIterator<'a,T> where T: Debug {
|
|
||||
p :&'a Polygon<T>,
|
|
||||
top :usize,
|
|
||||
current :Option<usize>,
|
|
||||
edge :Option<LineIterator<T>>,
|
|
||||
mode :VertexIteratorMode,
|
|
||||
direction :Direction,
|
|
||||
}
|
|
||||
|
|
||||
impl<'a,T> VertexIterator<'a,T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + From<i32> {
|
|
||||
fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
|
|
||||
let top = p.vert_min(direction);
|
|
||||
let next = p.next_y(top, direction);
|
|
||||
let edge = match next {
|
|
||||
None => None,
|
|
||||
Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),
|
|
||||
};
|
|
||||
|
|
||||
VertexIterator { p: p
|
|
||||
, top: top
|
|
||||
, current: next
|
|
||||
, edge: edge
|
|
||||
, mode: VertexIteratorMode::Edge
|
|
||||
, direction: direction }
|
|
||||
}
|
|
||||
|
|
||||
fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {
|
|
||||
let top = p.vert_min(direction);
|
|
||||
let next = p.next_y(top, direction);
|
|
||||
|
|
||||
VertexIterator { p: p
|
|
||||
, top: top
|
|
||||
, current: next
|
|
||||
, edge: None |
|
||||
, mode: VertexIteratorMode::Vertex
|
|
||||
, direction: direction }
|
|
||||
}
|
|
||||
|
|
||||
// if this yields "None" we are finished.
|
|
||||
fn next_edge(&mut self) -> Option<LineIterator<T>> {
|
|
||||
let current = self.current?;
|
|
||||
let next = self.p.next_y(current, self.direction)?;
|
|
||||
let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));
|
|
||||
|
|
||||
match edge.next() {
|
|
||||
// It should be impossible that a new edge iterator has no values
|
|
||||
// at all… anyway, just in case I handle it here.
|
|
||||
None => self.next_edge(),
|
|
||||
Some(_) => {
|
|
||||
self.current = Some(next);
|
|
||||
self.edge = Some(edge);
|
|
||||
self.edge
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<'a,T> Iterator for VertexIterator<'a,T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Copy + From<i32> {
|
|
||||
type Item = Coordinate<T>;
|
|
||||
|
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||
match self.mode {
|
|
||||
VertexIteratorMode::Edge => {
|
|
||||
// if for whatever reason edge is "None" finish this iterator.
|
|
||||
let next = self.edge.as_mut()?.next();
|
|
||||
|
|
||||
match next {
|
|
||||
Some(_) => next,
|
|
||||
None => {
|
|
||||
self.next_edge()?;
|
|
||||
self.next()
|
|
||||
},
|
|
||||
}
|
|
||||
},
|
|
||||
VertexIteratorMode::Vertex => {
|
|
||||
let current = self.current?;
|
|
||||
self.current = self.p.next_y(current, self.direction);
|
|
||||
Some(self.p.vertex(current))
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Polygon<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Copy + Debug + From<i32> {
|
|
||||
#[inline]
|
|
||||
fn vertex(&self, v :usize) -> Coordinate<T> {
|
|
||||
let Polygon(Coordinates(cs)) = self;
|
|
||||
cs[v]
|
|
||||
}
|
|
||||
|
|
||||
fn vert_min<'a>(&'a self, d :Direction) -> usize {
|
|
||||
let Polygon(Coordinates(cs)) = self;
|
|
||||
|
|
||||
type ICoord<'a,T> = (usize, &'a Coordinate<T>);
|
|
||||
|
|
||||
// TODO I guess the problem here is that it does not account for the
|
|
||||
// same y vertex on the beggining and the end. So i guess correct
|
|
||||
// would be finding the first one and then dependings on the
|
|
||||
// given direction either search left or right for same y's.
|
|
||||
let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|
|
|
||||
match acc {
|
|
||||
None => Some(x),
|
|
||||
Some(a) => {
|
|
||||
let Coordinate(_, ay, _) = a.1;
|
|
||||
let Coordinate(_, xy, _) = x.1;
|
|
||||
if xy < ay {Some(x)} else {Some(a)}
|
|
||||
},
|
|
||||
};
|
|
||||
|
|
||||
let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;
|
|
||||
let mut next = self.step(min, d);
|
|
||||
|
|
||||
while self.vertex(min).1 == self.vertex(next).1 {
|
|
||||
min = next;
|
|
||||
next = self.step(min, d);
|
|
||||
}
|
|
||||
|
|
||||
min
|
|
||||
}
|
|
||||
|
|
||||
fn left_edge(&self) -> VertexIterator<T> {
|
|
||||
VertexIterator::edge(self, Direction::Left)
|
|
||||
}
|
|
||||
|
|
||||
fn right_edge(&self) -> VertexIterator<T> {
|
|
||||
VertexIterator::edge(self, Direction::Right)
|
|
||||
}
|
|
||||
|
|
||||
fn left_vertices(&self) -> VertexIterator<T> {
|
|
||||
VertexIterator::vertex(self, Direction::Left)
|
|
||||
}
|
|
||||
|
|
||||
fn right_vertices(&self) -> VertexIterator<T> {
|
|
||||
VertexIterator::vertex(self, Direction::Right)
|
|
||||
}
|
|
||||
|
|
||||
fn left(&self, v :usize) -> usize {
|
|
||||
let Polygon(Coordinates(cs)) = self;
|
|
||||
|
|
||||
match v {
|
|
||||
0 => cs.len() - 1,
|
|
||||
_ => v - 1,
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn right(&self, v :usize) -> usize {
|
|
||||
let Polygon(Coordinates(cs)) = self;
|
|
||||
|
|
||||
(v + 1) % cs.len()
|
|
||||
}
|
|
||||
|
|
||||
fn step(&self, v :usize, d :Direction) -> usize {
|
|
||||
match d {
|
|
||||
Direction::Left => self.left(v),
|
|
||||
Direction::Right => self.right(v),
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
|
|
||||
fn inner<T>( p :&Polygon<T>
|
|
||||
, c :usize |
|
||||
, n :usize |
|
||||
, d :Direction) -> Option<usize>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Copy + Debug + From<i32> {
|
|
||||
if c == n {
|
|
||||
None
|
|
||||
} else {
|
|
||||
let Coordinate(_, cy, _) = p.vertex(c);
|
|
||||
let Coordinate(_, ny, _) = p.vertex(n);
|
|
||||
|
|
||||
if ny < cy { None } else { Some(n) }
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
inner(self, c, self.step(c, d), d)
|
|
||||
}
|
|
||||
|
|
||||
pub fn debug(&self) {
|
|
||||
let mut left = self.left_vertices();
|
|
||||
let mut right = self.right_vertices();
|
|
||||
|
|
||||
if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {
|
|
||||
let left :Vec<Coordinate<T>> = self.left_vertices().collect();
|
|
||||
let right :Vec<Coordinate<T>> = self.right_vertices().collect();
|
|
||||
|
|
||||
println!("===");
|
|
||||
println!("== poly : {:?}", self);
|
|
||||
println!("== ltop : {:?}", self.vert_min(Direction::Left));
|
|
||||
println!("== rtop : {:?}", self.vert_min(Direction::Right));
|
|
||||
println!("== left : {:?}", left);
|
|
||||
println!("== right : {:?}", right);
|
|
||||
println!("===");
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Drawable<T> for Polygon<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Clone + Copy + From<i32> {
|
|
||||
fn plot(&self) -> Coordinates<T> {
|
|
||||
let Polygon(Coordinates(cs)) = self;
|
|
||||
|
|
||||
match cs[..] {
|
|
||||
[] => Coordinates(Vec::<Coordinate<T>>::new()),
|
|
||||
[a] => Coordinates(vec!(a)),
|
|
||||
[a, b] => Coordinates(a.line(&b)),
|
|
||||
_ => {
|
|
||||
let (a, b) = (cs[0], cs[1]);
|
|
||||
let mut r = a.line(&b);
|
|
||||
let mut i = b;
|
|
||||
for j in cs[2..].iter() {
|
|
||||
r.append(&mut i.line(j)[1..].to_vec());
|
|
||||
i = *j;
|
|
||||
}
|
|
||||
let mut j = a.line(&i);
|
|
||||
let l = j.len();
|
|
||||
if l > 1 {
|
|
||||
r.append(&mut j[1..l-1].to_vec());
|
|
||||
}
|
|
||||
Coordinates(r)
|
|
||||
},
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Fillable<T> for Polygon<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Clone + Copy + From<i32> {
|
|
||||
fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {
|
|
||||
let scanlines = self.left_edge().zip(self.right_edge());
|
|
||||
|
|
||||
for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {
|
|
||||
canvas.set_pixel(l, color);
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Polygon<T> where T: Copy {
|
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
|
||||
let Polygon(a) = self;
|
|
||||
write!(f, "Poly[{}]", a)
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,186 +0,0 @@ |
|||||
//
|
|
||||
// Transformation of vectors in a given coordinate system...
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::ops::{Add, Sub, Neg, Mul, Div};
|
|
||||
use std::fmt::Debug;
|
|
||||
|
|
||||
use crate::Vector;
|
|
||||
use crate::trigonometry::Trig;
|
|
||||
|
|
||||
#[derive(Debug, Clone, Copy)]
|
|
||||
pub struct TMatrix<T>( (T, T, T, T)
|
|
||||
, (T, T, T, T)
|
|
||||
, (T, T, T, T)
|
|
||||
, (T, T, T, T) )
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;
|
|
||||
|
|
||||
pub trait Transformable<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy {
|
|
||||
fn transform(&self, m :&TMatrix<T>) -> Self;
|
|
||||
}
|
|
||||
|
|
||||
impl<T> TMatrix<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Trig + From<i32> + Copy {
|
|
||||
pub fn new( r1 :(T, T, T, T)
|
|
||||
, r2 :(T, T, T, T)
|
|
||||
, r3 :(T, T, T, T)
|
|
||||
, r4 :(T, T, T, T) ) -> Self {
|
|
||||
TMatrix(r1, r2, r3, r4)
|
|
||||
}
|
|
||||
|
|
||||
pub fn unit() -> Self {
|
|
||||
Self::new( (1.into(), 0.into(), 0.into(), 0.into())
|
|
||||
, (0.into(), 1.into(), 0.into(), 0.into())
|
|
||||
, (0.into(), 0.into(), 1.into(), 0.into())
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn translate(v :Vector<T>) -> Self {
|
|
||||
let Vector(x, y, z) = v;
|
|
||||
|
|
||||
Self::new( (1.into(), 0.into(), 0.into(), x)
|
|
||||
, (0.into(), 1.into(), 0.into(), y)
|
|
||||
, (0.into(), 0.into(), 1.into(), z)
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn rotate_x(a :i32) -> Self {
|
|
||||
let sin :T = Trig::sin(a);
|
|
||||
let cos :T = Trig::cos(a);
|
|
||||
|
|
||||
Self::new( (1.into(), 0.into(), 0.into(), 0.into())
|
|
||||
, (0.into(), cos , -sin , 0.into())
|
|
||||
, (0.into(), sin , cos , 0.into())
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn rotate_y(a :i32) -> Self {
|
|
||||
let sin :T = Trig::sin(a);
|
|
||||
let cos :T = Trig::cos(a);
|
|
||||
|
|
||||
Self::new( (cos , 0.into(), sin , 0.into())
|
|
||||
, (0.into(), 1.into(), 0.into(), 0.into())
|
|
||||
, (-sin , 0.into(), cos , 0.into())
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn rotate_z(a :i32) -> Self {
|
|
||||
let sin :T = Trig::sin(a);
|
|
||||
let cos :T = Trig::cos(a);
|
|
||||
|
|
||||
Self::new( (cos , -sin , 0.into(), 0.into())
|
|
||||
, (sin , cos , 0.into(), 0.into())
|
|
||||
, (0.into(), 0.into(), 1.into(), 0.into())
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn rotate_v(v :&Vector<T>, a :i32) -> Self {
|
|
||||
let Vector(x, y, z) = *v;
|
|
||||
|
|
||||
let sin :T = Trig::sin(a);
|
|
||||
let cos :T = Trig::cos(a);
|
|
||||
|
|
||||
let zero :T = 0.into();
|
|
||||
let one :T = 1.into();
|
|
||||
|
|
||||
Self::new( ( (one - cos) * x * x + cos
|
|
||||
, (one - cos) * x * y - sin * z
|
|
||||
, (one - cos) * x * z + sin * y
|
|
||||
, zero )
|
|
||||
, ( (one - cos) * x * y + sin * z
|
|
||||
, (one - cos) * y * y + cos
|
|
||||
, (one - cos) * y * z - sin * x
|
|
||||
, zero )
|
|
||||
, ( (one - cos) * x * z - sin * y
|
|
||||
, (one - cos) * y * z + sin * x
|
|
||||
, (one - cos) * z * z + cos
|
|
||||
, zero )
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn scale(v :Vector<T>) -> Self {
|
|
||||
let Vector(x, y, z) = v;
|
|
||||
|
|
||||
Self::new( ( x, 0.into(), 0.into(), 0.into())
|
|
||||
, (0.into(), y, 0.into(), 0.into())
|
|
||||
, (0.into(), 0.into(), z, 0.into())
|
|
||||
, (0.into(), 0.into(), 0.into(), 1.into()) )
|
|
||||
}
|
|
||||
|
|
||||
pub fn combine<I>(mi :I) -> TMatrix<T>
|
|
||||
where I: IntoIterator<Item = TMatrix<T>> {
|
|
||||
|
|
||||
mi.into_iter().fold(Self::unit(), |acc, x| x * acc)
|
|
||||
}
|
|
||||
|
|
||||
pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {
|
|
||||
let TMatrix( (a11, a12, a13, a14)
|
|
||||
, (a21, a22, a23, a24)
|
|
||||
, (a31, a32, a33, a34)
|
|
||||
, (a41, a42, a43, a44) ) = *self;
|
|
||||
let Vector(x, y, z) = *v;
|
|
||||
|
|
||||
let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w
|
|
||||
, a21 * x + a22 * y + a23 * z + a24 * w
|
|
||||
, a31 * x + a32 * y + a33 * z + a34 * w );
|
|
||||
let w = a41 * x + a42 * y + a43 * z + a44 * w;
|
|
||||
|
|
||||
//v.mul(&w.recip())
|
|
||||
(v, w)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Mul for TMatrix<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Debug + Trig + From<i32> + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
// ATTENTION: This is not commutative, nor assoziative.
|
|
||||
fn mul(self, other :Self) -> Self {
|
|
||||
let TMatrix( (a11, a12, a13, a14)
|
|
||||
, (a21, a22, a23, a24)
|
|
||||
, (a31, a32, a33, a34)
|
|
||||
, (a41, a42, a43, a44) ) = self;
|
|
||||
let TMatrix( (b11, b12, b13, b14)
|
|
||||
, (b21, b22, b23, b24)
|
|
||||
, (b31, b32, b33, b34)
|
|
||||
, (b41, b42, b43, b44) ) = other;
|
|
||||
|
|
||||
TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41
|
|
||||
, a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42
|
|
||||
, a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43
|
|
||||
, a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 )
|
|
||||
, ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41
|
|
||||
, a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42
|
|
||||
, a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43
|
|
||||
, a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 )
|
|
||||
, ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41
|
|
||||
, a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42
|
|
||||
, a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43
|
|
||||
, a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 )
|
|
||||
, ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41
|
|
||||
, a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42
|
|
||||
, a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43
|
|
||||
, a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) )
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,139 +0,0 @@ |
|||||
//
|
|
||||
// Stuff for manipulating 3 dimensional vectors.
|
|
||||
//
|
|
||||
// Georg Hopp <georg@steffers.org>
|
|
||||
//
|
|
||||
// Copyright © 2019 Georg Hopp
|
|
||||
//
|
|
||||
// This program is free software: you can redistribute it and/or modify
|
|
||||
// it under the terms of the GNU General Public License as published by
|
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||
// (at your option) any later version.
|
|
||||
//
|
|
||||
// This program is distributed in the hope that it will be useful,
|
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||
// GNU General Public License for more details.
|
|
||||
//
|
|
||||
// You should have received a copy of the GNU General Public License
|
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||
//
|
|
||||
use std::fmt::{Debug, Display, Formatter, Result};
|
|
||||
use std::ops::{Add, Sub, Neg, Mul, Div};
|
|
||||
|
|
||||
use crate::trigonometry::Trig;
|
|
||||
use crate::transform::{TMatrix, Transformable};
|
|
||||
|
|
||||
#[derive(Debug, Eq, Clone, Copy)]
|
|
||||
pub struct Vector<T>(pub T, pub T, pub T)
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Trig + Copy;
|
|
||||
|
|
||||
impl<T> Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy {
|
|
||||
pub fn x(self) -> T { self.0 }
|
|
||||
pub fn y(self) -> T { self.1 }
|
|
||||
pub fn z(self) -> T { self.2 }
|
|
||||
|
|
||||
pub fn mag(self) -> T {
|
|
||||
let Vector(x, y, z) = self;
|
|
||||
(x * x + y * y + z * z).sqrt().unwrap()
|
|
||||
}
|
|
||||
|
|
||||
pub fn mul(self, s :&T) -> Self {
|
|
||||
let Vector(x, y, z) = self;
|
|
||||
Vector(x * *s, y * *s, z * *s)
|
|
||||
}
|
|
||||
|
|
||||
pub fn dot(self, other :Self) -> T {
|
|
||||
let Vector(x1, y1, z1) = self;
|
|
||||
let Vector(x2, y2, z2) = other;
|
|
||||
|
|
||||
x1 * x2 + y1 * y2 + z1 * z2
|
|
||||
}
|
|
||||
|
|
||||
pub fn norm(self) -> Self {
|
|
||||
// TODO This can result in 0 or inf Vectors…
|
|
||||
// Maybe we need to handle zero and inf magnitude here…
|
|
||||
self.mul(&self.mag().recip())
|
|
||||
}
|
|
||||
|
|
||||
pub fn distance(self, other :Self) -> T {
|
|
||||
(self - other).mag()
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Display for Vector<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Trig + Display + Copy {
|
|
||||
fn fmt(&self, f :&mut Formatter<'_>) -> Result {
|
|
||||
let Vector(x, y, z) = self;
|
|
||||
write!(f, "({}, {}, {})", x, y, z)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> PartialEq for Vector<T>
|
|
||||
where T: Add + Sub + Neg + Mul + Div + Trig + PartialEq + Copy {
|
|
||||
fn eq(&self, other :&Self) -> bool {
|
|
||||
let Vector(x1, y1, z1) = self;
|
|
||||
let Vector(x2, y2, z2) = other;
|
|
||||
x1 == x2 && y1 == y2 && z1 == z2
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Add for Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn add(self, other :Self) -> Self {
|
|
||||
let Vector(x1, y1, z1) = self;
|
|
||||
let Vector(x2, y2, z2) = other;
|
|
||||
Vector(x1 + x2, y1 + y2, z1 + z2)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Sub for Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn sub(self, other :Self) -> Self {
|
|
||||
self + -other
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Neg for Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn neg(self) -> Self {
|
|
||||
let Vector(x, y, z) = self;
|
|
||||
Self(-x, -y, -z)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Mul for Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T> + Trig + Copy {
|
|
||||
type Output = Self;
|
|
||||
|
|
||||
fn mul(self, other :Self) -> Self {
|
|
||||
let Vector(ax, ay, az) = self;
|
|
||||
let Vector(bx, by, bz) = other;
|
|
||||
|
|
||||
Vector( ay * bz - az * by
|
|
||||
, az * bx - ax * bz
|
|
||||
, ax * by - ay * bx )
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<T> Transformable<T> for Vector<T>
|
|
||||
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
|
|
||||
+ Mul<Output = T> + Div<Output = T>
|
|
||||
+ Trig + Copy + Debug + From<i32> {
|
|
||||
fn transform(&self, m :&TMatrix<T>) -> Self {
|
|
||||
let (v, _) = m.apply(self, 0.into());
|
|
||||
v
|
|
||||
}
|
|
||||
}
|
|
||||
@ -1,6 +0,0 @@ |
|||||
# This file is automatically @generated by Cargo. |
|
||||
# It is not intended for manual editing. |
|
||||
[[package]] |
|
||||
name = "variables" |
|
||||
version = "0.1.0" |
|
||||
|
|
||||
@ -1,9 +0,0 @@ |
|||||
[package] |
|
||||
name = "variables" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
|
||||
|
|
||||
[dependencies] |
|
||||
@ -1,6 +0,0 @@ |
|||||
fn main() {
|
|
||||
let mut x = 5;
|
|
||||
println!("The value of x is: {}", x);
|
|
||||
x = 6;
|
|
||||
println!("The value of x is: {}", x);
|
|
||||
}
|
|
||||
@ -1,11 +0,0 @@ |
|||||
install: |
|
||||
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe |
|
||||
- if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly |
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin |
|
||||
- rustc -V |
|
||||
- cargo -V |
|
||||
|
|
||||
build: false |
|
||||
|
|
||||
test_script: |
|
||||
- cargo test --locked |
|
||||
@ -1,3 +0,0 @@ |
|||||
bin/ |
|
||||
pkg/ |
|
||||
wasm-pack.log |
|
||||
@ -1,69 +0,0 @@ |
|||||
language: rust |
|
||||
sudo: false |
|
||||
|
|
||||
cache: cargo |
|
||||
|
|
||||
matrix: |
|
||||
include: |
|
||||
|
|
||||
# Builds with wasm-pack. |
|
||||
- rust: beta |
|
||||
env: RUST_BACKTRACE=1 |
|
||||
addons: |
|
||||
firefox: latest |
|
||||
chrome: stable |
|
||||
before_script: |
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) |
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) |
|
||||
- cargo install-update -a |
|
||||
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f |
|
||||
script: |
|
||||
- cargo generate --git . --name testing |
|
||||
# Having a broken Cargo.toml (in that it has curlies in fields) anywhere |
|
||||
# in any of our parent dirs is problematic. |
|
||||
- mv Cargo.toml Cargo.toml.tmpl |
|
||||
- cd testing |
|
||||
- wasm-pack build |
|
||||
- wasm-pack test --chrome --firefox --headless |
|
||||
|
|
||||
# Builds on nightly. |
|
||||
- rust: nightly |
|
||||
env: RUST_BACKTRACE=1 |
|
||||
before_script: |
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) |
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) |
|
||||
- cargo install-update -a |
|
||||
- rustup target add wasm32-unknown-unknown |
|
||||
script: |
|
||||
- cargo generate --git . --name testing |
|
||||
- mv Cargo.toml Cargo.toml.tmpl |
|
||||
- cd testing |
|
||||
- cargo check |
|
||||
- cargo check --target wasm32-unknown-unknown |
|
||||
- cargo check --no-default-features |
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features |
|
||||
- cargo check --no-default-features --features console_error_panic_hook |
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook |
|
||||
- cargo check --no-default-features --features "console_error_panic_hook wee_alloc" |
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc" |
|
||||
|
|
||||
# Builds on beta. |
|
||||
- rust: beta |
|
||||
env: RUST_BACKTRACE=1 |
|
||||
before_script: |
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) |
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) |
|
||||
- cargo install-update -a |
|
||||
- rustup target add wasm32-unknown-unknown |
|
||||
script: |
|
||||
- cargo generate --git . --name testing |
|
||||
- mv Cargo.toml Cargo.toml.tmpl |
|
||||
- cd testing |
|
||||
- cargo check |
|
||||
- cargo check --target wasm32-unknown-unknown |
|
||||
- cargo check --no-default-features |
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features |
|
||||
- cargo check --no-default-features --features console_error_panic_hook |
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook |
|
||||
# Note: no enabling the `wee_alloc` feature here because it requires |
|
||||
# nightly for now. |
|
||||
@ -1,34 +0,0 @@ |
|||||
[package] |
|
||||
name = "wasm-game-of-life" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
[lib] |
|
||||
crate-type = ["cdylib", "rlib"] |
|
||||
|
|
||||
[features] |
|
||||
default = ["console_error_panic_hook"] |
|
||||
|
|
||||
[dependencies] |
|
||||
wasm-bindgen = "0.2" |
|
||||
|
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by |
|
||||
# logging them with `console.error`. This is great for development, but requires |
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for |
|
||||
# code size when deploying. |
|
||||
console_error_panic_hook = { version = "0.1.1", optional = true } |
|
||||
|
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size |
|
||||
# compared to the default allocator's ~10K. It is slower than the default |
|
||||
# allocator, however. |
|
||||
# |
|
||||
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. |
|
||||
wee_alloc = { version = "0.4.2", optional = true } |
|
||||
|
|
||||
[dev-dependencies] |
|
||||
wasm-bindgen-test = "0.2" |
|
||||
|
|
||||
[profile.release] |
|
||||
# Tell `rustc` to optimize for small code size. |
|
||||
opt-level = "s" |
|
||||
@ -1,176 +0,0 @@ |
|||||
Apache License |
|
||||
Version 2.0, January 2004 |
|
||||
http://www.apache.org/licenses/ |
|
||||
|
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
||||
|
|
||||
1. Definitions. |
|
||||
|
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
|
||||
and distribution as defined by Sections 1 through 9 of this document. |
|
||||
|
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
|
||||
the copyright owner that is granting the License. |
|
||||
|
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
|
||||
other entities that control, are controlled by, or are under common |
|
||||
control with that entity. For the purposes of this definition, |
|
||||
"control" means (i) the power, direct or indirect, to cause the |
|
||||
direction or management of such entity, whether by contract or |
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
|
||||
|
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
|
||||
exercising permissions granted by this License. |
|
||||
|
|
||||
"Source" form shall mean the preferred form for making modifications, |
|
||||
including but not limited to software source code, documentation |
|
||||
source, and configuration files. |
|
||||
|
|
||||
"Object" form shall mean any form resulting from mechanical |
|
||||
transformation or translation of a Source form, including but |
|
||||
not limited to compiled object code, generated documentation, |
|
||||
and conversions to other media types. |
|
||||
|
|
||||
"Work" shall mean the work of authorship, whether in Source or |
|
||||
Object form, made available under the License, as indicated by a |
|
||||
copyright notice that is included in or attached to the work |
|
||||
(an example is provided in the Appendix below). |
|
||||
|
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
|
||||
form, that is based on (or derived from) the Work and for which the |
|
||||
editorial revisions, annotations, elaborations, or other modifications |
|
||||
represent, as a whole, an original work of authorship. For the purposes |
|
||||
of this License, Derivative Works shall not include works that remain |
|
||||
separable from, or merely link (or bind by name) to the interfaces of, |
|
||||
the Work and Derivative Works thereof. |
|
||||
|
|
||||
"Contribution" shall mean any work of authorship, including |
|
||||
the original version of the Work and any modifications or additions |
|
||||
to that Work or Derivative Works thereof, that is intentionally |
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
|
||||
or by an individual or Legal Entity authorized to submit on behalf of |
|
||||
the copyright owner. For the purposes of this definition, "submitted" |
|
||||
means any form of electronic, verbal, or written communication sent |
|
||||
to the Licensor or its representatives, including but not limited to |
|
||||
communication on electronic mailing lists, source code control systems, |
|
||||
and issue tracking systems that are managed by, or on behalf of, the |
|
||||
Licensor for the purpose of discussing and improving the Work, but |
|
||||
excluding communication that is conspicuously marked or otherwise |
|
||||
designated in writing by the copyright owner as "Not a Contribution." |
|
||||
|
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|
||||
on behalf of whom a Contribution has been received by Licensor and |
|
||||
subsequently incorporated within the Work. |
|
||||
|
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
|
||||
this License, each Contributor hereby grants to You a perpetual, |
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
||||
copyright license to reproduce, prepare Derivative Works of, |
|
||||
publicly display, publicly perform, sublicense, and distribute the |
|
||||
Work and such Derivative Works in Source or Object form. |
|
||||
|
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
|
||||
this License, each Contributor hereby grants to You a perpetual, |
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
||||
(except as stated in this section) patent license to make, have made, |
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|
||||
where such license applies only to those patent claims licensable |
|
||||
by such Contributor that are necessarily infringed by their |
|
||||
Contribution(s) alone or by combination of their Contribution(s) |
|
||||
with the Work to which such Contribution(s) was submitted. If You |
|
||||
institute patent litigation against any entity (including a |
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
||||
or a Contribution incorporated within the Work constitutes direct |
|
||||
or contributory patent infringement, then any patent licenses |
|
||||
granted to You under this License for that Work shall terminate |
|
||||
as of the date such litigation is filed. |
|
||||
|
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
|
||||
Work or Derivative Works thereof in any medium, with or without |
|
||||
modifications, and in Source or Object form, provided that You |
|
||||
meet the following conditions: |
|
||||
|
|
||||
(a) You must give any other recipients of the Work or |
|
||||
Derivative Works a copy of this License; and |
|
||||
|
|
||||
(b) You must cause any modified files to carry prominent notices |
|
||||
stating that You changed the files; and |
|
||||
|
|
||||
(c) You must retain, in the Source form of any Derivative Works |
|
||||
that You distribute, all copyright, patent, trademark, and |
|
||||
attribution notices from the Source form of the Work, |
|
||||
excluding those notices that do not pertain to any part of |
|
||||
the Derivative Works; and |
|
||||
|
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
|
||||
distribution, then any Derivative Works that You distribute must |
|
||||
include a readable copy of the attribution notices contained |
|
||||
within such NOTICE file, excluding those notices that do not |
|
||||
pertain to any part of the Derivative Works, in at least one |
|
||||
of the following places: within a NOTICE text file distributed |
|
||||
as part of the Derivative Works; within the Source form or |
|
||||
documentation, if provided along with the Derivative Works; or, |
|
||||
within a display generated by the Derivative Works, if and |
|
||||
wherever such third-party notices normally appear. The contents |
|
||||
of the NOTICE file are for informational purposes only and |
|
||||
do not modify the License. You may add Your own attribution |
|
||||
notices within Derivative Works that You distribute, alongside |
|
||||
or as an addendum to the NOTICE text from the Work, provided |
|
||||
that such additional attribution notices cannot be construed |
|
||||
as modifying the License. |
|
||||
|
|
||||
You may add Your own copyright statement to Your modifications and |
|
||||
may provide additional or different license terms and conditions |
|
||||
for use, reproduction, or distribution of Your modifications, or |
|
||||
for any such Derivative Works as a whole, provided Your use, |
|
||||
reproduction, and distribution of the Work otherwise complies with |
|
||||
the conditions stated in this License. |
|
||||
|
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|
||||
any Contribution intentionally submitted for inclusion in the Work |
|
||||
by You to the Licensor shall be under the terms and conditions of |
|
||||
this License, without any additional terms or conditions. |
|
||||
Notwithstanding the above, nothing herein shall supersede or modify |
|
||||
the terms of any separate license agreement you may have executed |
|
||||
with Licensor regarding such Contributions. |
|
||||
|
|
||||
6. Trademarks. This License does not grant permission to use the trade |
|
||||
names, trademarks, service marks, or product names of the Licensor, |
|
||||
except as required for reasonable and customary use in describing the |
|
||||
origin of the Work and reproducing the content of the NOTICE file. |
|
||||
|
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
|
||||
agreed to in writing, Licensor provides the Work (and each |
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
||||
implied, including, without limitation, any warranties or conditions |
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|
||||
appropriateness of using or redistributing the Work and assume any |
|
||||
risks associated with Your exercise of permissions under this License. |
|
||||
|
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
|
||||
whether in tort (including negligence), contract, or otherwise, |
|
||||
unless required by applicable law (such as deliberate and grossly |
|
||||
negligent acts) or agreed to in writing, shall any Contributor be |
|
||||
liable to You for damages, including any direct, indirect, special, |
|
||||
incidental, or consequential damages of any character arising as a |
|
||||
result of this License or out of the use or inability to use the |
|
||||
Work (including but not limited to damages for loss of goodwill, |
|
||||
work stoppage, computer failure or malfunction, or any and all |
|
||||
other commercial damages or losses), even if such Contributor |
|
||||
has been advised of the possibility of such damages. |
|
||||
|
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
|
||||
the Work or Derivative Works thereof, You may choose to offer, |
|
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
|
||||
or other liability obligations and/or rights consistent with this |
|
||||
License. However, in accepting such obligations, You may act only |
|
||||
on Your own behalf and on Your sole responsibility, not on behalf |
|
||||
of any other Contributor, and only if You agree to indemnify, |
|
||||
defend, and hold each Contributor harmless for any liability |
|
||||
incurred by, or claims asserted against, such Contributor by reason |
|
||||
of your accepting any such warranty or additional liability. |
|
||||
|
|
||||
END OF TERMS AND CONDITIONS |
|
||||
@ -1,25 +0,0 @@ |
|||||
Copyright (c) 2018 Georg Hopp <georg@steffers.org> |
|
||||
|
|
||||
Permission is hereby granted, free of charge, to any |
|
||||
person obtaining a copy of this software and associated |
|
||||
documentation files (the "Software"), to deal in the |
|
||||
Software without restriction, including without |
|
||||
limitation the rights to use, copy, modify, merge, |
|
||||
publish, distribute, sublicense, and/or sell copies of |
|
||||
the Software, and to permit persons to whom the Software |
|
||||
is furnished to do so, subject to the following |
|
||||
conditions: |
|
||||
|
|
||||
The above copyright notice and this permission notice |
|
||||
shall be included in all copies or substantial portions |
|
||||
of the Software. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
||||
DEALINGS IN THE SOFTWARE. |
|
||||
@ -1,69 +0,0 @@ |
|||||
<div align="center"> |
|
||||
|
|
||||
<h1><code>wasm-pack-template</code></h1> |
|
||||
|
|
||||
<strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong> |
|
||||
|
|
||||
<p> |
|
||||
<a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a> |
|
||||
</p> |
|
||||
|
|
||||
<h3> |
|
||||
<a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a> |
|
||||
<span> | </span> |
|
||||
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a> |
|
||||
</h3> |
|
||||
|
|
||||
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub> |
|
||||
</div> |
|
||||
|
|
||||
## About |
|
||||
|
|
||||
[**📚 Read this template tutorial! 📚**][template-docs] |
|
||||
|
|
||||
This template is designed for compiling Rust libraries into WebAssembly and |
|
||||
publishing the resulting package to NPM. |
|
||||
|
|
||||
Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other |
|
||||
templates and usages of `wasm-pack`. |
|
||||
|
|
||||
[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html |
|
||||
[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html |
|
||||
|
|
||||
## 🚴 Usage |
|
||||
|
|
||||
### 🐑 Use `cargo generate` to Clone this Template |
|
||||
|
|
||||
[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) |
|
||||
|
|
||||
``` |
|
||||
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project |
|
||||
cd my-project |
|
||||
``` |
|
||||
|
|
||||
### 🛠️ Build with `wasm-pack build` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack build |
|
||||
``` |
|
||||
|
|
||||
### 🔬 Test in Headless Browsers with `wasm-pack test` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack test --headless --firefox |
|
||||
``` |
|
||||
|
|
||||
### 🎁 Publish to NPM with `wasm-pack publish` |
|
||||
|
|
||||
``` |
|
||||
wasm-pack publish |
|
||||
``` |
|
||||
|
|
||||
## 🔋 Batteries Included |
|
||||
|
|
||||
* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating |
|
||||
between WebAssembly and JavaScript. |
|
||||
* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) |
|
||||
for logging panic messages to the developer console. |
|
||||
* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized |
|
||||
for small code size. |
|
||||
@ -1,3 +0,0 @@ |
|||||
{ |
|
||||
"lockfileVersion": 1 |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
mod utils;
|
|
||||
|
|
||||
use wasm_bindgen::prelude::*;
|
|
||||
|
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
|
||||
// allocator.
|
|
||||
#[cfg(feature = "wee_alloc")]
|
|
||||
#[global_allocator]
|
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
|
||||
|
|
||||
#[wasm_bindgen]
|
|
||||
extern {
|
|
||||
fn alert(s: &str);
|
|
||||
}
|
|
||||
|
|
||||
#[wasm_bindgen]
|
|
||||
pub fn greet(name: &str) {
|
|
||||
alert(&format!("Hello, wasm-game-of-life! {}", name));
|
|
||||
}
|
|
||||
@ -1,10 +0,0 @@ |
|||||
pub fn set_panic_hook() {
|
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
|
||||
// we will get better error messages if our code ever panics.
|
|
||||
//
|
|
||||
// For more details see
|
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
|
||||
console_error_panic_hook::set_once();
|
|
||||
}
|
|
||||
@ -1,13 +0,0 @@ |
|||||
//! Test suite for the Web and headless browsers.
|
|
||||
|
|
||||
#![cfg(target_arch = "wasm32")]
|
|
||||
|
|
||||
extern crate wasm_bindgen_test;
|
|
||||
use wasm_bindgen_test::*;
|
|
||||
|
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
|
||||
|
|
||||
#[wasm_bindgen_test]
|
|
||||
fn pass() {
|
|
||||
assert_eq!(1 + 1, 2);
|
|
||||
}
|
|
||||
@ -1,24 +0,0 @@ |
|||||
#!/usr/bin/env node
|
|
||||
|
|
||||
const { spawn } = require("child_process"); |
|
||||
const fs = require("fs"); |
|
||||
|
|
||||
let folderName = '.'; |
|
||||
|
|
||||
if (process.argv.length >= 3) { |
|
||||
folderName = process.argv[2]; |
|
||||
if (!fs.existsSync(folderName)) { |
|
||||
fs.mkdirSync(folderName); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]); |
|
||||
|
|
||||
clone.on("close", code => { |
|
||||
if (code !== 0) { |
|
||||
console.error("cloning the template failed!") |
|
||||
process.exit(code); |
|
||||
} else { |
|
||||
console.log("🦀 Rust + 🕸 Wasm = ❤"); |
|
||||
} |
|
||||
}); |
|
||||
@ -1,2 +0,0 @@ |
|||||
node_modules |
|
||||
dist |
|
||||
@ -1,5 +0,0 @@ |
|||||
language: node_js |
|
||||
node_js: "10" |
|
||||
|
|
||||
script: |
|
||||
- ./node_modules/.bin/webpack |
|
||||
@ -1,201 +0,0 @@ |
|||||
Apache License |
|
||||
Version 2.0, January 2004 |
|
||||
http://www.apache.org/licenses/ |
|
||||
|
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
||||
|
|
||||
1. Definitions. |
|
||||
|
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
|
||||
and distribution as defined by Sections 1 through 9 of this document. |
|
||||
|
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
|
||||
the copyright owner that is granting the License. |
|
||||
|
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
|
||||
other entities that control, are controlled by, or are under common |
|
||||
control with that entity. For the purposes of this definition, |
|
||||
"control" means (i) the power, direct or indirect, to cause the |
|
||||
direction or management of such entity, whether by contract or |
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
|
||||
|
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
|
||||
exercising permissions granted by this License. |
|
||||
|
|
||||
"Source" form shall mean the preferred form for making modifications, |
|
||||
including but not limited to software source code, documentation |
|
||||
source, and configuration files. |
|
||||
|
|
||||
"Object" form shall mean any form resulting from mechanical |
|
||||
transformation or translation of a Source form, including but |
|
||||
not limited to compiled object code, generated documentation, |
|
||||
and conversions to other media types. |
|
||||
|
|
||||
"Work" shall mean the work of authorship, whether in Source or |
|
||||
Object form, made available under the License, as indicated by a |
|
||||
copyright notice that is included in or attached to the work |
|
||||
(an example is provided in the Appendix below). |
|
||||
|
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
|
||||
form, that is based on (or derived from) the Work and for which the |
|
||||
editorial revisions, annotations, elaborations, or other modifications |
|
||||
represent, as a whole, an original work of authorship. For the purposes |
|
||||
of this License, Derivative Works shall not include works that remain |
|
||||
separable from, or merely link (or bind by name) to the interfaces of, |
|
||||
the Work and Derivative Works thereof. |
|
||||
|
|
||||
"Contribution" shall mean any work of authorship, including |
|
||||
the original version of the Work and any modifications or additions |
|
||||
to that Work or Derivative Works thereof, that is intentionally |
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
|
||||
or by an individual or Legal Entity authorized to submit on behalf of |
|
||||
the copyright owner. For the purposes of this definition, "submitted" |
|
||||
means any form of electronic, verbal, or written communication sent |
|
||||
to the Licensor or its representatives, including but not limited to |
|
||||
communication on electronic mailing lists, source code control systems, |
|
||||
and issue tracking systems that are managed by, or on behalf of, the |
|
||||
Licensor for the purpose of discussing and improving the Work, but |
|
||||
excluding communication that is conspicuously marked or otherwise |
|
||||
designated in writing by the copyright owner as "Not a Contribution." |
|
||||
|
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|
||||
on behalf of whom a Contribution has been received by Licensor and |
|
||||
subsequently incorporated within the Work. |
|
||||
|
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
|
||||
this License, each Contributor hereby grants to You a perpetual, |
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
||||
copyright license to reproduce, prepare Derivative Works of, |
|
||||
publicly display, publicly perform, sublicense, and distribute the |
|
||||
Work and such Derivative Works in Source or Object form. |
|
||||
|
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
|
||||
this License, each Contributor hereby grants to You a perpetual, |
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
||||
(except as stated in this section) patent license to make, have made, |
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|
||||
where such license applies only to those patent claims licensable |
|
||||
by such Contributor that are necessarily infringed by their |
|
||||
Contribution(s) alone or by combination of their Contribution(s) |
|
||||
with the Work to which such Contribution(s) was submitted. If You |
|
||||
institute patent litigation against any entity (including a |
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
||||
or a Contribution incorporated within the Work constitutes direct |
|
||||
or contributory patent infringement, then any patent licenses |
|
||||
granted to You under this License for that Work shall terminate |
|
||||
as of the date such litigation is filed. |
|
||||
|
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
|
||||
Work or Derivative Works thereof in any medium, with or without |
|
||||
modifications, and in Source or Object form, provided that You |
|
||||
meet the following conditions: |
|
||||
|
|
||||
(a) You must give any other recipients of the Work or |
|
||||
Derivative Works a copy of this License; and |
|
||||
|
|
||||
(b) You must cause any modified files to carry prominent notices |
|
||||
stating that You changed the files; and |
|
||||
|
|
||||
(c) You must retain, in the Source form of any Derivative Works |
|
||||
that You distribute, all copyright, patent, trademark, and |
|
||||
attribution notices from the Source form of the Work, |
|
||||
excluding those notices that do not pertain to any part of |
|
||||
the Derivative Works; and |
|
||||
|
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
|
||||
distribution, then any Derivative Works that You distribute must |
|
||||
include a readable copy of the attribution notices contained |
|
||||
within such NOTICE file, excluding those notices that do not |
|
||||
pertain to any part of the Derivative Works, in at least one |
|
||||
of the following places: within a NOTICE text file distributed |
|
||||
as part of the Derivative Works; within the Source form or |
|
||||
documentation, if provided along with the Derivative Works; or, |
|
||||
within a display generated by the Derivative Works, if and |
|
||||
wherever such third-party notices normally appear. The contents |
|
||||
of the NOTICE file are for informational purposes only and |
|
||||
do not modify the License. You may add Your own attribution |
|
||||
notices within Derivative Works that You distribute, alongside |
|
||||
or as an addendum to the NOTICE text from the Work, provided |
|
||||
that such additional attribution notices cannot be construed |
|
||||
as modifying the License. |
|
||||
|
|
||||
You may add Your own copyright statement to Your modifications and |
|
||||
may provide additional or different license terms and conditions |
|
||||
for use, reproduction, or distribution of Your modifications, or |
|
||||
for any such Derivative Works as a whole, provided Your use, |
|
||||
reproduction, and distribution of the Work otherwise complies with |
|
||||
the conditions stated in this License. |
|
||||
|
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|
||||
any Contribution intentionally submitted for inclusion in the Work |
|
||||
by You to the Licensor shall be under the terms and conditions of |
|
||||
this License, without any additional terms or conditions. |
|
||||
Notwithstanding the above, nothing herein shall supersede or modify |
|
||||
the terms of any separate license agreement you may have executed |
|
||||
with Licensor regarding such Contributions. |
|
||||
|
|
||||
6. Trademarks. This License does not grant permission to use the trade |
|
||||
names, trademarks, service marks, or product names of the Licensor, |
|
||||
except as required for reasonable and customary use in describing the |
|
||||
origin of the Work and reproducing the content of the NOTICE file. |
|
||||
|
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
|
||||
agreed to in writing, Licensor provides the Work (and each |
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
||||
implied, including, without limitation, any warranties or conditions |
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|
||||
appropriateness of using or redistributing the Work and assume any |
|
||||
risks associated with Your exercise of permissions under this License. |
|
||||
|
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
|
||||
whether in tort (including negligence), contract, or otherwise, |
|
||||
unless required by applicable law (such as deliberate and grossly |
|
||||
negligent acts) or agreed to in writing, shall any Contributor be |
|
||||
liable to You for damages, including any direct, indirect, special, |
|
||||
incidental, or consequential damages of any character arising as a |
|
||||
result of this License or out of the use or inability to use the |
|
||||
Work (including but not limited to damages for loss of goodwill, |
|
||||
work stoppage, computer failure or malfunction, or any and all |
|
||||
other commercial damages or losses), even if such Contributor |
|
||||
has been advised of the possibility of such damages. |
|
||||
|
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
|
||||
the Work or Derivative Works thereof, You may choose to offer, |
|
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
|
||||
or other liability obligations and/or rights consistent with this |
|
||||
License. However, in accepting such obligations, You may act only |
|
||||
on Your own behalf and on Your sole responsibility, not on behalf |
|
||||
of any other Contributor, and only if You agree to indemnify, |
|
||||
defend, and hold each Contributor harmless for any liability |
|
||||
incurred by, or claims asserted against, such Contributor by reason |
|
||||
of your accepting any such warranty or additional liability. |
|
||||
|
|
||||
END OF TERMS AND CONDITIONS |
|
||||
|
|
||||
APPENDIX: How to apply the Apache License to your work. |
|
||||
|
|
||||
To apply the Apache License to your work, attach the following |
|
||||
boilerplate notice, with the fields enclosed by brackets "[]" |
|
||||
replaced with your own identifying information. (Don't include |
|
||||
the brackets!) The text should be enclosed in the appropriate |
|
||||
comment syntax for the file format. We also recommend that a |
|
||||
file or class name and description of purpose be included on the |
|
||||
same "printed page" as the copyright notice for easier |
|
||||
identification within third-party archives. |
|
||||
|
|
||||
Copyright [yyyy] [name of copyright owner] |
|
||||
|
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||
you may not use this file except in compliance with the License. |
|
||||
You may obtain a copy of the License at |
|
||||
|
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
|
|
||||
Unless required by applicable law or agreed to in writing, software |
|
||||
distributed under the License is distributed on an "AS IS" BASIS, |
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||
See the License for the specific language governing permissions and |
|
||||
limitations under the License. |
|
||||
@ -1,25 +0,0 @@ |
|||||
Copyright (c) [year] [name] |
|
||||
|
|
||||
Permission is hereby granted, free of charge, to any |
|
||||
person obtaining a copy of this software and associated |
|
||||
documentation files (the "Software"), to deal in the |
|
||||
Software without restriction, including without |
|
||||
limitation the rights to use, copy, modify, merge, |
|
||||
publish, distribute, sublicense, and/or sell copies of |
|
||||
the Software, and to permit persons to whom the Software |
|
||||
is furnished to do so, subject to the following |
|
||||
conditions: |
|
||||
|
|
||||
The above copyright notice and this permission notice |
|
||||
shall be included in all copies or substantial portions |
|
||||
of the Software. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
||||
DEALINGS IN THE SOFTWARE. |
|
||||
@ -1,67 +0,0 @@ |
|||||
<div align="center"> |
|
||||
|
|
||||
<h1><code>create-wasm-app</code></h1> |
|
||||
|
|
||||
<strong>An <code>npm init</code> template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.</strong> |
|
||||
|
|
||||
<p> |
|
||||
<a href="https://travis-ci.org/rustwasm/create-wasm-app"><img src="https://img.shields.io/travis/rustwasm/create-wasm-app.svg?style=flat-square" alt="Build Status" /></a> |
|
||||
</p> |
|
||||
|
|
||||
<h3> |
|
||||
<a href="#usage">Usage</a> |
|
||||
<span> | </span> |
|
||||
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a> |
|
||||
</h3> |
|
||||
|
|
||||
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub> |
|
||||
</div> |
|
||||
|
|
||||
## About |
|
||||
|
|
||||
This template is designed for depending on NPM packages that contain |
|
||||
Rust-generated WebAssembly and using them to create a Website. |
|
||||
|
|
||||
* Want to create an NPM package with Rust and WebAssembly? [Check out |
|
||||
`wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template) |
|
||||
* Want to make a monorepo-style Website without publishing to NPM? Check out |
|
||||
[`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template) |
|
||||
and/or |
|
||||
[`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template). |
|
||||
|
|
||||
## 🚴 Usage |
|
||||
|
|
||||
``` |
|
||||
npm init wasm-app |
|
||||
``` |
|
||||
|
|
||||
## 🔋 Batteries Included |
|
||||
|
|
||||
- `.gitignore`: ignores `node_modules` |
|
||||
- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you |
|
||||
- `README.md`: the file you are reading now! |
|
||||
- `index.html`: a bare bones html document that includes the webpack bundle |
|
||||
- `index.js`: example js file with a comment showing how to import and use a wasm pkg |
|
||||
- `package.json` and `package-lock.json`: |
|
||||
- pulls in devDependencies for using webpack: |
|
||||
- [`webpack`](https://www.npmjs.com/package/webpack) |
|
||||
- [`webpack-cli`](https://www.npmjs.com/package/webpack-cli) |
|
||||
- [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server) |
|
||||
- defines a `start` script to run `webpack-dev-server` |
|
||||
- `webpack.config.js`: configuration file for bundling your js with webpack |
|
||||
|
|
||||
## License |
|
||||
|
|
||||
Licensed under either of |
|
||||
|
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) |
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
|
||||
|
|
||||
at your option. |
|
||||
|
|
||||
### Contribution |
|
||||
|
|
||||
Unless you explicitly state otherwise, any contribution intentionally |
|
||||
submitted for inclusion in the work by you, as defined in the Apache-2.0 |
|
||||
license, shall be dual licensed as above, without any additional terms or |
|
||||
conditions. |
|
||||
@ -1,5 +0,0 @@ |
|||||
// A dependency graph that contains any wasm must all be imported
|
|
||||
// asynchronously. This `bootstrap.js` file does the single async import, so
|
|
||||
// that no one else needs to worry about it again.
|
|
||||
import("./index.js") |
|
||||
.catch(e => console.error("Error importing `index.js`:", e)); |
|
||||
@ -1,11 +0,0 @@ |
|||||
<!DOCTYPE html> |
|
||||
<html> |
|
||||
<head> |
|
||||
<meta charset="utf-8"> |
|
||||
<title>Hello wasm-pack!</title> |
|
||||
</head> |
|
||||
<body> |
|
||||
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> |
|
||||
<script src="./bootstrap.js"></script> |
|
||||
</body> |
|
||||
</html> |
|
||||
@ -1,3 +0,0 @@ |
|||||
import * as wasm from "wasm-game-of-life"; |
|
||||
|
|
||||
wasm.greet("Georg"); |
|
||||
5859
wasm-game-of-life/www/package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,37 +0,0 @@ |
|||||
{ |
|
||||
"name": "create-wasm-app", |
|
||||
"version": "0.1.0", |
|
||||
"description": "create an app to consume rust-generated wasm packages", |
|
||||
"main": "index.js", |
|
||||
"bin": { |
|
||||
"create-wasm-app": ".bin/create-wasm-app.js" |
|
||||
}, |
|
||||
"scripts": { |
|
||||
"build": "webpack --config webpack.config.js", |
|
||||
"start": "webpack-dev-server" |
|
||||
}, |
|
||||
"repository": { |
|
||||
"type": "git", |
|
||||
"url": "git+https://github.com/rustwasm/create-wasm-app.git" |
|
||||
}, |
|
||||
"keywords": [ |
|
||||
"webassembly", |
|
||||
"wasm", |
|
||||
"rust", |
|
||||
"webpack" |
|
||||
], |
|
||||
"author": "Ashley Williams <ashley666ashley@gmail.com>", |
|
||||
"license": "(MIT OR Apache-2.0)", |
|
||||
"bugs": { |
|
||||
"url": "https://github.com/rustwasm/create-wasm-app/issues" |
|
||||
}, |
|
||||
"homepage": "https://github.com/rustwasm/create-wasm-app#readme", |
|
||||
"devDependencies": { |
|
||||
"wasm-game-of-life": "file:../pkg", |
|
||||
"hello-wasm-pack": "^0.1.0", |
|
||||
"webpack": "^4.29.3", |
|
||||
"webpack-cli": "^3.1.0", |
|
||||
"webpack-dev-server": "^3.1.5", |
|
||||
"copy-webpack-plugin": "^5.0.0" |
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
const CopyWebpackPlugin = require("copy-webpack-plugin"); |
|
||||
const path = require('path'); |
|
||||
|
|
||||
module.exports = { |
|
||||
entry: "./bootstrap.js", |
|
||||
output: { |
|
||||
path: path.resolve(__dirname, "dist"), |
|
||||
filename: "bootstrap.js", |
|
||||
}, |
|
||||
mode: "development", |
|
||||
plugins: [ |
|
||||
new CopyWebpackPlugin(['index.html']) |
|
||||
], |
|
||||
}; |
|
||||
@ -1,2 +0,0 @@ |
|||||
xcbshm |
|
||||
xcbshm2 |
|
||||
@ -1,11 +0,0 @@ |
|||||
[package] |
|
||||
name = "xcb-test" |
|
||||
version = "0.1.0" |
|
||||
authors = ["Georg Hopp <georg@steffers.org>"] |
|
||||
edition = "2018" |
|
||||
|
|
||||
[dependencies] |
|
||||
libc = "0.2" |
|
||||
gl = "0.5.2" |
|
||||
x11 = { version = "2.3", features = ["glx"] } |
|
||||
xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] } |
|
||||
@ -1,12 +0,0 @@ |
|||||
all: xcbshm xcbshm2 |
|
||||
|
|
||||
xcbshm2: xcbshm2.c |
|
||||
gcc -o $@ -lxcb -lxcb-shm -lxcb-image $< |
|
||||
|
|
||||
xcbshm: xcbshm.c |
|
||||
gcc -o $@ -lxcb -lxcb-shm -lxcb-image $< |
|
||||
|
|
||||
.PHONY: clean |
|
||||
|
|
||||
clean: |
|
||||
@rm -f xcbshm xcbshm2 |
|
||||
@ -1,132 +0,0 @@ |
|||||
extern crate xcb;
|
|
||||
|
|
||||
use std::iter::{Iterator};
|
|
||||
use xcb::randr;
|
|
||||
|
|
||||
fn main() {
|
|
||||
|
|
||||
let dpy = ":0";
|
|
||||
let (conn, screen_num) = xcb::Connection::connect(Some(&dpy)).unwrap();
|
|
||||
|
|
||||
let setup = conn.get_setup();
|
|
||||
let screen = setup.roots().nth(screen_num as usize).unwrap();
|
|
||||
|
|
||||
println!("");
|
|
||||
println!("Informations of screen {}:", screen.root());
|
|
||||
println!(" width..........: {}", screen.width_in_pixels());
|
|
||||
println!(" height.........: {}", screen.height_in_pixels());
|
|
||||
println!(" white pixel....: {:x}", screen.white_pixel());
|
|
||||
println!(" black pixel....: {:x}", screen.black_pixel());
|
|
||||
|
|
||||
let window_dummy = conn.generate_id();
|
|
||||
xcb::create_window(
|
|
||||
&conn, 0, window_dummy, screen.root()
|
|
||||
, 0, 0, 1, 1, 0, 0, 0, &[]);
|
|
||||
|
|
||||
conn.flush();
|
|
||||
|
|
||||
let cookie = randr::get_screen_info(&conn, window_dummy);
|
|
||||
let reply = cookie.get_reply().unwrap();
|
|
||||
let sizes = reply.sizes();
|
|
||||
|
|
||||
for (i, size) in sizes.enumerate() {
|
|
||||
if i != 0 { println!(""); }
|
|
||||
println!("size of screen {}:", i+1);
|
|
||||
println!(" {} x {} ({}mm x {}mm)", size.width(), size.height(),
|
|
||||
size.mwidth(), size.mheight());
|
|
||||
}
|
|
||||
|
|
||||
// ====
|
|
||||
|
|
||||
let window = conn.generate_id();
|
|
||||
|
|
||||
let values = [
|
|
||||
(xcb::CW_BACK_PIXEL, screen.white_pixel()),
|
|
||||
(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS),
|
|
||||
];
|
|
||||
|
|
||||
xcb::create_window(&conn,
|
|
||||
xcb::COPY_FROM_PARENT as u8,
|
|
||||
window,
|
|
||||
screen.root(),
|
|
||||
0, 0,
|
|
||||
150, 150,
|
|
||||
10,
|
|
||||
xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
|
|
||||
screen.root_visual(),
|
|
||||
&values);
|
|
||||
|
|
||||
xcb::map_window(&conn, window);
|
|
||||
|
|
||||
let title = "Basic Window";
|
|
||||
// setting title
|
|
||||
xcb::change_property(&conn, xcb::PROP_MODE_REPLACE as u8, window,
|
|
||||
xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 8, title.as_bytes());
|
|
||||
|
|
||||
conn.flush();
|
|
||||
|
|
||||
// retrieving title
|
|
||||
let cookie = xcb::get_property(&conn, false, window, xcb::ATOM_WM_NAME,
|
|
||||
xcb::ATOM_STRING, 0, 1024);
|
|
||||
if let Ok(reply) = cookie.get_reply() {
|
|
||||
assert_eq!(std::str::from_utf8(reply.value()).unwrap(), title);
|
|
||||
} else {
|
|
||||
panic!("could not retrieve window title!");
|
|
||||
}
|
|
||||
|
|
||||
// retrieving a few atoms
|
|
||||
let (wm_state, wm_state_maxv, wm_state_maxh) = {
|
|
||||
let cook = xcb::intern_atom(&conn, true, "_NET_WM_STATE");
|
|
||||
let cook_maxv = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_VERT");
|
|
||||
let cook_maxh = xcb::intern_atom(&conn, true, "_NET_WM_STATE_MAXIMIZED_HORZ");
|
|
||||
|
|
||||
(cook.get_reply().unwrap().atom(),
|
|
||||
cook_maxv.get_reply().unwrap().atom(),
|
|
||||
cook_maxh.get_reply().unwrap().atom())
|
|
||||
};
|
|
||||
|
|
||||
let mut maximized = false;
|
|
||||
|
|
||||
loop {
|
|
||||
let event = conn.wait_for_event();
|
|
||||
match event {
|
|
||||
None => { break; }
|
|
||||
Some(event) => {
|
|
||||
let r = event.response_type();
|
|
||||
if r == xcb::KEY_PRESS as u8 {
|
|
||||
let key_press : &xcb::KeyPressEvent = unsafe {
|
|
||||
xcb::cast_event(&event)
|
|
||||
};
|
|
||||
|
|
||||
println!("Key '{}' pressed", key_press.detail());
|
|
||||
|
|
||||
if key_press.detail() == 0x3a { // M (on qwerty)
|
|
||||
|
|
||||
// toggle maximized
|
|
||||
println!("toggle maximized: {} {}", wm_state_maxv, wm_state_maxh);
|
|
||||
|
|
||||
// ClientMessageData is a memory safe untagged union
|
|
||||
let data = xcb::ClientMessageData::from_data32([
|
|
||||
if maximized { 0 } else { 1 },
|
|
||||
wm_state_maxv, wm_state_maxh,
|
|
||||
0, 0
|
|
||||
]);
|
|
||||
|
|
||||
let ev = xcb::ClientMessageEvent::new(32, window,
|
|
||||
wm_state, data);
|
|
||||
|
|
||||
xcb::send_event(&conn, false, screen.root(),
|
|
||||
xcb::EVENT_MASK_STRUCTURE_NOTIFY, &ev);
|
|
||||
|
|
||||
conn.flush();
|
|
||||
|
|
||||
maximized = !maximized;
|
|
||||
}
|
|
||||
else if key_press.detail() == 0x18 { // Q (on qwerty)
|
|
||||
break;
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
||||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue