Commit 6f1051d2 authored by Florian Blasius's avatar Florian Blasius

[update] wasm32 support

parent e686103c
/target/
target/
Cargo.lock
**/*.rs.bk
.idea/
\ No newline at end of file
.idea/
.vscode/
\ No newline at end of file
......@@ -3,7 +3,10 @@ name = "orbgl"
version = "0.1.0"
authors = ["Michael Hölzl <FlowPX2@gmail.com>"]
[dependencies]
[target.wasm32-unknown-unknown.dependencies]
stdweb = "0.4.13"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
orbclient = "*"
rust-cairo = { git = "https://gitlab.redox-os.org/redox-os/rust-cairo.git" }
orbimage = "0.1.16"
\ No newline at end of file
......@@ -20,6 +20,46 @@ The Orbital Graphics Library is a library for rendering 2D and 3D graphics. Comp
### Goal
The first goal is to be compatible with HTML Canvas.
## Running the examples Examples
You find the examples in the `examples/` directory.
You can start the drawing example by executing the following command:
```text
cargo run --example simple
```
## Running the web examples
> The WebRenderEngine is only available for wasm32 and asmjs targets
1. Install [cargo-web]:
$ cargo install -f cargo-web
3. Go into `examples/web/simple` and start the example using one of these commands:
* Compile to [WebAssembly] using Rust's native WebAssembly backend:
$ cargo web start --target=wasm32-unknown-unknown
* Compile to [asm.js] using Emscripten:
$ cargo web start --target=asmjs-unknown-emscripten
* Compile to [WebAssembly] using Emscripten:
$ cargo web start --target=wasm32-unknown-emscripten
4. Visit `http://localhost:8000` with your browser.
For the `*-emscripten` targets `cargo-web` is not necessary, however
the native `wasm32-unknown-unknown` which doesn't need Emscripten
**requires** `cargo-web` to work!
### Tasks
##### Colors, Styles, and Shadows
......@@ -81,6 +121,3 @@ The first goal is to be compatible with HTML Canvas.
##### Other
- [x] save()
- [x] restore()
......@@ -2,13 +2,14 @@
extern crate orbclient;
extern crate orbgl;
use orbclient::{Window, Renderer, EventOption};
use orbclient::{Color, Window, Renderer, EventOption};
use orbgl::surface::ImageSurface;
use orbgl::surface::FramebufferSurface;
use orbgl::api::Canvas;
use orbgl::render_engine::OrbGLRenderEngine;
use orbgl::render_engine::CairoRenderEngine;
use orbgl::{
surface::{ImageSurface, FramebufferSurface},
api::{Canvas, Color},
render_engine::{OrbGLRenderEngine, CairoRenderEngine}
};
fn main() {
......
[workspace]
members = ["rectangle", "simple"]
\ No newline at end of file
[package]
name = "rectangle"
version = "0.1.0"
authors = ["Florian Blasius"]
[dependencies]
stdweb = "0.4.13"
orbgl = { path = "../../.." }
extern crate stdweb;
use stdweb::traits::*;
use stdweb::unstable::TryInto;
use stdweb::web::{
document,
window,
CanvasRenderingContext2d
};
use stdweb::web::html_element::CanvasElement;
extern crate orbgl;
use orbgl::{
api::{Canvas, Color},
render_engine::WebRenderEngine
};
fn main() {
stdweb::initialize();
let w = 800;
let h = 600;
let canvas: CanvasElement = document().query_selector( "#canvas" ).unwrap().unwrap().try_into().unwrap();
canvas.set_width(w);
canvas.set_height(h);
let render_engine = WebRenderEngine::new(canvas.get_context().unwrap());
let mut canvas = Canvas::new(render_engine.clone());
//Transform the canvas
canvas.transform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
//Set canvas fill style
canvas.set_fill_style(Color::rgba(0, 0, 0, 255));
canvas.set_stroke_style(Color::rgba(0, 0, 0, 255));
canvas.stroke_rect(100.0, 20.0, 100.0, 100.0);
canvas.fill_rect(20.0, 100.0, 100.0, 100.0);
canvas.set_fill_style(Color::rgba(255, 0, 0, 255));
canvas.set_stroke_style(Color::rgba(0, 0, 0, 255));
//canvas.begin_path();
canvas.move_to(30.0,30.0);
canvas.line_to(50.0,50.0);
canvas.fill_rect(20.0, 20.0, 20.0, 20.0);
canvas.line_to(100.0,55.0);
//canvas.close_path();
canvas.stroke();
canvas.clear_rect(0.0,0.0,30.0,30.0);
stdweb::event_loop();
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>stdweb • Canvas</title>
<style>
html, body {
margin: 0px;
padding: 0px;
}
canvas {
display: block;
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="rectangle.js"></script>
</body>
</html>
\ No newline at end of file
[package]
name = "simple"
version = "0.1.0"
authors = ["Florian Blasius"]
[dependencies]
stdweb = "0.4.13"
orbgl = { path = "../../.." }
extern crate stdweb;
use stdweb::traits::*;
use stdweb::unstable::TryInto;
use stdweb::web::{
document,
window,
CanvasRenderingContext2d
};
use stdweb::web::html_element::CanvasElement;
extern crate orbgl;
use orbgl::{
api::{Canvas, Color, Image},
render_engine::WebRenderEngine
};
fn main() {
stdweb::initialize();
let w = 800;
let h = 600;
let canvas: CanvasElement = document().query_selector( "#canvas" ).unwrap().unwrap().try_into().unwrap();
canvas.set_width(w);
canvas.set_height(h);
let render_engine = WebRenderEngine::new(canvas.get_context().unwrap());
let mut canvas = Canvas::new(render_engine.clone());
//Transform the canvas
canvas.transform(2.83, -2.83, 2.83, 2.83, 150.0, 300.0);
//Set canvas fill style
canvas.set_fill_style(Color::rgba(0, 0, 0, 255));
canvas.begin_path();
canvas.move_to(48.355, 17.922);
canvas.bezier_curve_to(52.06, 20.245, 54.658, 24.176, 55.131, 28.739);
canvas.bezier_curve_to(56.642, 29.445, 58.319, 29.851, 60.097, 29.851);
canvas.bezier_curve_to(66.588, 29.851, 71.849, 24.59, 71.849, 18.1);
canvas.bezier_curve_to(71.849, 11.609, 66.588, 6.348, 60.097, 6.348);
canvas.bezier_curve_to(53.668, 6.35, 48.453, 11.517, 48.355, 17.922);
canvas.close_path();
canvas.move_to(40.656, 41.984);
canvas.bezier_curve_to(47.147, 41.984, 52.408, 36.722, 52.408, 30.232);
canvas.bezier_curve_to(52.408, 23.742, 47.146, 18.481, 40.656, 18.481);
canvas.bezier_curve_to(34.166, 18.481, 28.902, 23.743, 28.902, 30.233);
canvas.bezier_curve_to(28.902, 36.723, 34.166, 41.984, 40.656, 41.984);
canvas.close_path();
canvas.move_to(45.641, 42.785);
canvas.line_to(35.669, 42.785);
canvas.bezier_curve_to(27.372, 42.785, 20.622, 49.536, 20.622, 57.833);
canvas.line_to(20.622, 70.028);
canvas.line_to(20.653, 70.219);
canvas.line_to(21.493, 70.482);
canvas.bezier_curve_to(29.411, 72.956, 36.290, 73.781, 41.952, 73.781);
canvas.bezier_curve_to(53.011, 73.781, 59.421, 70.628, 59.816, 70.427);
canvas.line_to(60.601, 70.03);
canvas.line_to(60.685, 70.03);
canvas.line_to(60.685, 57.833);
canvas.bezier_curve_to(60.688, 49.536, 53.938, 42.785, 45.641, 42.785);
canvas.close_path();
canvas.move_to(65.084, 30.653);
canvas.line_to(55.189, 30.653);
canvas.bezier_curve_to(55.082, 34.612, 53.392, 38.177, 50.719, 40.741);
canvas.bezier_curve_to(58.094, 42.934, 63.49, 49.773, 63.49, 57.851);
canvas.line_to(63.49, 61.609);
canvas.bezier_curve_to(73.26, 61.251, 78.89, 58.482, 79.261, 58.296);
canvas.line_to(80.046, 57.898);
canvas.line_to(80.13, 57.898);
canvas.line_to(80.13, 45.699);
canvas.bezier_curve_to(80.13, 37.403, 73.38, 30.653, 65.084, 30.653);
canvas.close_path();
canvas.move_to(20.035, 29.853);
canvas.bezier_curve_to(22.334, 29.853, 24.473, 29.182, 26.285, 28.039);
canvas.bezier_curve_to(26.861, 24.282, 28.875, 20.999, 31.752, 18.763);
canvas.bezier_curve_to(31.764, 18.543, 31.785, 18.325, 31.785, 18.103);
canvas.bezier_curve_to(31.785, 11.612, 26.523, 6.351, 20.035, 6.351);
canvas.bezier_curve_to(13.543, 6.351, 8.283, 11.612, 8.283, 18.103);
canvas.bezier_curve_to(8.283, 24.591, 13.543, 29.853, 20.035, 29.853);
canvas.close_path();
canvas.move_to(30.589, 40.741);
canvas.bezier_curve_to(27.929, 38.19, 26.245, 34.644, 26.122, 30.709);
canvas.bezier_curve_to(25.755, 30.682, 25.392, 30.653, 25.018, 30.653);
canvas.line_to(15.047, 30.653);
canvas.bezier_curve_to(6.75, 30.653, 0.0, 37.403, 0.0, 45.699);
canvas.line_to(0.0, 57.896);
canvas.line_to(0.031, 58.084);
canvas.line_to(0.871, 58.349);
canvas.bezier_curve_to(7.223, 60.332, 12.892, 61.246, 17.816, 61.534);
canvas.line_to(17.816, 57.851);
canvas.bezier_curve_to(17.818, 49.773, 23.212, 42.936, 30.589, 40.74);
//Fill the polygon and draw a stroke
canvas.fill();
canvas.set_transform(1.0,0.0,0.0,1.0,0.0,0.0);
canvas.begin_path();
canvas.begin_path();
canvas.set_fill_style(Color::rgba(255, 0, 0, 255));
canvas.arc(200.0, 200.0, 50.0,1.0 * std::f64::consts::PI, 2.0 * std::f64::consts::PI);
canvas.fill();
canvas.begin_path();
canvas.set_fill_style(Color::rgba(0, 0, 255, 255));
canvas.arc(200.0, 200.0, 50.0,0.0 * std::f64::consts::PI, 1.0 * std::f64::consts::PI);
canvas.fill();
canvas.begin_path();
canvas.set_stroke_style(Color::rgba(0, 0, 0, 255));
canvas.arc(200.0, 200.0, 50.0,0.0 * std::f64::consts::PI, 2.0 * std::f64::consts::PI);
canvas.stroke();
let mut image = Image::new();
image.set_src("assets/test.png");
canvas.draw_image_with_size(&mut image, 0.0, 0.0, 256.0, 256.0);
stdweb::event_loop();
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>stdweb • Canvas</title>
<style>
html, body {
margin: 0px;
padding: 0px;
}
canvas {
display: block;
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="simple.js"></script>
</body>
</html>
\ No newline at end of file
use super::super::super::Surface;
use super::super::super::RenderEngine;
use std::rc::Rc;
use std::cell::RefCell;
use orbclient::Color;
use orbimage::Image;
use crate::api::{Color, Image};
pub struct Canvas {
pub render_engine: Rc<RefCell<RenderEngine>>,
......
#[cfg(not(feature = "no_std"))]
use std::fmt;
/// A color
#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Color {
pub data: u32,
}
impl Color {
/// Create a new color from RGB
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Color {
data: 0xFF000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
}
}
/// Set the alpha
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Color {
data: ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
}
}
/// Get the r value
pub fn r(&self) -> u8 {
((self.data & 0x00FF0000) >> 16) as u8
}
/// Get the g value
pub fn g(&self) -> u8 {
((self.data & 0x0000FF00) >> 8) as u8
}
/// Get the b value
pub fn b(&self) -> u8 {
(self.data & 0x000000FF) as u8
}
/// Get the alpha value
pub fn a(&self) -> u8 {
((self.data & 0xFF000000) >> 24) as u8
}
/// Interpolate between two colors
pub fn interpolate(start_color: Color, end_color: Color, scale: f64) -> Color {
let r = Color::interp(start_color.r(), end_color.r(), scale);
let g = Color::interp(start_color.g(), end_color.g(), scale);
let b = Color::interp(start_color.b(), end_color.b(), scale);
let a = Color::interp(start_color.a(), end_color.a(), scale);
Color::rgba(r, g, b, a)
}
fn interp(start_color: u8, end_color: u8, scale: f64) -> u8 {
((end_color as f64 - start_color as f64) * scale + start_color as f64) as u8
}
}
impl ToString for Color {
fn to_string(&self) -> String {
let mut color = format!("#{:x}", self.data);
color.remove(1);
color.remove(1);
color
}
}
/// Compare two colors (Do not take care of alpha)
impl PartialEq for Color {
fn eq(&self, other: &Color) -> bool {
self.r() == other.r() && self.g() == other.g() && self.b() == other.b()
}
}
#[cfg(not(feature = "no_std"))]
impl fmt::Debug for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:#010X}", { self.data })
}
}
#[cfg(test)]
mod tests {
#[test]
fn partial_eq() {
use Color;
assert_eq!(true, Color::rgb(1, 2, 3) == Color::rgba(1, 2, 3, 200));
assert_eq!(false, Color::rgb(1, 2, 3) == Color::rgba(11, 2, 3, 200));
assert_eq!(true, Color::rgba(1, 2, 3, 200) == Color::rgba(1, 2, 3, 200));
}
}
pub use self::canvas::*;
mod canvas;
#[cfg(target_arch = "wasm32")]
pub use self::color::*;
#[cfg(not(target_arch = "wasm32"))]
pub use orbclient::Color;
#[cfg(not(target_arch = "wasm32"))]
pub use orbimage::Image as Image;
#[cfg(target_arch = "wasm32")]
pub use stdweb::web::html_element::ImageElement as Image;
#[cfg(target_arch = "wasm32")]
mod color;
......@@ -2,13 +2,20 @@
#![crate_type = "lib"]
extern crate core;
#[cfg(not(target_arch = "wasm32"))]
extern crate orbclient;
#[cfg(not(target_arch = "wasm32"))]
extern crate orbimage;
extern crate rust_cairo;
pub use orbclient::Color;
#[cfg(not(target_arch = "wasm32"))]
extern crate rust_cairo;
#[cfg(target_arch = "wasm32")]
extern crate stdweb;
pub use crate::api::Color;
pub use api::*;
pub mod api;
......@@ -16,9 +23,11 @@ pub mod api;
pub use render_engine::*;
pub mod render_engine;
#[cfg(not(target_arch = "wasm32"))]
pub use surface::*;
pub mod surface;
#[cfg(not(target_arch = "wasm32"))]
pub mod surface;
/*
/// Canvas components
......
use rust_cairo::*;
use super::super::RenderEngine;
use orbclient::Color;
use crate::api::Color;
use std::rc::Rc;
use std::cell::RefCell;
......
use orbclient::Color;
use crate::api::Color;
#[derive(Copy, Clone)]
pub struct CanvasPaintState {
......
#[cfg(not(target_arch = "wasm32"))]
pub use self::orbgl::*;
#[cfg(not(target_arch = "wasm32"))]
mod orbgl;
#[cfg(not(target_arch = "wasm32"))]
pub use self::cairo::*;
#[cfg(not(target_arch = "wasm32"))]
mod cairo;
#[cfg(target_arch = "wasm32")]
pub use self::web::*;
#[cfg(target_arch = "wasm32")]
mod web;
pub use self::render_engine::*;
mod render_engine;
use orbclient::Color;
use crate::api::Color;
use super::matrix::Matrix;
#[derive(Copy, Clone)]
......
use super::super::RenderEngine;
use orbclient::Color;
use crate::api::Color;
use std::rc::Rc;
use std::cell::RefCell;
use super::super::super::Surface;
......
use orbclient::Color;
use crate::api::{Color, Image};
use std::rc::Rc;
use std::cell::RefCell;
use super::super::Surface;
use orbimage::Image;
pub trait RenderEngine {
fn save(&mut self) { println!("RenderEngine: 'save' is not implemented."); }
......@@ -28,6 +26,8 @@ pub trait RenderEngine {
fn set_fill_style(&mut self, color: Color) { println!("RenderEngine: 'set_fill_style' is not implemented."); }
fn set_stroke_style(&mut self, color: Color) { println!("RenderEngine: 'set_stroke_style' is not implemented."); }
fn set_line_width(&mut self, line_width: f64) { println!("RenderEngine: 'set_line_width' is not implemented."); }
fn draw_image(&mut self, image: &mut Image, x: f64, y: f64) { println!("RenderEngine: 'draw_image' is not implemented.") }
fn draw_image_with_size(&mut self, image: &mut Image, x: f64, y: f64, width: f64, height: f64) { println!("RenderEngine: 'draw_image_with_size' is not implemented.") }
fn draw_image_with_clip_and_size(&mut self, image: &mut Image, clip_x: f64, clip_y: f64, clip_width: f64, clip_height: f64, x: f64, y: f64, width: f64, height: f64) { println!("RenderEngine: 'draw_image_with_size' is not implemented.") }
......
pub use self::web_render_engine::*;
mod web_render_engine;
\ No newline at end of file
use std::{cell::RefCell, rc::Rc};
use stdweb::web::{CanvasRenderingContext2d, FillRule};
use stdweb::{
_js_impl, js,
};
use crate::{
api::{Color, Image},
render_engine::RenderEngine,
};
pub struct WebRenderEngine {
context: CanvasRenderingContext2d,
}
impl WebRenderEngine {
pub fn new(context: CanvasRenderingContext2d) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(WebRenderEngine { context }))
}
}
impl RenderEngine for WebRenderEngine {
fn save(&mut self) {
self.context.save();
}
fn restore(&mut self) {
self.context.restore();
}
fn fill(&mut self) {
self.context.fill(FillRule::default());
}
fn stroke(&mut self) {
self.context.stroke();
}
fn begin_path(&mut self) {
self.context.begin_path();
}
fn close_path(&mut self) {
self.context.close_path();
}
fn arc(&mut self, x: f64, y: f64, radius: f64, start_segment: f64, end_segment: f64) {
self.context
.arc(x, y, radius, start_segment, end_segment, false);
}
fn move_to(&mut self, x: f64, y: f64) {
self.context.move_to(x, y);
}
fn line_to(&mut self, x: f64, y: f64) {
self.context.line_to(x, y);
}
/*
fn quadratic_curve_to(&mut self, cpx: f64, cpy: f64, x: f64, y: f64) {
unsafe {
}
}
*/
fn bezier_curve_to(&mut self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
self.context.bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y);
}
fn rect(&mut self, x: f64, y: f64, width: f64, height: f64) {
self.context.rect(x, y, width, height);
}
fn fill_rect(&mut self, x: f64, y: f64, width: f64, height: f64) {
self.context.fill_rect(x, y, width, height);
}
fn stroke_rect(&mut self, x: f64, y: f64, width: f64, height: f64) {
self.context.stroke_rect(x, y, width, height);
}
fn clear_rect(&mut self, x: f64, y: f64, width: f64, height: f64) {
self.context.clear_rect(x, y, width, height);
}
fn scale(&mut self, sx: f64, sy: f64) {
self.context.scale(sx, sy);
}
fn rotate(&mut self, angle: f64) {
self.context.rotate(angle);
}
fn translate(&mut self, tx: f64, ty: f64) {
self.context.translate(tx, ty);
}
fn transform(&mut self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
self.context.transform(a, b, c, d, e, f);
}
fn set_transform(&mut self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
self.context.set_transform(a, b, c, d, e, f);
}
fn set_fill_style(&mut self, color: Color) {
self.context.set_fill_style_color(&color.to_string());
}
fn set_stroke_style(&mut self, color: Color) {
self.context.set_stroke_style_color(&color.to_string());
}
fn set_line_width(&mut self, line_width: f64) {
self.set_line_width(line_width);
}
fn draw_image(&mut self, image: &mut Image, x: f64, y: f64) {
let image = image.clone();
js! {
var img = @{&image};
var context = @{&self.context};
img.onload = function() {
context.drawImage(@{&image}, @{&x}, @{&y});</