Commit 8f79b4d2a8c62271b06fd9f959d01d4d13ff6c9e

Authored by Georg Hopp
1 parent 3087691d

use easel3d crate now

1 [package] 1 [package]
2 -name = "wasm-game-of-life" 2 +name = "easel3d-wasm"
3 version = "0.1.0" 3 version = "0.1.0"
4 authors = ["hopp@silpion.de"] 4 authors = ["hopp@silpion.de"]
5 edition = "2018" 5 edition = "2018"
@@ -7,29 +7,13 @@ edition = "2018" @@ -7,29 +7,13 @@ edition = "2018"
7 [lib] 7 [lib]
8 crate-type = ["cdylib", "rlib"] 8 crate-type = ["cdylib", "rlib"]
9 9
10 -[features]  
11 -default = ["console_error_panic_hook"]  
12 -  
13 [dependencies] 10 [dependencies]
14 wasm-bindgen = "0.2" 11 wasm-bindgen = "0.2"
15 -lazy_static = "1.4.0"  
16 -  
17 -# The `console_error_panic_hook` crate provides better debugging of panics by  
18 -# logging them with `console.error`. This is great for development, but requires  
19 -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for  
20 -# code size when deploying.  
21 -console_error_panic_hook = { version = "0.1.1", optional = true }  
22 -  
23 -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size  
24 -# compared to the default allocator's ~10K. It is slower than the default  
25 -# allocator, however.  
26 -#  
27 -# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. 12 +easel3d = { path = "../easel3d" }
28 wee_alloc = { version = "0.4.2", optional = true } 13 wee_alloc = { version = "0.4.2", optional = true }
29 14
30 [dev-dependencies] 15 [dev-dependencies]
31 wasm-bindgen-test = "0.2" 16 wasm-bindgen-test = "0.2"
32 17
33 [profile.release] 18 [profile.release]
34 -# Tell `rustc` to optimize for small code size.  
35 opt-level = "s" 19 opt-level = "s"
1 -<div align="center"> 1 +# Easel3D-WASM
2 2
3 - <h1><code>wasm-pack-template</code></h1>  
4 -  
5 - <strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>  
6 -  
7 - <p>  
8 - <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>  
9 - </p>  
10 -  
11 - <h3>  
12 - <a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>  
13 - <span> | </span>  
14 - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>  
15 - </h3>  
16 -  
17 - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>  
18 -</div>  
19 -  
20 -## About  
21 -  
22 -[**📚 Read this template tutorial! 📚**][template-docs]  
23 -  
24 -This template is designed for compiling Rust libraries into WebAssembly and  
25 -publishing the resulting package to NPM.  
26 -  
27 -Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other  
28 -templates and usages of `wasm-pack`.  
29 -  
30 -[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html  
31 -[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html  
32 -  
33 -## 🚴 Usage  
34 -  
35 -### 🐑 Use `cargo generate` to Clone this Template  
36 -  
37 -[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)  
38 -  
39 -```  
40 -cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project  
41 -cd my-project  
42 -```  
43 -  
44 -### 🛠️ Build with `wasm-pack build`  
45 -  
46 -```  
47 -wasm-pack build  
48 -```  
49 -  
50 -### 🔬 Test in Headless Browsers with `wasm-pack test`  
51 -  
52 -```  
53 -wasm-pack test --headless --firefox  
54 -```  
55 -  
56 -### 🎁 Publish to NPM with `wasm-pack publish`  
57 -  
58 -```  
59 -wasm-pack publish  
60 -```  
61 -  
62 -## 🔋 Batteries Included  
63 -  
64 -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating  
65 - between WebAssembly and JavaScript.  
66 -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)  
67 - for logging panic messages to the developer console.  
68 -* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized  
69 - for small code size.  
70 -# Rust playground  
71 -  
72 -Things I have recently done while learning the Rust programming language. 3 +WebAssembly demo application using Easel3D...
73 4
74 ## Synopsis 5 ## Synopsis
75 6
76 -Change in one of the toplevel subdirectories and try `cargo build` or  
77 -`cargo run`. Maybe not everything is working oob. Feel free to fix whatever  
78 -you want. 7 +Checkout this repository as well as the _easel3d_ repository to the same
  8 +destination directory.
79 9
80 -## Description 10 +In the root of this repository call `wasm-pack build`.
  11 +Then change to www and call `npm install`.
81 12
82 -Various small examples I have tried while learning rust. The biggest and  
83 -currently most active project is **fractional** which started as an  
84 -implamentation of a rational number data type and then switched to a 3D  
85 -math playground visualizing using **XCB** (in future it might also use  
86 -a **HTML5 Canvas** for drawing as WebAssembly application.  
87 -Using fractions with 3D math has several drawbacks: 13 +To test the stuff call `npm run start` from www directory and in your browser
  14 +open http:://localhost:8080/.
88 15
89 -1. A huge part of 3D math is non rational, like sin, cos, tan and sqrt.  
90 -2. The numerator and denominator tend to become very huge while nearing to non  
91 - rational numbers and reduction is difficult and time consuming.  
92 -3. Because of 2 it is way slower than the floating point calculation (at least  
93 - with a decent coprocessor). 16 +## Description
94 17
95 -Anyway, implementing the vector math stuff for both fractions and floating  
96 -point was a nice playground for generics and traits. In future I might add  
97 -another data type which implements the math as done by David Braben for the  
98 -elite computer game. 18 +A demo application using easel3d to draw in an HTML5 canvas element in a web
  19 +page.
99 20
100 ## Requirements 21 ## Requirements
101 22
102 -### Always  
103 -  
104 - A recent version of the Rust programming language as well as tooling. 23 - A recent version of the Rust programming language as well as tooling.
105 Currently I use Rust 1.39.0. 24 Currently I use Rust 1.39.0.
  25 +- wasm-pack to build to wasm target
  26 +- npm for Javascript code.
  27 +- A browser capable of executing WebAssembly.
106 28
107 -### For fractional 29 +## Dependencies
108 30
109 -- A running X Server with **XCB** and **X11-SHM** extentions 31 +### Rust crates.
110 32
111 -## Dependencies 33 +- easel3d (from parent directory)
  34 +- wasm-bindgen =0.2
  35 +- wee-alloc =0.4.2 (optional)
  36 +
  37 +Along with the dependencies of the external crates. `wasm-pack build` should
  38 +take care of having them available.
  39 +
  40 +### Javascript
112 41
113 -... 42 +Various things npm installs.
114 43
115 ## Contributing 44 ## Contributing
116 45
1 -//  
2 -// This is an abstraction over a drawing environment.  
3 -// Future note: z-Buffer is described here:  
4 -// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes  
5 -//  
6 -// Georg Hopp <georg@steffers.org>  
7 -//  
8 -// Copyright © 2019 Georg Hopp  
9 -//  
10 -// This program is free software: you can redistribute it and/or modify  
11 -// it under the terms of the GNU General Public License as published by  
12 -// the Free Software Foundation, either version 3 of the License, or  
13 -// (at your option) any later version.  
14 -//  
15 -// This program is distributed in the hope that it will be useful,  
16 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
17 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
18 -// GNU General Public License for more details.  
19 -//  
20 -// You should have received a copy of the GNU General Public License  
21 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
22 -//  
23 -use std::cmp;  
24 -use std::fmt::{Formatter, Debug, Display, Result};  
25 -use std::ops::{Add, Sub, Div};  
26 -use std::sync::mpsc;  
27 -  
28 -pub trait Easel {  
29 - //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;  
30 -}  
31 -  
32 -pub trait Canvas<T> {  
33 - fn init_events(&self);  
34 - fn start_events(&self, tx :mpsc::Sender<i32>);  
35 -  
36 - fn width(&self) -> u16;  
37 - fn height(&self) -> u16;  
38 -  
39 - fn clear(&mut self);  
40 - fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);  
41 - fn put_text(&self, ofs :Coordinate<T>, s :&str);  
42 - fn set_pixel(&mut self, c :Coordinate<T>, color :u32);  
43 - fn show(&self);  
44 -}  
45 -  
46 -pub trait Drawable<T> {  
47 - fn plot(&self) -> Coordinates<T>;  
48 -}  
49 -  
50 -pub trait Fillable<T>  
51 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
52 - + Debug + Copy + From<i32> {  
53 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);  
54 -}  
55 -  
56 -#[derive(Debug, Clone, Copy)]  
57 -pub struct Coordinate<T>(pub i32, pub i32, pub T);  
58 -  
59 -#[derive(Debug, Clone)]  
60 -pub struct Coordinates<T>(pub Vec<Coordinate<T>>);  
61 -  
62 -#[derive(Debug, Clone, Copy)]  
63 -pub struct LineIterator<T> where T: Debug {  
64 - a :Option<Coordinate<T>>  
65 - , b :Coordinate<T>  
66 - , dx :i32  
67 - , dy :i32  
68 - , dz :T  
69 - , sx :i32  
70 - , sy :i32  
71 - , err :i32  
72 - , only_edges :bool  
73 -}  
74 -  
75 -impl<T> Iterator for LineIterator<T>  
76 -where T: Add<Output = T> + Debug + Copy + From<i32> {  
77 - type Item = Coordinate<T>;  
78 -  
79 - fn next(&mut self) -> Option<Self::Item> {  
80 - match self.a {  
81 - None => None,  
82 - Some(a) => {  
83 - let Coordinate(ax, ay, az) = a;  
84 - let Coordinate(bx, by, _) = self.b;  
85 -  
86 - if ax != bx || ay != by {  
87 - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {  
88 - (true, false) => {  
89 - let r = self.a;  
90 - self.a = Some(Coordinate( ax + self.sx  
91 - , ay  
92 - , az + self.dz ));  
93 - self.err = self.err + self.dy;  
94 - if self.only_edges { self.next() } else { r }  
95 - },  
96 - (false, true) => {  
97 - let r = self.a;  
98 - self.a = Some(Coordinate( ax  
99 - , ay + self.sy  
100 - , az + self.dz ));  
101 - self.err = self.err + self.dx;  
102 - r  
103 - },  
104 - _ => {  
105 - let r = self.a;  
106 - self.a = Some(Coordinate( ax + self.sx  
107 - , ay + self.sy  
108 - , az + self.dz ));  
109 - self.err = self.err + self.dx + self.dy;  
110 - r  
111 - },  
112 - }  
113 - } else {  
114 - self.a = None;  
115 - Some(self.b)  
116 - }  
117 - }  
118 - }  
119 - }  
120 -}  
121 -  
122 -impl<T> Coordinate<T>  
123 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
124 - + Debug + Clone + Copy + From<i32> {  
125 - fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {  
126 - let Coordinate(ax, ay, az) = self;  
127 - let Coordinate(bx, by, bz) = *b;  
128 -  
129 - let dx = (bx - ax).abs();  
130 - let dy = -(by - ay).abs();  
131 -  
132 - LineIterator { a: Some(self)  
133 - , b: *b  
134 - , dx: dx  
135 - , dy: dy  
136 - , dz: (bz - az) / cmp::max(dx, -dy).into()  
137 - , sx: if ax < bx { 1 } else { -1 }  
138 - , sy: if ay < by { 1 } else { -1 }  
139 - , err: dx + dy  
140 - , only_edges: only_edges  
141 - }  
142 - }  
143 -  
144 - fn line_iter(self, b :&Self) -> LineIterator<T> {  
145 - self.iter(b, false)  
146 - }  
147 -  
148 - fn line(self, b :&Self) -> Vec<Self> {  
149 - self.line_iter(b).collect()  
150 - }  
151 -  
152 - fn edge_iter(self, b :&Self) -> LineIterator<T> {  
153 - self.iter(b, true)  
154 - }  
155 -  
156 - fn edge(self, b :&Self) -> Vec<Self> {  
157 - self.edge_iter(b).collect()  
158 - }  
159 -  
160 - fn face(edges :&[Self]) -> Vec<Self> {  
161 - edges.to_vec()  
162 - }  
163 -}  
164 -  
165 -impl<T> Display for Coordinate<T> {  
166 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
167 - write!(f, "<{},{}>", self.0, self.1)  
168 - }  
169 -}  
170 -  
171 -impl<T> Display for Coordinates<T> where T: Copy {  
172 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
173 - let Coordinates(is) = self;  
174 -  
175 - let c = match is[..] {  
176 - [] => String::from(""),  
177 - [a] => format!("{}", a),  
178 - _ => {  
179 - let mut a = format!("{}", is[0]);  
180 - for i in is[1..].iter() {  
181 - a = a + &format!(",{}", i);  
182 - }  
183 - a  
184 - }  
185 - };  
186 -  
187 - write!(f, "Coordinates[{}]", c)  
188 - }  
189 -}  
190 -  
191 -  
192 -#[derive(Debug, Clone, Copy)]  
193 -pub struct Point<T>(pub Coordinate<T>);  
194 -  
195 -impl<T> Drawable<T> for Point<T> where T: Copy {  
196 - fn plot(&self) -> Coordinates<T> {  
197 - let Point(c) = *self;  
198 - Coordinates(vec!(c))  
199 - }  
200 -}  
201 -  
202 -impl<T> Display for Point<T> {  
203 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
204 - let Point(p) = self;  
205 - write!(f, "Point[{}]", p)  
206 - }  
207 -}  
208 -  
209 -#[derive(Debug, Clone, Copy)]  
210 -pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);  
211 -  
212 -impl<T> Drawable<T> for Line<T>  
213 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
214 - + Debug + Clone + Copy + From<i32> {  
215 - fn plot(&self) -> Coordinates<T> {  
216 - let Line(a, b) = *self;  
217 - Coordinates(a.line(&b))  
218 - }  
219 -}  
220 -  
221 -impl<T> Display for Line<T> {  
222 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
223 - let Line(a, b) = self;  
224 - write!(f, "Line[{},{}]", a, b)  
225 - }  
226 -}  
227 -  
228 -#[derive(Debug, Clone)]  
229 -pub struct Polyline<T>(pub Coordinates<T>);  
230 -  
231 -impl<T> Drawable<T> for Polyline<T>  
232 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
233 - + Debug + Clone + Copy + From<i32> {  
234 - fn plot(&self) -> Coordinates<T> {  
235 - let Polyline(Coordinates(cs)) = self;  
236 -  
237 - match cs[..] {  
238 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
239 - [a] => Coordinates(vec!(a)),  
240 - [a, b] => Coordinates(a.line(&b)),  
241 - _ => {  
242 - let (a, b) = (cs[0], cs[1]);  
243 - let mut r = a.line(&b);  
244 - let mut i = b;  
245 - for j in cs[2..].iter() {  
246 - r.append(&mut i.line(j)[1..].to_vec());  
247 - i = *j;  
248 - }  
249 - Coordinates(r)  
250 - },  
251 - }  
252 - }  
253 -}  
254 -  
255 -impl<T> Display for Polyline<T> where T: Copy {  
256 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
257 - let Polyline(a) = self;  
258 - write!(f, "PLine[{}]", a)  
259 - }  
260 -}  
261 -  
262 -#[derive(Debug, Clone, Copy)]  
263 -enum Direction { Left, Right }  
264 -  
265 -#[derive(Debug, Clone)]  
266 -pub struct Polygon<T>(pub Coordinates<T>);  
267 -  
268 -#[derive(Debug, Clone)]  
269 -enum VertexIteratorMode { Vertex, Edge }  
270 -#[derive(Debug, Clone)]  
271 -pub struct VertexIterator<'a,T> where T: Debug {  
272 - p :&'a Polygon<T>,  
273 - top :usize,  
274 - current :Option<usize>,  
275 - edge :Option<LineIterator<T>>,  
276 - mode :VertexIteratorMode,  
277 - direction :Direction,  
278 -}  
279 -  
280 -impl<'a,T> VertexIterator<'a,T>  
281 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
282 - + Debug + Copy + From<i32> {  
283 - fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {  
284 - let top = p.vert_min(direction);  
285 - let next = p.next_y(top, direction);  
286 - let edge = match next {  
287 - None => None,  
288 - Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),  
289 - };  
290 -  
291 - VertexIterator { p: p  
292 - , top: top  
293 - , current: next  
294 - , edge: edge  
295 - , mode: VertexIteratorMode::Edge  
296 - , direction: direction }  
297 - }  
298 -  
299 - fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {  
300 - let top = p.vert_min(direction);  
301 - let next = p.next_y(top, direction);  
302 -  
303 - VertexIterator { p: p  
304 - , top: top  
305 - , current: next  
306 - , edge: None  
307 - , mode: VertexIteratorMode::Vertex  
308 - , direction: direction }  
309 - }  
310 -  
311 - // if this yields "None" we are finished.  
312 - fn next_edge(&mut self) -> Option<LineIterator<T>> {  
313 - let current = self.current?;  
314 - let next = self.p.next_y(current, self.direction)?;  
315 - let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));  
316 -  
317 - match edge.next() {  
318 - // It should be impossible that a new edge iterator has no values  
319 - // at all… anyway, just in case I handle it here.  
320 - None => self.next_edge(),  
321 - Some(_) => {  
322 - self.current = Some(next);  
323 - self.edge = Some(edge);  
324 - self.edge  
325 - },  
326 - }  
327 - }  
328 -}  
329 -  
330 -impl<'a,T> Iterator for VertexIterator<'a,T>  
331 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
332 - + Debug + Copy + From<i32> {  
333 - type Item = Coordinate<T>;  
334 -  
335 - fn next(&mut self) -> Option<Self::Item> {  
336 - match self.mode {  
337 - VertexIteratorMode::Edge => {  
338 - // if for whatever reason edge is "None" finish this iterator.  
339 - let next = self.edge.as_mut()?.next();  
340 -  
341 - match next {  
342 - Some(_) => next,  
343 - None => {  
344 - self.next_edge()?;  
345 - self.next()  
346 - },  
347 - }  
348 - },  
349 - VertexIteratorMode::Vertex => {  
350 - let current = self.current?;  
351 - self.current = self.p.next_y(current, self.direction);  
352 - Some(self.p.vertex(current))  
353 - },  
354 - }  
355 - }  
356 -}  
357 -  
358 -impl<T> Polygon<T>  
359 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
360 - + Copy + Debug + From<i32> {  
361 - #[inline]  
362 - fn vertex(&self, v :usize) -> Coordinate<T> {  
363 - let Polygon(Coordinates(cs)) = self;  
364 - cs[v]  
365 - }  
366 -  
367 - fn vert_min<'a>(&'a self, d :Direction) -> usize {  
368 - let Polygon(Coordinates(cs)) = self;  
369 -  
370 - type ICoord<'a,T> = (usize, &'a Coordinate<T>);  
371 -  
372 - // TODO I guess the problem here is that it does not account for the  
373 - // same y vertex on the beggining and the end. So i guess correct  
374 - // would be finding the first one and then dependings on the  
375 - // given direction either search left or right for same y's.  
376 - let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|  
377 - match acc {  
378 - None => Some(x),  
379 - Some(a) => {  
380 - let Coordinate(_, ay, _) = a.1;  
381 - let Coordinate(_, xy, _) = x.1;  
382 - if xy < ay {Some(x)} else {Some(a)}  
383 - },  
384 - };  
385 -  
386 - let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;  
387 - let mut next = self.step(min, d);  
388 -  
389 - while self.vertex(min).1 == self.vertex(next).1 {  
390 - min = next;  
391 - next = self.step(min, d);  
392 - }  
393 -  
394 - min  
395 - }  
396 -  
397 - fn left_edge(&self) -> VertexIterator<T> {  
398 - VertexIterator::edge(self, Direction::Left)  
399 - }  
400 -  
401 - fn right_edge(&self) -> VertexIterator<T> {  
402 - VertexIterator::edge(self, Direction::Right)  
403 - }  
404 -  
405 - fn left_vertices(&self) -> VertexIterator<T> {  
406 - VertexIterator::vertex(self, Direction::Left)  
407 - }  
408 -  
409 - fn right_vertices(&self) -> VertexIterator<T> {  
410 - VertexIterator::vertex(self, Direction::Right)  
411 - }  
412 -  
413 - fn left(&self, v :usize) -> usize {  
414 - let Polygon(Coordinates(cs)) = self;  
415 -  
416 - match v {  
417 - 0 => cs.len() - 1,  
418 - _ => v - 1,  
419 - }  
420 - }  
421 -  
422 - fn right(&self, v :usize) -> usize {  
423 - let Polygon(Coordinates(cs)) = self;  
424 -  
425 - (v + 1) % cs.len()  
426 - }  
427 -  
428 - fn step(&self, v :usize, d :Direction) -> usize {  
429 - match d {  
430 - Direction::Left => self.left(v),  
431 - Direction::Right => self.right(v),  
432 - }  
433 - }  
434 -  
435 - fn next_y(&self, c :usize, d :Direction) -> Option<usize> {  
436 - fn inner<T>( p :&Polygon<T>  
437 - , c :usize  
438 - , n :usize  
439 - , d :Direction) -> Option<usize>  
440 - where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
441 - + Copy + Debug + From<i32> {  
442 - if c == n {  
443 - None  
444 - } else {  
445 - let Coordinate(_, cy, _) = p.vertex(c);  
446 - let Coordinate(_, ny, _) = p.vertex(n);  
447 -  
448 - if ny < cy { None } else { Some(n) }  
449 - }  
450 - }  
451 -  
452 - inner(self, c, self.step(c, d), d)  
453 - }  
454 -  
455 - pub fn debug(&self) {  
456 - let mut left = self.left_vertices();  
457 - let mut right = self.right_vertices();  
458 -  
459 - if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {  
460 - let left :Vec<Coordinate<T>> = self.left_vertices().collect();  
461 - let right :Vec<Coordinate<T>> = self.right_vertices().collect();  
462 -  
463 - println!("===");  
464 - println!("== poly : {:?}", self);  
465 - println!("== ltop : {:?}", self.vert_min(Direction::Left));  
466 - println!("== rtop : {:?}", self.vert_min(Direction::Right));  
467 - println!("== left : {:?}", left);  
468 - println!("== right : {:?}", right);  
469 - println!("===");  
470 - }  
471 - }  
472 -}  
473 -  
474 -impl<T> Drawable<T> for Polygon<T>  
475 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
476 - + Debug + Clone + Copy + From<i32> {  
477 - fn plot(&self) -> Coordinates<T> {  
478 - let Polygon(Coordinates(cs)) = self;  
479 -  
480 - match cs[..] {  
481 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
482 - [a] => Coordinates(vec!(a)),  
483 - [a, b] => Coordinates(a.line(&b)),  
484 - _ => {  
485 - let (a, b) = (cs[0], cs[1]);  
486 - let mut r = a.line(&b);  
487 - let mut i = b;  
488 - for j in cs[2..].iter() {  
489 - r.append(&mut i.line(j)[1..].to_vec());  
490 - i = *j;  
491 - }  
492 - let mut j = a.line(&i);  
493 - let l = j.len();  
494 - if l > 1 {  
495 - r.append(&mut j[1..l-1].to_vec());  
496 - }  
497 - Coordinates(r)  
498 - },  
499 - }  
500 - }  
501 -}  
502 -  
503 -impl<T> Fillable<T> for Polygon<T>  
504 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
505 - + Debug + Clone + Copy + From<i32> {  
506 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {  
507 - let scanlines = self.left_edge().zip(self.right_edge());  
508 -  
509 - for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {  
510 - canvas.set_pixel(l, color);  
511 - }  
512 - }  
513 -}  
514 -  
515 -impl<T> Display for Polygon<T> where T: Copy {  
516 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
517 - let Polygon(a) = self;  
518 - write!(f, "Poly[{}]", a)  
519 - }  
520 -}  
  1 +use std::sync::mpsc;
  2 +
  3 +use easel3d::easel::canvas::{Canvas, Vertex};
  4 +use easel3d::easel::drawable::Drawable;
  5 +
  6 +#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  7 +pub struct Color(u8, u8, u8, u8);
  8 +
  9 +pub struct WasmCanvas { width :u16
  10 + , height :u16
  11 + , size :usize
  12 + , zbuf :Vec<f64>
  13 + , image :Vec<Color> }
  14 +
  15 +impl WasmCanvas {
  16 + pub fn new(width :u16, height :u16) -> Self {
  17 + let size = width as usize * height as usize;
  18 +
  19 + Self { width: width
  20 + , height: height
  21 + , size: size
  22 + , zbuf: vec!(0.0; size)
  23 + , image: vec!(Color(0, 0, 0, 0xFF); size) }
  24 + }
  25 +
  26 + pub fn image(&self) -> *const Color {
  27 + self.image.as_ptr()
  28 + }
  29 +}
  30 +
  31 +impl Canvas<f64> for WasmCanvas {
  32 + #[inline]
  33 + fn width(&self) -> u16 {
  34 + self.width
  35 + }
  36 +
  37 + #[inline]
  38 + fn height(&self) -> u16 {
  39 + self.height
  40 + }
  41 +
  42 + fn clear(&mut self) {
  43 + self.zbuf = vec!(0.0; self.size);
  44 + self.image = vec!(Color(0, 0, 0, 0xFF); self.size);
  45 + }
  46 +
  47 + fn set_pixel(&mut self, c :Vertex<f64>, color :u32) {
  48 + let (x, y, zr) = c.as_tuple();
  49 + let idx :usize = (y * (self.width as i32) + x) as usize;
  50 +
  51 + let r = ((color >> 16) & 0xFF) as u8;
  52 + let g = ((color >> 8) & 0xFF) as u8;
  53 + let b = ( color & 0xFF) as u8;
  54 +
  55 + if self.zbuf[idx] < zr {
  56 + self.zbuf[idx] = zr;
  57 + self.image[idx] = Color(r, g, b, 0xFF);
  58 + }
  59 + }
  60 +
  61 + // Empty implementations for now… mostly not needed because it is
  62 + // done from JavaScript…
  63 + fn init_events(&self) {}
  64 + fn start_events(&self, _ :mpsc::Sender<i32>) {}
  65 + fn draw(&mut self, _ :&dyn Drawable<f64>, _ :u32) {}
  66 + fn put_text(&self, _ :Vertex<f64>, _ :&str) {}
  67 + fn show(&self) {}
  68 +}
1 -//  
2 -// Basic geometric things...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::convert::{From, Into};  
22 -use std::ops::{Add,Sub,Neg,Mul,Div};  
23 -use std::fmt::Debug;  
24 -  
25 -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};  
26 -use crate::transform::{TMatrix, Transformable};  
27 -use crate::trigonometry::Trig;  
28 -use crate::vector::Vector;  
29 -  
30 -#[derive(Debug, Clone)]  
31 -pub struct Face<T>  
32 -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {  
33 - corners :Vec<usize>,  
34 - normal :Option<Vector<T>>,  
35 -}  
36 -  
37 -#[derive(Debug, PartialEq, Eq, Clone, Copy)]  
38 -pub struct Point<T>(pub Vector<T>, T)  
39 - where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig;  
40 -  
41 -impl<T> Point<T>  
42 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
43 - + Mul<Output = T> + Div<Output = T>  
44 - + PartialEq + Trig + Copy + From<i32> {  
45 - pub fn new(x :T, y :T, z :T) -> Self {  
46 - Self(Vector(x, y, z), 1.into())  
47 - }  
48 -}  
49 -  
50 -impl<T> Add for Point<T>  
51 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
52 - + Mul<Output = T> + Div<Output = T>  
53 - + PartialEq + Trig + Copy {  
54 - type Output = Self;  
55 -  
56 - fn add(self, other :Self) -> Self {  
57 - let Point(v1, w1) = self;  
58 - let Point(v2, w2) = other;  
59 - Self(v1 + v2, w1 + w2)  
60 - }  
61 -}  
62 -  
63 -impl<T> Neg for Point<T>  
64 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
65 - + Mul<Output = T> + Div<Output = T>  
66 - + PartialEq + Trig + Copy {  
67 - type Output = Self;  
68 -  
69 - fn neg(self) -> Self {  
70 - let Point(v, w) = self;  
71 - Self(-v, -w)  
72 - }  
73 -}  
74 -  
75 -impl<T> Sub for Point<T>  
76 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
77 - + Mul<Output = T> + Div<Output = T>  
78 - + PartialEq + Trig + Copy {  
79 - type Output = Self;  
80 -  
81 - fn sub(self, other :Self) -> Self {  
82 - self + -other  
83 - }  
84 -}  
85 -  
86 -impl<T> Mul for Point<T>  
87 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
88 - + Mul<Output = T> + Div<Output = T>  
89 - + PartialEq + Trig + Copy + From<i32> {  
90 - type Output = Self;  
91 -  
92 - fn mul(self, other :Self) -> Self {  
93 - let a :Vector<T> = self.into();  
94 - let b :Vector<T> = other.into();  
95 -  
96 - Point(a * b, 1.into())  
97 - }  
98 -}  
99 -  
100 -impl<T> From<Vector<T>> for Point<T>  
101 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
102 - + Mul<Output = T> + Div<Output = T>  
103 - + PartialEq + Trig + Copy + From<i32> {  
104 - fn from(v :Vector<T>) -> Self {  
105 - Point(v, 1.into())  
106 - }  
107 -}  
108 -  
109 -impl<T> Into<Vector<T>> for Point<T>  
110 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
111 - + Mul<Output = T> + Div<Output = T>  
112 - + PartialEq + Trig + Copy + From<i32> {  
113 - fn into(self) -> Vector<T> {  
114 - let Point(v, w) = self;  
115 -  
116 - if w == 0.into() {  
117 - v  
118 - } else {  
119 - v.mul(&w.recip())  
120 - }  
121 - }  
122 -}  
123 -  
124 -impl<T> Transformable<T> for Point<T>  
125 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
126 - + Mul<Output = T> + Div<Output = T>  
127 - + PartialEq + Debug + Trig + Copy + From<i32> {  
128 - fn transform(&self, m :&TMatrix<T>) -> Self {  
129 - let Point(v, w) = *self;  
130 - let (v, w) = m.apply(&v, w);  
131 -  
132 - if w == 0.into() {  
133 - v.into()  
134 - } else {  
135 - v.mul(&w.recip()).into()  
136 - }  
137 - }  
138 -}  
139 -  
140 -#[derive(Debug)]  
141 -pub struct Polyeder<T>  
142 -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {  
143 - points :Vec<Point<T>>,  
144 - faces :Vec<Face<T>>,  
145 -}  
146 -  
147 -pub trait Primitives<T>  
148 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
149 - fn transform(&self, m :&TMatrix<T>) -> Self;  
150 - fn project( &self  
151 - , camera :&Camera<T>  
152 - , light :&DirectLight<T>  
153 - , col :u32 ) -> Vec<(Polygon<T>, u32)>;  
154 -}  
155 -  
156 -#[derive(Debug, Clone, Copy)]  
157 -pub struct Camera<T>  
158 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
159 - width :T,  
160 - height :T,  
161 - distance :T,  
162 - project :TMatrix<T>,  
163 -}  
164 -  
165 -pub struct DirectLight<T>  
166 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
167 - direction: Vector<T>,  
168 -}  
169 -  
170 -impl<T> Camera<T>  
171 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
172 - + Mul<Output = T> + Div<Output = T>  
173 - + PartialEq + Debug + Copy + Trig + From<i32> {  
174 - // This code assumes that the size of the viewport is always  
175 - // equal to the size of the physical screen… e.g. window/canvas thus some  
176 - // effects can't be done. See book for examples with different viewport  
177 - // and screen sizes.  
178 - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {  
179 - let width :T = (c.width() as i32).into();  
180 - let height :T = (c.height() as i32).into();  
181 - let d :T = 1.into();  
182 - let fov = T::cot(angle) * width;  
183 - let wh = width / 2.into();  
184 - let hh = height / 2.into();  
185 -  
186 - Camera { width: width  
187 - , height: height  
188 - , distance: d  
189 - , project: TMatrix::new(  
190 - ( fov, 0.into(), wh, 0.into())  
191 - , (0.into(), fov, hh, 0.into())  
192 - , (0.into(), 0.into(), d, 1.into())  
193 - , (0.into(), 0.into(), 1.into(), 0.into()) ) }  
194 - }  
195 -  
196 - pub fn get_distance(&self) -> T {  
197 - self.distance  
198 - }  
199 -  
200 - pub fn get_projection(&self) -> TMatrix<T> {  
201 - self.project  
202 - }  
203 -  
204 - pub fn project(&self, p :Point<T>) -> Point<T> {  
205 - p.transform(&self.project)  
206 - }  
207 -}  
208 -  
209 -impl<T> DirectLight<T>  
210 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
211 - + Mul<Output = T> + Div<Output = T>  
212 - + Debug + Copy + Trig + From<i32> {  
213 - pub fn new(v :Vector<T>) -> Self {  
214 - DirectLight{ direction: v }  
215 - }  
216 -  
217 - pub fn dir(&self) -> Vector<T> {  
218 - self.direction  
219 - }  
220 -}  
221 -  
222 -impl<T> Face<T>  
223 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
224 - + Mul<Output = T> + Div<Output = T>  
225 - + PartialEq + Debug + Copy + Trig + From<i32> {  
226 - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {  
227 - let mut f = Face{ corners: corners, normal: None };  
228 - f.update_normal(ps);  
229 - f  
230 - }  
231 -  
232 - fn update_normal(&mut self, ps :&[Point<T>]) {  
233 - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();  
234 - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();  
235 - self.normal = Some(edge10 * edge12);  
236 - }  
237 -}  
238 -  
239 -impl<T> Polyeder<T>  
240 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
241 - + Mul<Output = T> + Div<Output = T>  
242 - + PartialEq + Debug + Copy + Trig + From<i32> {  
243 - fn update_normals(&mut self) {  
244 - for f in self.faces.iter_mut() {  
245 - f.update_normal(&self.points);  
246 - }  
247 - }  
248 -  
249 - // construct via cube, see polyhedra.pdf  
250 - pub fn tetrahedron(a :T) -> Polyeder<T> {  
251 - let f2 :T = 2.into();  
252 - let ch = a / (f2 * T::sqrt(f2).unwrap());  
253 -  
254 - let ps = vec!( Point::new(-ch, -ch, ch) // A  
255 - , Point::new(-ch, ch, -ch) // C  
256 - , Point::new( ch, -ch, -ch) // E  
257 - , Point::new( ch, ch, ch) ); // G  
258 -  
259 - // bottom: 1, 2, 3  
260 - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom  
261 - , Face::new(vec!(3, 2, 0), &ps)  
262 - , Face::new(vec!(0, 1, 3), &ps)  
263 - , Face::new(vec!(1, 2, 3), &ps) );  
264 - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom  
265 - // , Face::new(vec!(0, 2, 3), &ps)  
266 - // , Face::new(vec!(3, 1, 0), &ps)  
267 - // , Face::new(vec!(3, 2, 1), &ps) );  
268 -  
269 - Polyeder{ points: ps, faces: fs }  
270 - }  
271 -  
272 - pub fn triangle(a :T) -> Polyeder<T> {  
273 - let f0 :T = 0.into();  
274 - let f3 :T = 3.into();  
275 - let f6 :T = 6.into();  
276 - let zi :T = T::sqrt(f3).unwrap() / f6 * a;  
277 - let zc :T = T::sqrt(f3).unwrap() / f3 * a;  
278 - let ah :T = a / 2.into();  
279 -  
280 - let ps = vec!( Point::new(-ah, f0, -zi)  
281 - , Point::new( f0, f0, zc)  
282 - , Point::new( ah, f0, -zi) );  
283 -  
284 - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));  
285 -  
286 - Polyeder{ points: ps, faces: fs }  
287 - }  
288 -  
289 - pub fn cube(a :T) -> Polyeder<T> {  
290 - let ah :T = a / From::<i32>::from(2);  
291 -  
292 - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1  
293 - , Point::new(-ah, -ah, -ah) // 1 => front 2  
294 - , Point::new( ah, -ah, -ah) // 2 => front 3  
295 - , Point::new( ah, ah, -ah) // 3 => front 4  
296 - , Point::new(-ah, ah, ah) // 4 => back 1  
297 - , Point::new(-ah, -ah, ah) // 5 => back 2  
298 - , Point::new( ah, -ah, ah) // 6 => back 3  
299 - , Point::new( ah, ah, ah) ); // 7 => back 4  
300 -  
301 - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front  
302 - , Face::new(vec!(7, 6, 5, 4), &ps) // back  
303 - , Face::new(vec!(1, 5, 6, 2), &ps) // top  
304 - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom  
305 - , Face::new(vec!(0, 4, 5, 1), &ps) // left  
306 - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right  
307 -  
308 - Polyeder{ points: ps, faces: fs }  
309 - }  
310 -}  
311 -  
312 -impl<T> Primitives<T> for Polyeder<T>  
313 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
314 - + Mul<Output = T> + Div<Output = T>  
315 - + Debug + Copy + Trig + From<i32> + PartialOrd {  
316 - // TODO Maybe this should also be an instance of Transformable…  
317 - fn transform(&self, m :&TMatrix<T>) -> Self {  
318 - let Polyeder{ points: ps, faces: fs } = self;  
319 -  
320 - let mut p = Polyeder{  
321 - points: ps.iter().map(|p| p.transform(m)).collect()  
322 - , faces: fs.to_vec()  
323 - };  
324 -  
325 - // TODO alternatively we could rotate the normals too, but this cannot  
326 - // done with the original matrix… the question is, what is faster.  
327 - p.update_normals();  
328 - p  
329 - }  
330 -  
331 - fn project( &self  
332 - , camera :&Camera<T>  
333 - , light :&DirectLight<T>  
334 - , color :u32 ) -> Vec<(Polygon<T>, u32)> {  
335 - // Helper to create a Polygon from Coordinates…  
336 - // TODO probably there needs to be a Polygon constructor for this.  
337 - fn polygon<I, T>(c :I) -> Polygon<T>  
338 - where I: Iterator<Item = Coordinate<T>> {  
339 - Polygon(Coordinates(c.collect()))  
340 - }  
341 -  
342 - // this one does the projection... as the projection was the last  
343 - // matrix we do not need to do it here.  
344 - let to_coord = |p :&usize| {  
345 - let Point(v, _) = camera.project(self.points[*p]);  
346 - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())  
347 - };  
348 - let to_poly = |f :&Face<T>| {  
349 - let pg = polygon(f.corners.iter().map(to_coord));  
350 - let mut r :T = (((color >> 16) & 0xFF) as i32).into();  
351 - let mut g :T = (((color >> 8) & 0xFF) as i32).into();  
352 - let mut b :T = (((color ) & 0xFF) as i32).into();  
353 - let lf :T = match f.normal {  
354 - None => 1.into(),  
355 - Some(n) => n.dot(light.dir())  
356 - / (n.mag() * light.dir().mag()),  
357 - };  
358 -  
359 - // this "if" represents a first simple backface culling  
360 - // approach. We only return face that face towards us.  
361 - if lf < 0.into() {  
362 - r = r * -lf;  
363 - g = g * -lf;  
364 - b = b * -lf;  
365 -  
366 - let c :u32 = (r.round() as u32) << 16  
367 - | (g.round() as u32) << 8  
368 - | (b.round() as u32);  
369 -  
370 - Some((pg, c))  
371 - } else {  
372 - None  
373 - }};  
374 -  
375 - self.faces.iter().filter_map(to_poly).collect()  
376 - }  
377 -}  
1 -extern crate lazy_static; 1 +extern crate easel3d;
2 2
3 -pub type Error = &'static str; 3 +mod easel3d_wasm;
  4 +use easel3d_wasm::{WasmCanvas, Color};
4 5
5 -pub mod easel;  
6 -pub mod transform;  
7 -pub mod trigonometry;  
8 -pub mod vector;  
9 -pub mod geometry; 6 +use easel3d::easel::canvas::Canvas;
  7 +use easel3d::easel::fillable::Fillable;
10 8
11 -mod utils; 9 +use easel3d::math::transform::TMatrix;
  10 +use easel3d::math::vector::Vector;
12 11
13 -use vector::Vector;  
14 -use easel::{Canvas, Coordinate, Drawable, Fillable};  
15 -use geometry::{Camera, DirectLight, Polyeder, Primitives};  
16 -use transform::{TMatrix}; 12 +use easel3d::space::camera::Camera;
  13 +use easel3d::space::light::DirectLight;
  14 +use easel3d::space::polyeder::Polyeder;
  15 +use easel3d::space::primitives::Primitives;
17 16
18 -use std::fmt::{Display, Formatter, Result};  
19 -use std::sync::mpsc;  
20 -use std::time::Instant;  
21 use wasm_bindgen::prelude::*; 17 use wasm_bindgen::prelude::*;
22 18
23 // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global 19 // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
@@ -27,56 +23,37 @@ use wasm_bindgen::prelude::*; @@ -27,56 +23,37 @@ use wasm_bindgen::prelude::*;
27 static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 23 static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
28 24
29 #[wasm_bindgen] 25 #[wasm_bindgen]
30 -#[derive(Clone, Copy, Debug, PartialEq, Eq)]  
31 -pub struct Color(u8, u8, u8, u8);  
32 -  
33 -#[wasm_bindgen]  
34 -pub struct View3d { width :u16  
35 - , height :u16  
36 - , size :usize 26 +pub struct View3d { canvas :WasmCanvas
37 , degree :i32 27 , degree :i32
38 - //, start :Instant  
39 , tetrahedron :Polyeder<f64> 28 , tetrahedron :Polyeder<f64>
40 , cube :Polyeder<f64> 29 , cube :Polyeder<f64>
41 - , camera :Option<Camera<f64>>  
42 - , light :DirectLight<f64>  
43 - , zbuf :Vec<f64>  
44 - , image :Vec<Color>  
45 -} 30 + , camera :Camera<f64>
  31 + , light :DirectLight<f64> }
46 32
47 #[wasm_bindgen] 33 #[wasm_bindgen]
48 impl View3d { 34 impl View3d {
49 pub fn new(width :u16, height :u16) -> Self { 35 pub fn new(width :u16, height :u16) -> Self {
50 - let size = width as usize * height as usize;  
51 let light_vector = Vector(0.0, 0.0, 1.0); 36 let light_vector = Vector(0.0, 0.0, 1.0);
  37 + let canvas = WasmCanvas::new(width, height);
  38 + let camera = Camera::<f64>::new(&canvas, 45);
52 39
53 - let mut view3d = Self { width: width  
54 - , height: height  
55 - , size: size  
56 - , degree: 0  
57 - //, start: Instant::now()  
58 - , tetrahedron: Polyeder::tetrahedron(100.0)  
59 - , cube: Polyeder::cube(56.25)  
60 - , camera: None  
61 - , light: DirectLight::new(light_vector)  
62 - , zbuf: vec!(0.0; size)  
63 - , image: vec!(Color(0, 0, 0, 0xFF); size)  
64 - };  
65 -  
66 - view3d.camera = Some(Camera::<f64>::new(&view3d, 45));  
67 - view3d 40 + Self { canvas: canvas
  41 + , degree: 0
  42 + , tetrahedron: Polyeder::tetrahedron(100.0)
  43 + , cube: Polyeder::cube(56.25)
  44 + , camera: camera
  45 + , light: DirectLight::new(light_vector) }
68 } 46 }
69 47
70 pub fn width(&self) -> u16 { 48 pub fn width(&self) -> u16 {
71 - self.width 49 + self.canvas.width()
72 } 50 }
73 51
74 pub fn height(&self) -> u16 { 52 pub fn height(&self) -> u16 {
75 - self.height 53 + self.canvas.height()
76 } 54 }
77 55
78 pub fn update(&mut self) { 56 pub fn update(&mut self) {
79 - //let deg = ((self.start.elapsed() / 25).as_millis() % 360) as i32;  
80 let t = TMatrix::translate(Vector(0.0, 0.0, 150.0)); 57 let t = TMatrix::translate(Vector(0.0, 0.0, 150.0));
81 let rz = TMatrix::rotate_z(self.degree); 58 let rz = TMatrix::rotate_z(self.degree);
82 let rx = TMatrix::rotate_x(-self.degree*2); 59 let rx = TMatrix::rotate_x(-self.degree*2);
@@ -88,176 +65,22 @@ impl View3d { @@ -88,176 +65,22 @@ impl View3d {
88 let objects = vec!( (self.tetrahedron.transform(&rot1), 0xFFFF00) 65 let objects = vec!( (self.tetrahedron.transform(&rot1), 0xFFFF00)
89 , ( self.cube.transform(&rot2), 0x0000FF) ); 66 , ( self.cube.transform(&rot2), 0x0000FF) );
90 67
91 - self.degree = (self.degree + 1) % 360;  
92 -  
93 - self.clear();  
94 -  
95 - match self.camera {  
96 - None => {},  
97 - Some(camera) => {  
98 - for (o, color) in objects {  
99 - for (pg, c) in o.project(&camera, &self.light, color) {  
100 - (&pg).fill(self, c);  
101 - }  
102 - }  
103 - },  
104 - }  
105 - }  
106 -  
107 - pub fn image(&self) -> *const Color {  
108 - self.image.as_ptr()  
109 - }  
110 -}  
111 -  
112 -impl Canvas<f64> for View3d {  
113 - fn width(&self) -> u16 {  
114 - self.width  
115 - }  
116 -  
117 - fn height(&self) -> u16 {  
118 - self.height  
119 - }  
120 -  
121 - fn clear(&mut self) {  
122 - self.zbuf = vec!(0.0; self.size);  
123 - self.image = vec!(Color(0, 0, 0, 0xFF); self.size);  
124 - }  
125 -  
126 - fn set_pixel(&mut self, c :Coordinate<f64>, color :u32) {  
127 - let Coordinate(x, y, zr) = c;  
128 - let idx :usize = (y * (self.width as i32) + x) as usize;  
129 -  
130 - let r = ((color >> 16) & 0xFF) as u8;  
131 - let g = ((color >> 8) & 0xFF) as u8;  
132 - let b = ( color & 0xFF) as u8;  
133 -  
134 - if self.zbuf[idx] < zr {  
135 - self.zbuf[idx] = zr;  
136 - self.image[idx] = Color(r, g, b, 0xFF);  
137 - }  
138 - }  
139 -  
140 - // Empty implementations for now… mostly not needed because it is  
141 - // done from JavaScript…  
142 - fn init_events(&self) {}  
143 - fn start_events(&self, _ :mpsc::Sender<i32>) {}  
144 - fn draw( &mut self, _ :&dyn Drawable<f64>, _ :Coordinate<f64>, _ :u32 ) {}  
145 - fn put_text(&self, _ :Coordinate<f64>, _ :&str) {}  
146 - fn show(&self) {}  
147 -}  
148 -  
149 -#[wasm_bindgen]  
150 -#[repr(u8)]  
151 -#[derive(Clone, Copy, Debug, PartialEq, Eq)]  
152 -pub enum Cell {  
153 - Dead = 0,  
154 - Alive = 1,  
155 -}  
156 -  
157 -#[wasm_bindgen]  
158 -pub struct Universe {  
159 - width :u32,  
160 - height :u32,  
161 - cells :Vec<Cell>,  
162 -}  
163 -  
164 -#[wasm_bindgen]  
165 -impl Universe {  
166 - pub fn new() -> Universe {  
167 - let width = 64;  
168 - let height = 64;  
169 -  
170 - let init_cells = |i :u32| {  
171 - if i % 2 == 0 || i % 7 == 0 { Cell::Alive } else { Cell::Dead }  
172 - };  
173 -  
174 - let cells = (0..width * height).map(init_cells).collect();  
175 -  
176 - Universe {  
177 - width: width,  
178 - height: height,  
179 - cells: cells,  
180 - }  
181 - }  
182 -  
183 - pub fn width(&self) -> u32 {  
184 - self.width  
185 - }  
186 -  
187 - pub fn height(&self) -> u32 {  
188 - self.height  
189 - }  
190 -  
191 - pub fn cells(&self) -> *const Cell {  
192 - self.cells.as_ptr()  
193 - }  
194 -  
195 - pub fn render(&self) -> String {  
196 - self.to_string()  
197 - }  
198 -  
199 - pub fn tick(&mut self) {  
200 - let mut next = self.cells.clone(); 68 + let rlx = TMatrix::rotate_x(-self.degree/4);
  69 + let rly = TMatrix::rotate_y(-self.degree/1);
  70 + let light = self.light.transform(&TMatrix::combine(vec!(rlx, rly)));
201 71
202 - for row in 0..self.height {  
203 - for col in 0..self.width {  
204 - let idx = self.get_index(row, col);  
205 - let cell = self.cells[idx];  
206 - let live_neighbors = self.live_neighbor_count(row, col); 72 + self.degree = (self.degree + 1) % (4*360);
207 73
208 - // Game of life rules....  
209 - let next_cell = match (cell, live_neighbors) {  
210 - (Cell::Alive, 2) |  
211 - (Cell::Alive, 3) => Cell::Alive,  
212 - (Cell::Alive, _) => Cell::Dead,  
213 - ( Cell::Dead, 3) => Cell::Alive,  
214 - ( otherwise, _) => otherwise,  
215 - }; 74 + self.canvas.clear();
216 75
217 - next[idx] = next_cell; 76 + for (o, color) in objects {
  77 + for (pg, c) in o.project(&self.camera, &light, color) {
  78 + (&pg).fill(&mut self.canvas, c);
218 } 79 }
219 } 80 }
220 -  
221 - self.cells = next;  
222 - }  
223 -  
224 - fn get_index(&self, row :u32, col :u32) -> usize {  
225 - (row * self.width + col) as usize  
226 } 81 }
227 82
228 - fn live_neighbor_count(&self, row :u32, col :u32) -> u8 {  
229 - let mut count = 0;  
230 -  
231 - for delta_row in [self.height - 1, 0, 1].iter().cloned() {  
232 - for delta_col in [self.width - 1, 0, 1].iter().cloned() {  
233 - if delta_row == 0 && delta_col == 0 {  
234 - continue;  
235 - }  
236 -  
237 - let neighbor_row = (row + delta_row) % self.height;  
238 - let neighbor_col = (col + delta_col) % self.width;  
239 - let idx = self.get_index(neighbor_row, neighbor_col);  
240 - count += self.cells[idx] as u8;  
241 - }  
242 - }  
243 -  
244 - count  
245 - }  
246 -}  
247 -  
248 -impl Display for Universe {  
249 - fn fmt(&self, f :&mut Formatter) -> Result {  
250 - for line in self.cells.as_slice().chunks(self.width as usize) {  
251 - for &cell in line {  
252 - let symbol = match cell {  
253 - Cell::Dead => ' ',  
254 - Cell::Alive => '*',  
255 - };  
256 - write!(f, "{}", symbol)?;  
257 - }  
258 - write!(f, "\n")?;  
259 - }  
260 -  
261 - Ok(()) 83 + pub fn image(&self) -> *const Color {
  84 + self.canvas.image()
262 } 85 }
263 } 86 }
1 -//  
2 -// Transformation of vectors in a given coordinate system...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::ops::{Add, Sub, Neg, Mul, Div};  
22 -use std::fmt::Debug;  
23 -  
24 -use crate::Vector;  
25 -use crate::trigonometry::Trig;  
26 -  
27 -#[derive(Debug, Clone, Copy)]  
28 -pub struct TMatrix<T>( (T, T, T, T)  
29 - , (T, T, T, T)  
30 - , (T, T, T, T)  
31 - , (T, T, T, T) )  
32 - where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;  
33 -  
34 -pub trait Transformable<T>  
35 -where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy {  
36 - fn transform(&self, m :&TMatrix<T>) -> Self;  
37 -}  
38 -  
39 -impl<T> TMatrix<T>  
40 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
41 - + Mul<Output = T> + Div<Output = T>  
42 - + Debug + Trig + From<i32> + Copy {  
43 - pub fn new( r1 :(T, T, T, T)  
44 - , r2 :(T, T, T, T)  
45 - , r3 :(T, T, T, T)  
46 - , r4 :(T, T, T, T) ) -> Self {  
47 - TMatrix(r1, r2, r3, r4)  
48 - }  
49 -  
50 - pub fn unit() -> Self {  
51 - Self::new( (1.into(), 0.into(), 0.into(), 0.into())  
52 - , (0.into(), 1.into(), 0.into(), 0.into())  
53 - , (0.into(), 0.into(), 1.into(), 0.into())  
54 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
55 - }  
56 -  
57 - pub fn translate(v :Vector<T>) -> Self {  
58 - let Vector(x, y, z) = v;  
59 -  
60 - Self::new( (1.into(), 0.into(), 0.into(), x)  
61 - , (0.into(), 1.into(), 0.into(), y)  
62 - , (0.into(), 0.into(), 1.into(), z)  
63 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
64 - }  
65 -  
66 - pub fn rotate_x(a :i32) -> Self {  
67 - let sin :T = Trig::sin(a);  
68 - let cos :T = Trig::cos(a);  
69 -  
70 - Self::new( (1.into(), 0.into(), 0.into(), 0.into())  
71 - , (0.into(), cos , -sin , 0.into())  
72 - , (0.into(), sin , cos , 0.into())  
73 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
74 - }  
75 -  
76 - pub fn rotate_y(a :i32) -> Self {  
77 - let sin :T = Trig::sin(a);  
78 - let cos :T = Trig::cos(a);  
79 -  
80 - Self::new( (cos , 0.into(), sin , 0.into())  
81 - , (0.into(), 1.into(), 0.into(), 0.into())  
82 - , (-sin , 0.into(), cos , 0.into())  
83 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
84 - }  
85 -  
86 - pub fn rotate_z(a :i32) -> Self {  
87 - let sin :T = Trig::sin(a);  
88 - let cos :T = Trig::cos(a);  
89 -  
90 - Self::new( (cos , -sin , 0.into(), 0.into())  
91 - , (sin , cos , 0.into(), 0.into())  
92 - , (0.into(), 0.into(), 1.into(), 0.into())  
93 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
94 - }  
95 -  
96 - pub fn rotate_v(v :&Vector<T>, a :i32) -> Self {  
97 - let Vector(x, y, z) = *v;  
98 -  
99 - let sin :T = Trig::sin(a);  
100 - let cos :T = Trig::cos(a);  
101 -  
102 - let zero :T = 0.into();  
103 - let one :T = 1.into();  
104 -  
105 - Self::new( ( (one - cos) * x * x + cos  
106 - , (one - cos) * x * y - sin * z  
107 - , (one - cos) * x * z + sin * y  
108 - , zero )  
109 - , ( (one - cos) * x * y + sin * z  
110 - , (one - cos) * y * y + cos  
111 - , (one - cos) * y * z - sin * x  
112 - , zero )  
113 - , ( (one - cos) * x * z - sin * y  
114 - , (one - cos) * y * z + sin * x  
115 - , (one - cos) * z * z + cos  
116 - , zero )  
117 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
118 - }  
119 -  
120 - pub fn scale(v :Vector<T>) -> Self {  
121 - let Vector(x, y, z) = v;  
122 -  
123 - Self::new( ( x, 0.into(), 0.into(), 0.into())  
124 - , (0.into(), y, 0.into(), 0.into())  
125 - , (0.into(), 0.into(), z, 0.into())  
126 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
127 - }  
128 -  
129 - pub fn combine<I>(mi :I) -> TMatrix<T>  
130 - where I: IntoIterator<Item = TMatrix<T>> {  
131 -  
132 - mi.into_iter().fold(Self::unit(), |acc, x| x * acc)  
133 - }  
134 -  
135 - pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {  
136 - let TMatrix( (a11, a12, a13, a14)  
137 - , (a21, a22, a23, a24)  
138 - , (a31, a32, a33, a34)  
139 - , (a41, a42, a43, a44) ) = *self;  
140 - let Vector(x, y, z) = *v;  
141 -  
142 - let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w  
143 - , a21 * x + a22 * y + a23 * z + a24 * w  
144 - , a31 * x + a32 * y + a33 * z + a34 * w );  
145 - let w = a41 * x + a42 * y + a43 * z + a44 * w;  
146 -  
147 - //v.mul(&w.recip())  
148 - (v, w)  
149 - }  
150 -}  
151 -  
152 -impl<T> Mul for TMatrix<T>  
153 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
154 - + Mul<Output = T> + Div<Output = T>  
155 - + Debug + Trig + From<i32> + Copy {  
156 - type Output = Self;  
157 -  
158 - // ATTENTION: This is not commutative, nor assoziative.  
159 - fn mul(self, other :Self) -> Self {  
160 - let TMatrix( (a11, a12, a13, a14)  
161 - , (a21, a22, a23, a24)  
162 - , (a31, a32, a33, a34)  
163 - , (a41, a42, a43, a44) ) = self;  
164 - let TMatrix( (b11, b12, b13, b14)  
165 - , (b21, b22, b23, b24)  
166 - , (b31, b32, b33, b34)  
167 - , (b41, b42, b43, b44) ) = other;  
168 -  
169 - TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41  
170 - , a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42  
171 - , a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43  
172 - , a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 )  
173 - , ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41  
174 - , a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42  
175 - , a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43  
176 - , a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 )  
177 - , ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41  
178 - , a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42  
179 - , a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43  
180 - , a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 )  
181 - , ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41  
182 - , a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42  
183 - , a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43  
184 - , a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) )  
185 - }  
186 -}  
1 -//  
2 -// Some trigonometic functions with Fractions results.  
3 -// Currently only sin, cos and tan are implemented.  
4 -// As I was unable to find a really good integral approximation for them I  
5 -// implement them as a table which is predefined using the floating point  
6 -// function f64::sin and then transformed into a fraction of a given  
7 -// PRECISION.  
8 -// These approximations are quite good and for a few edge cases  
9 -// even better than the floating point implementations.  
10 -//  
11 -// Georg Hopp <georg@steffers.org>  
12 -//  
13 -// Copyright © 2019 Georg Hopp  
14 -//  
15 -// This program is free software: you can redistribute it and/or modify  
16 -// it under the terms of the GNU General Public License as published by  
17 -// the Free Software Foundation, either version 3 of the License, or  
18 -// (at your option) any later version.  
19 -//  
20 -// This program is distributed in the hope that it will be useful,  
21 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
22 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
23 -// GNU General Public License for more details.  
24 -//  
25 -// You should have received a copy of the GNU General Public License  
26 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
27 -//  
28 -use std::ops::Div;  
29 -use std::ops::Neg;  
30 -use std::marker::Sized;  
31 -use crate::Error;  
32 -  
33 -pub trait Trig {  
34 - fn pi() -> Self;  
35 - fn recip(self) -> Self;  
36 - fn round(&self) -> i32;  
37 - fn sqrt(self) -> Result<Self, Error> where Self: Sized;  
38 - fn sintab() -> Vec<Self> where Self: Sized;  
39 - fn tantab() -> Vec<Self> where Self: Sized;  
40 -  
41 - fn sin(d :i32) -> Self  
42 - where Self: Sized + Neg<Output = Self> + Copy {  
43 - match d {  
44 - 0 ..=90 => Self::sintab()[d as usize],  
45 - 91 ..=180 => Self::sintab()[180 - d as usize],  
46 - 181..=270 => -Self::sintab()[d as usize - 180],  
47 - 271..=359 => -Self::sintab()[360 - d as usize],  
48 - _ => {  
49 - Self::sin(if d < 0 { d % 360 + 360 } else { d % 360 })  
50 - },  
51 - }  
52 - }  
53 -  
54 - fn cos(d :i32) -> Self  
55 - where Self: Sized + Neg<Output = Self> + Copy {  
56 - match d {  
57 - 0 ..=90 => Self::sintab()[90 - d as usize],  
58 - 91 ..=180 => -Self::sintab()[90 - (180 - d as usize)],  
59 - 181..=270 => -Self::sintab()[90 - (d as usize - 180)],  
60 - 271..=359 => Self::sintab()[90 - (360 - d as usize)],  
61 - _ => {  
62 - Self::cos(if d < 0 { d % 360 + 360 } else { d % 360 })  
63 - },  
64 - }  
65 - }  
66 -  
67 - fn tan(d :i32) -> Self where Self: Sized + Copy {  
68 - match d {  
69 - 0 ..=179 => Self::tantab()[d as usize],  
70 - 180..=359 => Self::tantab()[d as usize - 180],  
71 - _ => {  
72 - Self::tan(if d < 0 { d % 360 + 360 } else { d % 360 })  
73 - },  
74 - }  
75 - }  
76 -  
77 - fn cot(d :i32) -> Self  
78 - where Self: Sized + Copy + From<i32> + Div<Output = Self> {  
79 - Into::<Self>::into(1) / Self::tan(d)  
80 - }  
81 -}  
82 -  
83 -impl Trig for f64 {  
84 - fn pi() -> Self {  
85 - std::f64::consts::PI  
86 - }  
87 -  
88 - fn recip(self) -> Self {  
89 - self.recip()  
90 - }  
91 -  
92 - fn round(&self) -> i32 {  
93 - f64::round(*self) as i32  
94 - }  
95 -  
96 - fn sqrt(self) -> Result<Self, Error> {  
97 - let x = self.sqrt();  
98 - match x.is_nan() {  
99 - true => Err("sqrt on negative undefined"),  
100 - false => Ok(x),  
101 - }  
102 - }  
103 -  
104 - fn sintab() -> Vec<Self> {  
105 - lazy_static::lazy_static! {  
106 - static ref SINTAB :Vec<f64> =  
107 - (0..=90).map(|x| _sin(x)).collect();  
108 - }  
109 -  
110 - // f64 sin. (From 0° to 90°)  
111 - fn _sin(d: u32) -> f64 {  
112 - match d {  
113 - 0 => 0.0,  
114 - 90 => 1.0,  
115 - _ => (d as f64).to_radians().sin(),  
116 - }  
117 - }  
118 -  
119 - SINTAB.to_vec()  
120 - }  
121 -  
122 - fn tantab() -> Vec<Self> {  
123 - // This table exists only because the sin(α) / cos(α) method  
124 - // yields very large unreducable denominators in a lot of cases.  
125 - lazy_static::lazy_static! {  
126 - static ref TANTAB :Vec<f64> =  
127 - (0..180).map(|x| _tan(x)).collect();  
128 - }  
129 -  
130 - // fractional tan from f64 tan. (From 0° to 179°)  
131 - fn _tan(d: u32) -> f64 {  
132 - match d {  
133 - 0 => 0.0,  
134 - 45 => 1.0,  
135 - 90 => std::f64::INFINITY,  
136 - 135 => -1.0,  
137 - _ => (d as f64).to_radians().tan(),  
138 - }  
139 - }  
140 -  
141 - TANTAB.to_vec()  
142 - }  
143 -}  
1 -pub fn set_panic_hook() {  
2 - // When the `console_error_panic_hook` feature is enabled, we can call the  
3 - // `set_panic_hook` function at least once during initialization, and then  
4 - // we will get better error messages if our code ever panics.  
5 - //  
6 - // For more details see  
7 - // https://github.com/rustwasm/console_error_panic_hook#readme  
8 - #[cfg(feature = "console_error_panic_hook")]  
9 - console_error_panic_hook::set_once();  
10 -}  
1 -//  
2 -// Stuff for manipulating 3 dimensional vectors.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::fmt::{Debug, Display, Formatter, Result};  
22 -use std::ops::{Add, Sub, Neg, Mul, Div};  
23 -  
24 -use crate::trigonometry::Trig;  
25 -use crate::transform::{TMatrix, Transformable};  
26 -  
27 -#[derive(Debug, Eq, Clone, Copy)]  
28 -pub struct Vector<T>(pub T, pub T, pub T)  
29 - where T: Add + Sub + Neg + Mul + Div + Trig + Copy;  
30 -  
31 -impl<T> Vector<T>  
32 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
33 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
34 - pub fn x(self) -> T { self.0 }  
35 - pub fn y(self) -> T { self.1 }  
36 - pub fn z(self) -> T { self.2 }  
37 -  
38 - pub fn mag(self) -> T {  
39 - let Vector(x, y, z) = self;  
40 - (x * x + y * y + z * z).sqrt().unwrap()  
41 - }  
42 -  
43 - pub fn mul(self, s :&T) -> Self {  
44 - let Vector(x, y, z) = self;  
45 - Vector(x * *s, y * *s, z * *s)  
46 - }  
47 -  
48 - pub fn dot(self, other :Self) -> T {  
49 - let Vector(x1, y1, z1) = self;  
50 - let Vector(x2, y2, z2) = other;  
51 -  
52 - x1 * x2 + y1 * y2 + z1 * z2  
53 - }  
54 -  
55 - pub fn norm(self) -> Self {  
56 - // TODO This can result in 0 or inf Vectors…  
57 - // Maybe we need to handle zero and inf magnitude here…  
58 - self.mul(&self.mag().recip())  
59 - }  
60 -  
61 - pub fn distance(self, other :Self) -> T {  
62 - (self - other).mag()  
63 - }  
64 -}  
65 -  
66 -impl<T> Display for Vector<T>  
67 -where T: Add + Sub + Neg + Mul + Div + Trig + Display + Copy {  
68 - fn fmt(&self, f :&mut Formatter<'_>) -> Result {  
69 - let Vector(x, y, z) = self;  
70 - write!(f, "({}, {}, {})", x, y, z)  
71 - }  
72 -}  
73 -  
74 -impl<T> PartialEq for Vector<T>  
75 -where T: Add + Sub + Neg + Mul + Div + Trig + PartialEq + Copy {  
76 - fn eq(&self, other :&Self) -> bool {  
77 - let Vector(x1, y1, z1) = self;  
78 - let Vector(x2, y2, z2) = other;  
79 - x1 == x2 && y1 == y2 && z1 == z2  
80 - }  
81 -}  
82 -  
83 -impl<T> Add for Vector<T>  
84 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
85 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
86 - type Output = Self;  
87 -  
88 - fn add(self, other :Self) -> Self {  
89 - let Vector(x1, y1, z1) = self;  
90 - let Vector(x2, y2, z2) = other;  
91 - Vector(x1 + x2, y1 + y2, z1 + z2)  
92 - }  
93 -}  
94 -  
95 -impl<T> Sub for Vector<T>  
96 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
97 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
98 - type Output = Self;  
99 -  
100 - fn sub(self, other :Self) -> Self {  
101 - self + -other  
102 - }  
103 -}  
104 -  
105 -impl<T> Neg for Vector<T>  
106 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
107 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
108 - type Output = Self;  
109 -  
110 - fn neg(self) -> Self {  
111 - let Vector(x, y, z) = self;  
112 - Self(-x, -y, -z)  
113 - }  
114 -}  
115 -  
116 -impl<T> Mul for Vector<T>  
117 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
118 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
119 - type Output = Self;  
120 -  
121 - fn mul(self, other :Self) -> Self {  
122 - let Vector(ax, ay, az) = self;  
123 - let Vector(bx, by, bz) = other;  
124 -  
125 - Vector( ay * bz - az * by  
126 - , az * bx - ax * bz  
127 - , ax * by - ay * bx )  
128 - }  
129 -}  
130 -  
131 -impl<T> Transformable<T> for Vector<T>  
132 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
133 - + Mul<Output = T> + Div<Output = T>  
134 - + Trig + Copy + Debug + From<i32> {  
135 - fn transform(&self, m :&TMatrix<T>) -> Self {  
136 - let (v, _) = m.apply(self, 0.into());  
137 - v  
138 - }  
139 -}  
1 -#!/usr/bin/env node  
2 -  
3 -const { spawn } = require("child_process");  
4 -const fs = require("fs");  
5 -  
6 -let folderName = '.';  
7 -  
8 -if (process.argv.length >= 3) {  
9 - folderName = process.argv[2];  
10 - if (!fs.existsSync(folderName)) {  
11 - fs.mkdirSync(folderName);  
12 - }  
13 -}  
14 -  
15 -const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]);  
16 -  
17 -clone.on("close", code => {  
18 - if (code !== 0) {  
19 - console.error("cloning the template failed!")  
20 - process.exit(code);  
21 - } else {  
22 - console.log("🦀 Rust + 🕸 Wasm = ❤");  
23 - }  
24 -});  
1 -<div align="center">  
2 -  
3 - <h1><code>create-wasm-app</code></h1>  
4 -  
5 - <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>  
6 -  
7 - <p>  
8 - <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>  
9 - </p>  
10 -  
11 - <h3>  
12 - <a href="#usage">Usage</a>  
13 - <span> | </span>  
14 - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>  
15 - </h3>  
16 -  
17 - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>  
18 -</div>  
19 -  
20 -## About  
21 -  
22 -This template is designed for depending on NPM packages that contain  
23 -Rust-generated WebAssembly and using them to create a Website.  
24 -  
25 -* Want to create an NPM package with Rust and WebAssembly? [Check out  
26 - `wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)  
27 -* Want to make a monorepo-style Website without publishing to NPM? Check out  
28 - [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)  
29 - and/or  
30 - [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).  
31 -  
32 -## 🚴 Usage  
33 -  
34 -```  
35 -npm init wasm-app  
36 -```  
37 -  
38 -## 🔋 Batteries Included  
39 -  
40 -- `.gitignore`: ignores `node_modules`  
41 -- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you  
42 -- `README.md`: the file you are reading now!  
43 -- `index.html`: a bare bones html document that includes the webpack bundle  
44 -- `index.js`: example js file with a comment showing how to import and use a wasm pkg  
45 -- `package.json` and `package-lock.json`:  
46 - - pulls in devDependencies for using webpack:  
47 - - [`webpack`](https://www.npmjs.com/package/webpack)  
48 - - [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)  
49 - - [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)  
50 - - defines a `start` script to run `webpack-dev-server`  
51 -- `webpack.config.js`: configuration file for bundling your js with webpack  
52 -  
53 -## License  
54 -  
55 -Licensed under either of  
56 -  
57 -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)  
58 -* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)  
59 -  
60 -at your option.  
61 -  
62 -### Contribution  
63 -  
64 -Unless you explicitly state otherwise, any contribution intentionally  
65 -submitted for inclusion in the work by you, as defined in the Apache-2.0  
66 -license, shall be dual licensed as above, without any additional terms or  
67 -conditions.  
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 <html> 2 <html>
3 <head> 3 <head>
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 - <title>wasm-game-of-life!</title> 5 + <title>easel3d</title>
6 <style> 6 <style>
7 body { 7 body {
8 position: absolute; 8 position: absolute;
1 -import { View3d } from "wasm-game-of-life";  
2 -import { memory } from "wasm-game-of-life/wasm_game_of_life_bg"; 1 +import { View3d } from "easel3d-wasm";
  2 +import { memory } from "easel3d-wasm/easel3d_wasm_bg";
3 3
4 // 3D canvas stuff 4 // 3D canvas stuff
5 -const view3d = View3d.new(300, 300); 5 +const view3d = View3d.new(301, 301);
6 6
7 const view3d_canvas = document.getElementById("view3d"); 7 const view3d_canvas = document.getElementById("view3d");
8 view3d_canvas.width = view3d.width(); 8 view3d_canvas.width = view3d.width();
@@ -17,7 +17,6 @@ const view3d_renderLoop = () => { @@ -17,7 +17,6 @@ const view3d_renderLoop = () => {
17 } 17 }
18 18
19 const drawView3d = () => { 19 const drawView3d = () => {
20 - const view3d_imagePtr = view3d.image();  
21 const view3d_image = new ImageData( 20 const view3d_image = new ImageData(
22 new Uint8ClampedArray( memory.buffer 21 new Uint8ClampedArray( memory.buffer
23 , view3d.image() 22 , view3d.image()
1 { 1 {
2 - "name": "create-wasm-app", 2 + "name": "easel3d-wasm",
3 "version": "0.1.0", 3 "version": "0.1.0",
4 "lockfileVersion": 1, 4 "lockfileVersion": 1,
5 "requires": true, 5 "requires": true,
@@ -1486,6 +1486,9 @@ @@ -1486,6 +1486,9 @@
1486 "stream-shift": "^1.0.0" 1486 "stream-shift": "^1.0.0"
1487 } 1487 }
1488 }, 1488 },
  1489 + "easel3d-wasm": {
  1490 + "version": "file:../pkg"
  1491 + },
1489 "ee-first": { 1492 "ee-first": {
1490 "version": "1.1.1", 1493 "version": "1.1.1",
1491 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 1494 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -2836,12 +2839,6 @@ @@ -2836,12 +2839,6 @@
2836 "minimalistic-assert": "^1.0.1" 2839 "minimalistic-assert": "^1.0.1"
2837 } 2840 }
2838 }, 2841 },
2839 - "hello-wasm-pack": {  
2840 - "version": "0.1.0",  
2841 - "resolved": "https://registry.npmjs.org/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz",  
2842 - "integrity": "sha512-3hx0GDkDLf/a9ThCMV2qG4mwza8N/MCtm8aeFFc/cdBCL2zMJ1kW1wjNl7xPqD1lz8Yl5+uhnc/cpui4dLwz/w==",  
2843 - "dev": true  
2844 - },  
2845 "hmac-drbg": { 2842 "hmac-drbg": {
2846 "version": "1.0.1", 2843 "version": "1.0.1",
2847 "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 2844 "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@@ -5511,9 +5508,6 @@ @@ -5511,9 +5508,6 @@
5511 "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", 5508 "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
5512 "dev": true 5509 "dev": true
5513 }, 5510 },
5514 - "wasm-game-of-life": {  
5515 - "version": "file:../pkg"  
5516 - },  
5517 "watchpack": { 5511 "watchpack": {
5518 "version": "1.6.0", 5512 "version": "1.6.0",
5519 "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", 5513 "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
1 { 1 {
2 - "name": "create-wasm-app", 2 + "name": "easel3d-wasm",
3 "version": "0.1.0", 3 "version": "0.1.0",
4 "description": "create an app to consume rust-generated wasm packages", 4 "description": "create an app to consume rust-generated wasm packages",
5 "main": "index.js", 5 "main": "index.js",
6 - "bin": {  
7 - "create-wasm-app": ".bin/create-wasm-app.js"  
8 - },  
9 "scripts": { 6 "scripts": {
10 "build": "webpack --config webpack.config.js", 7 "build": "webpack --config webpack.config.js",
11 "start": "webpack-dev-server" 8 "start": "webpack-dev-server"
12 }, 9 },
13 "repository": { 10 "repository": {
14 "type": "git", 11 "type": "git",
15 - "url": "git+https://github.com/rustwasm/create-wasm-app.git" 12 + "url": "https://git.silpion.de/scm/~hopp/easel3d-wasm.git"
16 }, 13 },
17 "keywords": [ 14 "keywords": [
18 "webassembly", 15 "webassembly",
19 "wasm", 16 "wasm",
20 "rust", 17 "rust",
21 - "webpack" 18 + "webpack",
  19 + "easel3d"
22 ], 20 ],
23 - "author": "Ashley Williams <ashley666ashley@gmail.com>",  
24 - "license": "(MIT OR Apache-2.0)",  
25 - "bugs": {  
26 - "url": "https://github.com/rustwasm/create-wasm-app/issues"  
27 - },  
28 - "homepage": "https://github.com/rustwasm/create-wasm-app#readme", 21 + "author": "Georg Hopp <hopp@silpion.de>",
  22 + "license": "GPL-3.0-or-later",
29 "devDependencies": { 23 "devDependencies": {
30 - "wasm-game-of-life": "file:../pkg",  
31 - "hello-wasm-pack": "^0.1.0",  
32 "webpack": "^4.29.3", 24 "webpack": "^4.29.3",
33 "webpack-cli": "^3.1.0", 25 "webpack-cli": "^3.1.0",
34 "webpack-dev-server": "^3.1.5", 26 "webpack-dev-server": "^3.1.5",
35 "copy-webpack-plugin": "^5.0.0" 27 "copy-webpack-plugin": "^5.0.0"
36 }, 28 },
37 "dependencies": { 29 "dependencies": {
38 - "wasm-game-of-life": "file:../pkg" 30 + "easel3d-wasm": "file:../pkg"
39 } 31 }
40 } 32 }
Please register or login to post a comment