mirror of
https://github.com/enso-org/enso.git
synced 2024-12-29 05:11:34 +03:00
Performance fine-tuning & monitoring (https://github.com/enso-org/ide/pull/95)
Original commit: 4351c60828
This commit is contained in:
parent
cd95b281e8
commit
5af7a0fd2f
@ -13,5 +13,14 @@ members = [
|
|||||||
"lib/system/web",
|
"lib/system/web",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
lto = false
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
lto = true
|
||||||
|
|
||||||
|
[profile.bench]
|
||||||
|
opt-level = 3
|
||||||
|
lto = true
|
||||||
|
105
gui/README.md
105
gui/README.md
@ -1,23 +1,24 @@
|
|||||||
[![License](https://img.shields.io/static/v1?label=License&message=MIT&color=2ec352&labelColor=2c3239)](https://github.com/luna/basegl/blob/master/LICENSE) [![Actions Status](https://github.com/luna/basegl/workflows/Build%20%28MacOS%2C%20Linux%2C%20Windows%29/badge.svg)](https://github.com/luna/basegl/actions) [![Coverage](https://img.shields.io/codecov/c/github/luna/basegl?label=Coverage&labelColor=2c3239)](https://codecov.io/gh/luna/basegl/branch/master)
|
[![License](https://img.shields.io/static/v1?label=License&message=MIT&color=2ec352&labelColor=2c3239)](https://github.com/luna/basegl/blob/master/LICENSE)
|
||||||
|
[![Actions Status](https://github.com/luna/basegl/workflows/Build%20%28MacOS%2C%20Linux%2C%20Windows%29/badge.svg)](https://github.com/luna/basegl/actions)
|
||||||
|
[![Coverage](https://img.shields.io/codecov/c/github/luna/basegl?label=Coverage&labelColor=2c3239)](https://codecov.io/gh/luna/basegl/branch/master)
|
||||||
![Stability](https://img.shields.io/static/v1?label=Stability&message=Unstable&color=d52229&labelColor=2c3239)
|
![Stability](https://img.shields.io/static/v1?label=Stability&message=Unstable&color=d52229&labelColor=2c3239)
|
||||||
|
|
||||||
# BaseGL
|
# BaseGL
|
||||||
|
|
||||||
BaseGL is a blazing fast 2D drawing API. This repository is a work in progress
|
BaseGL is a blazing fast 2D vector rendering engine with a rich set of
|
||||||
of BaseGL 2.0. Please refer to BaseGL 1.0 repository for more information:
|
primitives and a GUI component library. It is able to display millions of shapes
|
||||||
https://github.com/luna/basegl-old.
|
60 frames per second in a web browser on a modern laptop hardware.
|
||||||
|
|
||||||
## Working with the code
|
This repository is a work in progress of BaseGL 2.0. Please refer to BaseGL 1.0
|
||||||
|
repository for more information: https://github.com/luna/basegl-old.
|
||||||
|
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
### The Rust toolchain
|
### The Rust toolchain
|
||||||
|
This project uses several features available only in the nightly Rust toolchain.
|
||||||
In order to use some of the WASM pipeline features we need to use a nightly Rust
|
To setup the toolchain, please use the [the Rust toolchain
|
||||||
channel. The same applies to the code auto-formatter and it's advanced
|
installer](https://rustup.rs/):
|
||||||
configuration options used here. You would neither be able to compile not format
|
|
||||||
the code using the stable branch.
|
|
||||||
|
|
||||||
To setup the toolchain, please use the [the Rust toolchain installer
|
|
||||||
](https://rustup.rs/):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rustup toolchain install nightly-2019-11-04 # Install the nightly channel.
|
rustup toolchain install nightly-2019-11-04 # Install the nightly channel.
|
||||||
@ -26,59 +27,59 @@ rustup component add rustfmt # Install the code auto-formatter.
|
|||||||
rustup component add clippy # Install the linter.
|
rustup component add clippy # Install the linter.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building and testing the project
|
### Building the sources
|
||||||
|
Please use the `script/build.sh` script to build the project or the
|
||||||
|
`script/watch.sh` script to run a file watch utility which will build the
|
||||||
|
project when on every source change. The scripts are thin wrappers over
|
||||||
|
[wasm-pack](https://github.com/rustwasm/wasm-pack) and accept the same [command
|
||||||
|
line arguments](https://rustwasm.github.io/wasm-pack/book/commands/build.html).
|
||||||
|
In particular, you can provide them with `--release`, `--dev`, or `--profile`
|
||||||
|
flags to switch the compilation profile. If not option is provided, the scripts
|
||||||
|
default to the `--release` profile.
|
||||||
|
|
||||||
Please use the `script/build.sh`, `script/watch.sh`, and `script/lint.sh`
|
### Running examples
|
||||||
scripts to build, watch, and lint the project respectively. We need to use a
|
Please note that in order to run the examples you have to first build the
|
||||||
simple custom wrappers here because of the several Rust toolchain issues:
|
project. For best experience, it is recommended to use the `scripts/watch.sh`
|
||||||
|
in a second shell. In order to build the demo scenes, follow the steps below:
|
||||||
- [No direct support for Cargo Workspaces in
|
|
||||||
wasm-pack.](https://github.com/rustwasm/wasm-pack/issues/642). Fixed in
|
|
||||||
`build.sh`.
|
|
||||||
- There is no watch utility in wasm-pack, which makes using it harder than it
|
|
||||||
should be. Fixed in `watch.sh`.
|
|
||||||
- [The commands cargo-check and cargo-clippy do not clean local cache if used
|
|
||||||
several times.](https://github.com/rust-lang/cargo/issues/6986). Fixed in
|
|
||||||
`lint.sh`.
|
|
||||||
|
|
||||||
In order to build an example demo scene, please use the following commands:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./script/watch.sh # Build and watch for changes.
|
cd examples
|
||||||
|
|
||||||
# Wait till the project finishes building.
|
|
||||||
# Run the following lines from other cmd:
|
|
||||||
|
|
||||||
cd examples/01-scene
|
|
||||||
npm install
|
npm install
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
You can now open the following address in your browser: http://localhost:8080.
|
You can now navigate to http://localhost:8080 and play with the demo scenes!
|
||||||
|
|
||||||
There are also _web test_ which are run in browser and produce some output. To
|
Please note that `npm run start` runs the Webpack Dev-Server in the production
|
||||||
run them, pick a test suite (`html_renderer` for instance) and run:
|
mode. You can use the `npm run start-dev` in order to enable the development
|
||||||
```bash
|
mode, however, as all sources are provided to Webpack in form of WASM binaries,
|
||||||
wasm-pack test lib/core --chrome --release -- --test html_renderer
|
we haven't observed any differences between them in this project.
|
||||||
```
|
|
||||||
Now the test output is available at http://127.0.0.1:8000. There are benchmark
|
While Webpack provides handy utilities for development, like live-reloading on
|
||||||
tests too (that's why `--release` flag is recommended).
|
sources change, it also adds some runtime overhead. In order to run the compiled
|
||||||
|
examples using a lightweight http-server (without live-reloading functionality),
|
||||||
|
please use the `npm run prod-server` command.
|
||||||
|
|
||||||
|
**Please remember to disable the cache in your browser during development!**
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
The sources use both unit tests and web test, which are run in a browser and
|
||||||
|
produce visual results. To run them, use the `scripts/test.sh` script and follow
|
||||||
|
the output in the terminal.
|
||||||
|
|
||||||
**Please remember to disable the cache in your browser!**
|
|
||||||
|
|
||||||
### Working with the source code
|
### Working with the source code
|
||||||
|
|
||||||
#### Formatting
|
#### Formatting
|
||||||
|
Please note that this codebase does not use `rustfmt`. Please read the following
|
||||||
All codebase should be auto-formatted using `rustfmt`. It is highly recommended
|
documents to learn more about reasons behind this decision and the recommended
|
||||||
that you use an IDE which takes care of formatting the code as you type. Please
|
code style guide. Be sure to carefully read the documents before contributing to
|
||||||
remember that auto-formatting does not mean you should not care of the way your
|
this repository:
|
||||||
code looks and feels! Be sure to carefully read the [Rust style
|
- [Rust style guide](https://github.com/luna/basegl/blob/master/docs/style-guide.md)
|
||||||
guide](https://github.com/luna/enso/blob/master/doc/rust-style-guide.md) and
|
- [Rust style
|
||||||
apply it everywhere in your codebase.
|
guide](https://github.com/luna/enso/blob/master/doc/rust-style-guide.md)
|
||||||
|
|
||||||
|
|
||||||
#### Linting
|
#### Linting
|
||||||
|
Please be sure to fix all errors reported by `scripts/lint.sh` before creating a
|
||||||
Please be sure to fix all errors reported by `cargo clippy` before creating a
|
|
||||||
pull request to this repository.
|
pull request to this repository.
|
||||||
|
1
gui/examples/.gitignore
vendored
1
gui/examples/.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
package-lock.json
|
|
@ -11,7 +11,7 @@ function hello_screen(msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(msg==="" && msg===null && msg===undefined) {
|
if(msg==="" || msg===null || msg===undefined) {
|
||||||
msg = ""
|
msg = ""
|
||||||
}
|
}
|
||||||
let newDiv = document.createElement("div");
|
let newDiv = document.createElement("div");
|
||||||
|
5646
gui/examples/package-lock.json
generated
Normal file
5646
gui/examples/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "example-scene",
|
"name": "example-scenes",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Example Scene",
|
"description": "Example Scenes",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"create-wasm-app": ".bin/create-wasm-app.js"
|
"create-wasm-app": ".bin/create-wasm-app.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.prod.js",
|
||||||
"start": "webpack-dev-server"
|
"build-dev": "webpack --config webpack.dev.js",
|
||||||
|
"start": "webpack-dev-server --config webpack.prod.js",
|
||||||
|
"start-dev": "webpack-dev-server --config webpack.dev.js",
|
||||||
|
"prod-server": "npx http-server -p 3000 --proxy http://localhost:3000\\? dist"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
|
"url": "git@github.com:luna/basegl.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"webassembly",
|
"webassembly",
|
||||||
@ -20,19 +23,20 @@
|
|||||||
"rust",
|
"rust",
|
||||||
"webpack"
|
"webpack"
|
||||||
],
|
],
|
||||||
"author": "Ashley Williams <ashley666ashley@gmail.com>",
|
"author": "Enso Team (contact@luna-lang.org)",
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"license": "(MIT OR Apache-2.0)",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/rustwasm/create-wasm-app/issues"
|
"url": "https://github.com/luna/basegl/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
|
"homepage": "https://github.com/luna/basegl",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"basegl": "file:../target/web",
|
|
||||||
"copy-webpack-plugin": "^5.1.1",
|
"copy-webpack-plugin": "^5.1.1",
|
||||||
"hello-wasm-pack": "^0.1.0",
|
|
||||||
"html-webpack-plugin": "^3.2.0",
|
|
||||||
"webpack": "^4.29.3",
|
"webpack": "^4.29.3",
|
||||||
"webpack-cli": "^3.1.0",
|
"webpack-cli": "^3.1.0",
|
||||||
"webpack-dev-server": "^3.1.5"
|
"webpack-dev-server": "^3.1.5",
|
||||||
|
"webpack-merge": "^4.2.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"basegl": "file:../target/web"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,30 @@
|
|||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
const CopyWebpackPlugin = require("copy-webpack-plugin")
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const mb = 1024 * 1024;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: "./bootstrap.js",
|
entry: "./bootstrap.js",
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
filename: "bootstrap.js",
|
filename: "bootstrap.js",
|
||||||
},
|
},
|
||||||
mode: "development",
|
|
||||||
node: {
|
node: {
|
||||||
fs: 'empty'
|
fs: 'empty'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin(['index.html']),
|
new CopyWebpackPlugin(['index.html']),
|
||||||
// new HtmlWebpackPlugin({template: 'index.html'}),
|
|
||||||
],
|
],
|
||||||
devServer: {
|
devServer: {
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
index: 'index.html'
|
index: 'index.html'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
resolve: {
|
||||||
|
modules: [path.resolve(__dirname, "node_modules")]
|
||||||
|
},
|
||||||
|
performance: {
|
||||||
|
hints: 'error',
|
||||||
|
maxAssetSize: 3.7 * mb,
|
||||||
|
},
|
||||||
};
|
};
|
10
gui/examples/webpack.dev.js
Normal file
10
gui/examples/webpack.dev.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const merge = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: '',
|
||||||
|
devServer: {
|
||||||
|
contentBase: './dist',
|
||||||
|
},
|
||||||
|
});
|
6
gui/examples/webpack.prod.js
Normal file
6
gui/examples/webpack.prod.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const merge = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'production',
|
||||||
|
});
|
@ -44,6 +44,7 @@ features = [
|
|||||||
'Element',
|
'Element',
|
||||||
'HtmlElement',
|
'HtmlElement',
|
||||||
'HtmlCollection',
|
'HtmlCollection',
|
||||||
|
'CanvasRenderingContext2d',
|
||||||
'CssStyleDeclaration',
|
'CssStyleDeclaration',
|
||||||
'HtmlCanvasElement',
|
'HtmlCanvasElement',
|
||||||
'WebGlBuffer',
|
'WebGlBuffer',
|
||||||
|
@ -1,2 +1 @@
|
|||||||
pub mod callback;
|
pub mod callback;
|
||||||
pub mod event_loop;
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
pub mod monitor;
|
603
gui/lib/core/src/debug/monitor.rs
Normal file
603
gui/lib/core/src/debug/monitor.rs
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use js_sys::ArrayBuffer;
|
||||||
|
use js_sys::WebAssembly::Memory;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::f64;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen;
|
||||||
|
use web_sys::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// === Helpers ===
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
fn window() -> web_sys::Window {
|
||||||
|
web_sys::window().unwrap_or_else(|| panic!("Cannot access window."))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn document() -> web_sys::Document {
|
||||||
|
window().document().unwrap_or_else(|| panic!("Cannot access window.document."))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn body() -> web_sys::HtmlElement {
|
||||||
|
document().body().unwrap_or_else(|| panic!("Cannot access window.document.body."))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn performance() -> Performance {
|
||||||
|
window().performance().unwrap_or_else(|| panic!("Cannot access window.performance."))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ==============
|
||||||
|
// === Config ===
|
||||||
|
// ==============
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
pub struct ConfigTemplate<Str,Num> {
|
||||||
|
pub background_color : Str,
|
||||||
|
pub label_color_ok : Str,
|
||||||
|
pub label_color_warn : Str,
|
||||||
|
pub label_color_err : Str,
|
||||||
|
pub plot_color_ok : Str,
|
||||||
|
pub plot_color_warn : Str,
|
||||||
|
pub plot_color_err : Str,
|
||||||
|
pub plot_background_color : Str,
|
||||||
|
pub plot_step_size : Num,
|
||||||
|
pub margin : Num,
|
||||||
|
pub panel_height : Num,
|
||||||
|
pub labels_width : Num,
|
||||||
|
pub results_width : Num,
|
||||||
|
pub plots_width : Num,
|
||||||
|
pub font_size : Num,
|
||||||
|
pub font_vertical_offset : Num,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Config = ConfigTemplate<String,u32>;
|
||||||
|
pub type SamplerConfig = ConfigTemplate<JsValue,f64>;
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Config {
|
||||||
|
Config {
|
||||||
|
background_color : "#222222".into(),
|
||||||
|
label_color_ok : "#8e939a".into(),
|
||||||
|
label_color_warn : "#ffba18".into(),
|
||||||
|
label_color_err : "#eb3941".into(),
|
||||||
|
plot_color_ok : "#8e939a".into(),
|
||||||
|
plot_color_warn : "#ffba18".into(),
|
||||||
|
plot_color_err : "#eb3941".into(),
|
||||||
|
plot_background_color : "#333333".into(),
|
||||||
|
plot_step_size : 1,
|
||||||
|
margin : 4,
|
||||||
|
panel_height : 15,
|
||||||
|
labels_width : 120,
|
||||||
|
results_width : 30,
|
||||||
|
plots_width : 100,
|
||||||
|
font_size : 9,
|
||||||
|
font_vertical_offset : 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn to_plot_config(&self) -> SamplerConfig {
|
||||||
|
let ratio = window().device_pixel_ratio();
|
||||||
|
SamplerConfig {
|
||||||
|
background_color : (&self.background_color) . into(),
|
||||||
|
label_color_ok : (&self.label_color_ok) . into(),
|
||||||
|
label_color_warn : (&self.label_color_warn) . into(),
|
||||||
|
label_color_err : (&self.label_color_err) . into(),
|
||||||
|
plot_color_ok : (&self.plot_color_ok) . into(),
|
||||||
|
plot_color_warn : (&self.plot_color_warn) . into(),
|
||||||
|
plot_color_err : (&self.plot_color_err) . into(),
|
||||||
|
plot_background_color : (&self.plot_background_color) . into(),
|
||||||
|
plot_step_size : self.plot_step_size as f64 * ratio,
|
||||||
|
margin : self.margin as f64 * ratio,
|
||||||
|
panel_height : self.panel_height as f64 * ratio,
|
||||||
|
labels_width : self.labels_width as f64 * ratio,
|
||||||
|
results_width : self.results_width as f64 * ratio,
|
||||||
|
plots_width : self.plots_width as f64 * ratio,
|
||||||
|
font_size : self.font_size as f64 * ratio,
|
||||||
|
font_vertical_offset : self.font_vertical_offset as f64 * ratio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// === Monitor ===
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Monitor {
|
||||||
|
user_config : Config,
|
||||||
|
config : SamplerConfig,
|
||||||
|
width : f64,
|
||||||
|
height : f64,
|
||||||
|
dom : Element,
|
||||||
|
panels : Vec<Panel>,
|
||||||
|
canvas : HtmlCanvasElement,
|
||||||
|
context : CanvasRenderingContext2d,
|
||||||
|
is_first_draw : bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Public API ===
|
||||||
|
|
||||||
|
// TODO: All the `unwraps` below should be handled nicer when this lib will be finished.
|
||||||
|
|
||||||
|
impl Default for Monitor {
|
||||||
|
fn default() -> Self {
|
||||||
|
let user_config: Config = default();
|
||||||
|
let panels = default();
|
||||||
|
let width = default();
|
||||||
|
let height = default();
|
||||||
|
let is_first_draw = true;
|
||||||
|
let config = user_config.to_plot_config();
|
||||||
|
|
||||||
|
let dom = document().create_element("div").unwrap();
|
||||||
|
dom.set_attribute("style", "position:absolute;").unwrap();
|
||||||
|
body().prepend_with_node_1(&dom).unwrap();
|
||||||
|
|
||||||
|
let canvas = document().create_element("canvas").unwrap();
|
||||||
|
let canvas: HtmlCanvasElement = canvas.dyn_into().unwrap();
|
||||||
|
|
||||||
|
let context = canvas.get_context("2d").unwrap().unwrap();
|
||||||
|
let context: CanvasRenderingContext2d = context.dyn_into().unwrap();
|
||||||
|
dom.append_child(&canvas).unwrap();
|
||||||
|
|
||||||
|
let mut out = Self{user_config,config,width,height,dom,panels,canvas,context,is_first_draw};
|
||||||
|
out.update_config();
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor {
|
||||||
|
/// Creates a new, empty monitor instance. Ise the `add` method to fill it with samplers.
|
||||||
|
pub fn new() -> Self { default() }
|
||||||
|
|
||||||
|
/// Modifies the Monitor's config and updates the view.
|
||||||
|
pub fn mod_config<F:FnOnce(&mut Config)>(&mut self, f:F) {
|
||||||
|
f(&mut self.user_config);
|
||||||
|
self.update_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds new display element.
|
||||||
|
pub fn add<M:Sampler+'static>(&mut self, monitor:M) -> Panel {
|
||||||
|
let panel = Panel::new(self.context.clone(),self.config.clone(),monitor);
|
||||||
|
self.panels.push(panel.clone());
|
||||||
|
self.resize();
|
||||||
|
panel
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws the Monitor and updates all of it's values.
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
if self.is_first_draw {
|
||||||
|
self.is_first_draw = false;
|
||||||
|
self.first_draw();
|
||||||
|
}
|
||||||
|
self.shift_plot_area_left();
|
||||||
|
self.clear_labels_area();
|
||||||
|
self.draw_plots();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Private API ===
|
||||||
|
|
||||||
|
impl Monitor {
|
||||||
|
fn update_config(&mut self) {
|
||||||
|
self.config = self.user_config.to_plot_config()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self) {
|
||||||
|
let width = self.config.labels_width
|
||||||
|
+ self.config.results_width
|
||||||
|
+ self.config.plots_width
|
||||||
|
+ 4.0 * self.config.margin;
|
||||||
|
let mut height = 0.0;
|
||||||
|
for _panel in &self.panels {
|
||||||
|
height += self.config.margin + self.config.panel_height;
|
||||||
|
}
|
||||||
|
height += self.config.margin;
|
||||||
|
|
||||||
|
let u_width = width as u32;
|
||||||
|
let u_height = height as u32;
|
||||||
|
let style = format!("width:{}px; height:{}px",u_width/2,u_height/2);
|
||||||
|
self.width = width;
|
||||||
|
self.height = height;
|
||||||
|
self.canvas.set_width (u_width);
|
||||||
|
self.canvas.set_height (u_height);
|
||||||
|
self.canvas.set_attribute("style",&style).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shift_plot_area_left(&mut self) {
|
||||||
|
let width = self.width as f64;
|
||||||
|
let height = self.height as f64;
|
||||||
|
let shift = -(self.config.plot_step_size as f64);
|
||||||
|
self.context.draw_image_with_html_canvas_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh
|
||||||
|
(&self.canvas,0.0,0.0,width,height,shift,0.0,self.width,self.height).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_labels_area(&mut self) {
|
||||||
|
let step = self.config.plot_step_size;
|
||||||
|
let width = self.config.labels_width + self.config.results_width + 3.0 * self.config.margin;
|
||||||
|
self.context.set_fill_style(&self.config.background_color);
|
||||||
|
self.context.fill_rect(0.0,0.0,width,self.height);
|
||||||
|
self.context.fill_rect(self.width-step,0.0,step,self.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_plots(&mut self) {
|
||||||
|
self.with_all_panels(|panel| panel.draw());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_draw(&self) {
|
||||||
|
self.context.set_fill_style(&self.config.background_color);
|
||||||
|
self.context.fill_rect(0.0,0.0,self.width,self.height);
|
||||||
|
self.with_all_panels(|panel| panel.first_draw());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_all_panels<F:Fn(&Panel)>(&self,f:F) {
|
||||||
|
let mut total_off = 0.0;
|
||||||
|
for panel in &self.panels {
|
||||||
|
let off = self.config.margin;
|
||||||
|
self.context.translate(0.0,off).unwrap();
|
||||||
|
total_off += off;
|
||||||
|
f(panel);
|
||||||
|
let off = self.config.panel_height;
|
||||||
|
self.context.translate(0.0,off).unwrap();
|
||||||
|
total_off += off;
|
||||||
|
}
|
||||||
|
self.context.translate(0.0,-total_off).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =============
|
||||||
|
// === Panel ===
|
||||||
|
// =============
|
||||||
|
|
||||||
|
/// A single element in the `Monitor`. It can display labels, values and plots. Each `Panel` uses
|
||||||
|
/// a `Sampler` under the hood, which defines both its behavior and its look and feel.
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
pub struct Panel {
|
||||||
|
rc: Rc<RefCell<PanelData>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Panel {
|
||||||
|
/// Creates a new, empty Panel with a given sampler.
|
||||||
|
pub fn new<S:Sampler+'static>
|
||||||
|
(context:CanvasRenderingContext2d, config:SamplerConfig, sampler:S) -> Self {
|
||||||
|
let rc = Rc::new(RefCell::new(PanelData::new(context,config,sampler)));
|
||||||
|
Self {rc}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display results of last measurements.
|
||||||
|
pub fn draw(&self) {
|
||||||
|
self.rc.borrow_mut().draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start measuring the data.
|
||||||
|
pub fn begin(&self) {
|
||||||
|
self.rc.borrow_mut().begin()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop measuring the data.
|
||||||
|
pub fn end(&self) {
|
||||||
|
self.rc.borrow_mut().end()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_draw(&self) {
|
||||||
|
self.rc.borrow_mut().first_draw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// === ValueCheck ===
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
#[derive(Copy,Clone,Debug)]
|
||||||
|
pub enum ValueCheck {Correct,Warning,Error}
|
||||||
|
|
||||||
|
impl Default for ValueCheck {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Correct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============
|
||||||
|
// === Sampler ===
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
pub trait Sampler: Debug {
|
||||||
|
fn label (&self) -> &str;
|
||||||
|
fn begin (&mut self, _time:f64) {}
|
||||||
|
fn end (&mut self, _time:f64) {}
|
||||||
|
fn value (&self) -> f64;
|
||||||
|
fn check (&self) -> ValueCheck { ValueCheck::Correct }
|
||||||
|
fn max_value (&self) -> Option<f64> { None }
|
||||||
|
fn min_value (&self) -> Option<f64> { None }
|
||||||
|
fn min_size (&self) -> Option<f64> { None }
|
||||||
|
fn smooth_range (&self) -> usize { 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =================
|
||||||
|
// === PanelData ===
|
||||||
|
// =================
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PanelData {
|
||||||
|
label : String,
|
||||||
|
context : CanvasRenderingContext2d,
|
||||||
|
performance : Performance,
|
||||||
|
config : SamplerConfig,
|
||||||
|
min_value : f64,
|
||||||
|
max_value : f64,
|
||||||
|
begin_value : f64,
|
||||||
|
value : f64,
|
||||||
|
last_values : VecDeque<f64>,
|
||||||
|
norm_value : f64,
|
||||||
|
draw_offset : f64,
|
||||||
|
value_check : ValueCheck,
|
||||||
|
sampler : Box<dyn Sampler>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Construction ===
|
||||||
|
|
||||||
|
impl PanelData {
|
||||||
|
pub fn new<S:Sampler+'static>
|
||||||
|
(context:CanvasRenderingContext2d, config:SamplerConfig, sampler:S) -> Self {
|
||||||
|
let label = sampler.label().into();
|
||||||
|
let performance = performance();
|
||||||
|
let min_value = f64::INFINITY;
|
||||||
|
let max_value = f64::NEG_INFINITY;
|
||||||
|
let begin_value = default();
|
||||||
|
let value = default();
|
||||||
|
let last_values = default();
|
||||||
|
let norm_value = default();
|
||||||
|
let draw_offset = 0.0;
|
||||||
|
let value_check = default();
|
||||||
|
let sampler = Box::new(sampler);
|
||||||
|
Self {label,context,performance,config,min_value,max_value,begin_value,value,last_values
|
||||||
|
,norm_value,draw_offset,value_check,sampler}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Begin / End ===
|
||||||
|
|
||||||
|
impl PanelData {
|
||||||
|
pub fn begin(&mut self) {
|
||||||
|
let time = self.performance.now();
|
||||||
|
self.sampler.begin(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end(&mut self) {
|
||||||
|
let time = self.performance.now();
|
||||||
|
self.sampler.end(time);
|
||||||
|
self.value_check = self.sampler.check();
|
||||||
|
self.value = self.sampler.value();
|
||||||
|
self.clamp_value();
|
||||||
|
self.smooth_value();
|
||||||
|
self.normalize_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clamp_value(&mut self) {
|
||||||
|
if let Some(max_value) = self.sampler.max_value() {
|
||||||
|
if self.value > max_value { self.value = max_value; }
|
||||||
|
}
|
||||||
|
if let Some(min_value) = self.sampler.min_value() {
|
||||||
|
if self.value > min_value { self.value = min_value; }
|
||||||
|
}
|
||||||
|
if self.value > self.max_value { self.max_value = self.value; }
|
||||||
|
if self.value < self.min_value { self.min_value = self.value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smooth_value(&mut self) {
|
||||||
|
self.last_values.push_front(self.value);
|
||||||
|
if self.last_values.len() > self.sampler.smooth_range() {
|
||||||
|
self.last_values.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.value = self.last_values.iter().sum();
|
||||||
|
self.value /= self.last_values.len() as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_value(&mut self) {
|
||||||
|
let mut size = self.max_value - self.min_value;
|
||||||
|
if let Some(min_size) = self.sampler.min_size() {
|
||||||
|
if size < min_size { size = min_size; }
|
||||||
|
}
|
||||||
|
self.norm_value = (self.value - self.min_value) / size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Draw ===
|
||||||
|
|
||||||
|
impl PanelData {
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.init_draw();
|
||||||
|
self.draw_plots();
|
||||||
|
self.finish_draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn first_draw(&mut self) {
|
||||||
|
self.init_draw();
|
||||||
|
self.context.set_fill_style(&self.config.plot_background_color);
|
||||||
|
self.context.fill_rect(0.0,0.0,self.config.plots_width,self.config.panel_height);
|
||||||
|
self.finish_draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_pen_to_next_element(&mut self, offset:f64) {
|
||||||
|
self.context.translate(offset,0.0).unwrap();
|
||||||
|
self.draw_offset += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_draw(&mut self) {
|
||||||
|
self.context.translate(-self.draw_offset,0.0).unwrap();
|
||||||
|
self.draw_offset = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_draw(&mut self) {
|
||||||
|
self.move_pen_to_next_element(self.config.margin);
|
||||||
|
self.draw_labels();
|
||||||
|
self.draw_results();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_labels(&mut self) {
|
||||||
|
let fonts = "Helvetica,Arial,sans-serif";
|
||||||
|
let y_pos = self.config.panel_height - self.config.font_vertical_offset;
|
||||||
|
self.context.set_font(&format!("bold {}px {}",self.config.font_size,fonts));
|
||||||
|
self.context.set_text_align("right");
|
||||||
|
self.context.set_fill_style(&self.config.label_color_ok);
|
||||||
|
self.context.fill_text(&self.label,self.config.labels_width,y_pos).unwrap();
|
||||||
|
self.move_pen_to_next_element(self.config.labels_width + self.config.margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_results(&mut self) {
|
||||||
|
let display_value = (self.value * 100.0).round() / 100.0;
|
||||||
|
let display_value = format!("{:.*}",2,display_value);
|
||||||
|
let y_pos = self.config.panel_height - self.config.font_vertical_offset;
|
||||||
|
let color = match self.value_check {
|
||||||
|
ValueCheck::Correct => &self.config.label_color_ok,
|
||||||
|
ValueCheck::Warning => &self.config.label_color_warn,
|
||||||
|
ValueCheck::Error => &self.config.label_color_err
|
||||||
|
};
|
||||||
|
self.context.set_fill_style(color);
|
||||||
|
self.context.fill_text(&display_value,self.config.results_width,y_pos).unwrap();
|
||||||
|
self.move_pen_to_next_element(self.config.results_width + self.config.margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_plots(&mut self) {
|
||||||
|
self.move_pen_to_next_element(self.config.plots_width - self.config.plot_step_size);
|
||||||
|
self.context.set_fill_style(&self.config.plot_background_color);
|
||||||
|
self.context.fill_rect(0.0,0.0,self.config.plot_step_size,self.config.panel_height);
|
||||||
|
let value_height = self.norm_value * self.config.panel_height;
|
||||||
|
let y_pos = self.config.panel_height-value_height;
|
||||||
|
let color = match self.value_check {
|
||||||
|
ValueCheck::Correct => &self.config.plot_color_ok,
|
||||||
|
ValueCheck::Warning => &self.config.plot_color_warn,
|
||||||
|
ValueCheck::Error => &self.config.plot_color_err
|
||||||
|
};
|
||||||
|
self.context.set_fill_style(color);
|
||||||
|
self.context.fill_rect(0.0,y_pos,self.config.plot_step_size,value_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================================================
|
||||||
|
// === Samplers ====================================================================================
|
||||||
|
// =================================================================================================
|
||||||
|
|
||||||
|
// =================
|
||||||
|
// === FrameTime ===
|
||||||
|
// =================
|
||||||
|
|
||||||
|
#[derive(Debug,Default)]
|
||||||
|
pub struct FrameTime {
|
||||||
|
begin_time : f64,
|
||||||
|
value : f64,
|
||||||
|
value_check : ValueCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameTime {
|
||||||
|
pub fn new() -> Self { default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sampler for FrameTime {
|
||||||
|
fn label (&self) -> &str { "Frame time (ms)" }
|
||||||
|
fn value (&self) -> f64 { self.value }
|
||||||
|
fn check (&self) -> ValueCheck { self.value_check }
|
||||||
|
fn begin (&mut self, time:f64) { self.begin_time = time; }
|
||||||
|
fn end (&mut self, time:f64) {
|
||||||
|
let end_time = time;
|
||||||
|
self.value = end_time - self.begin_time;
|
||||||
|
self.value_check =
|
||||||
|
if self.value < 1000.0 / 55.0 { ValueCheck::Correct }
|
||||||
|
else if self.value < 1000.0 / 25.0 { ValueCheck::Warning }
|
||||||
|
else { ValueCheck::Error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===========
|
||||||
|
// === Fps ===
|
||||||
|
// ===========
|
||||||
|
|
||||||
|
#[derive(Debug,Default)]
|
||||||
|
pub struct Fps {
|
||||||
|
begin_time : f64,
|
||||||
|
value : f64,
|
||||||
|
value_check : ValueCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fps {
|
||||||
|
pub fn new() -> Self { default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sampler for Fps {
|
||||||
|
fn label (&self) -> &str { "Frames per second" }
|
||||||
|
fn value (&self) -> f64 { self.value }
|
||||||
|
fn check (&self) -> ValueCheck { self.value_check }
|
||||||
|
fn max_value (&self) -> Option<f64> { Some(60.0) }
|
||||||
|
fn begin (&mut self, time:f64) {
|
||||||
|
if self.begin_time > 0.0 {
|
||||||
|
let end_time = time;
|
||||||
|
self.value = 1000.0 / (end_time - self.begin_time);
|
||||||
|
self.value_check =
|
||||||
|
if self.value >= 55.0 { ValueCheck::Correct }
|
||||||
|
else if self.value >= 25.0 { ValueCheck::Warning }
|
||||||
|
else { ValueCheck::Error };
|
||||||
|
}
|
||||||
|
self.begin_time = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// === WasmMemory ===
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
#[derive(Debug,Default)]
|
||||||
|
pub struct WasmMemory {
|
||||||
|
value : f64,
|
||||||
|
value_check : ValueCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmMemory {
|
||||||
|
pub fn new() -> Self { default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sampler for WasmMemory {
|
||||||
|
fn label (&self) -> &str { "WASM memory usage (Mb)" }
|
||||||
|
fn value (&self) -> f64 { self.value }
|
||||||
|
fn check (&self) -> ValueCheck { self.value_check }
|
||||||
|
fn min_size (&self) -> Option<f64> { Some(100.0) }
|
||||||
|
fn end (&mut self, _time:f64) {
|
||||||
|
let memory: Memory = wasm_bindgen::memory().dyn_into().unwrap();
|
||||||
|
let buffer: ArrayBuffer = memory.buffer().dyn_into().unwrap();
|
||||||
|
self.value = (buffer.byte_length() as f64) / (1024.0 * 1024.0);
|
||||||
|
self.value_check =
|
||||||
|
if self.value <= 50.0 { ValueCheck::Correct }
|
||||||
|
else if self.value <= 100.0 { ValueCheck::Warning }
|
||||||
|
else { ValueCheck::Error };
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod event_loop;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
|
|
||||||
@ -8,7 +9,6 @@ pub use crate::display::world::workspace::SymbolId;
|
|||||||
|
|
||||||
use crate::closure;
|
use crate::closure;
|
||||||
use crate::control::callback::CallbackHandle;
|
use crate::control::callback::CallbackHandle;
|
||||||
use crate::control::event_loop::EventLoop;
|
|
||||||
use crate::data::opt_vec::OptVec;
|
use crate::data::opt_vec::OptVec;
|
||||||
use crate::data::dirty;
|
use crate::data::dirty;
|
||||||
use crate::data::dirty::traits::*;
|
use crate::data::dirty::traits::*;
|
||||||
@ -19,6 +19,7 @@ use crate::system::web::group;
|
|||||||
use crate::system::web::Logger;
|
use crate::system::web::Logger;
|
||||||
use crate::display::shape::text::font::Fonts;
|
use crate::display::shape::text::font::Fonts;
|
||||||
|
|
||||||
|
use event_loop::EventLoop;
|
||||||
use eval_tt::*;
|
use eval_tt::*;
|
||||||
|
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ pub struct World {
|
|||||||
pub event_loop : EventLoop,
|
pub event_loop : EventLoop,
|
||||||
pub fonts : Fonts,
|
pub fonts : Fonts,
|
||||||
pub update_handle : Option<CallbackHandle>,
|
pub update_handle : Option<CallbackHandle>,
|
||||||
pub self_reference : Option<WorldRef>
|
pub self_reference : Option<WorldRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -66,12 +67,12 @@ impl World {
|
|||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub fn new() -> WorldRef {
|
pub fn new() -> WorldRef {
|
||||||
println!("NOTICE! When profiling in Chrome check 'Disable JavaScript Samples' under the \
|
println!("NOTICE! When profiling in Chrome check 'Disable JavaScript Samples' under the \
|
||||||
gear icon in the 'Performance' tab. It can drastically slow the reading.");
|
gear icon in the 'Performance' tab. It can drastically slow the rendering.");
|
||||||
let world_ref = WorldRef::new(Self::new_uninitialized());
|
let world_ref = WorldRef::new(Self::new_uninitialized());
|
||||||
let world_ref2 = world_ref.clone_rc();
|
let world_ref2 = world_ref.clone_rc();
|
||||||
let world_ref3 = world_ref.clone_rc();
|
let world_ref3 = world_ref.clone_rc();
|
||||||
with(world_ref.borrow_mut(), |mut data| {
|
with(world_ref.borrow_mut(), |mut data| {
|
||||||
let update = move || world_ref2.borrow_mut().update();
|
let update = move || world_ref2.borrow_mut().run();
|
||||||
let update_handle = data.event_loop.add_callback(update);
|
let update_handle = data.event_loop.add_callback(update);
|
||||||
data.update_handle = Some(update_handle);
|
data.update_handle = Some(update_handle);
|
||||||
data.self_reference = Some(world_ref3);
|
data.self_reference = Some(world_ref3);
|
||||||
@ -123,12 +124,16 @@ impl World {
|
|||||||
/// which when dropped will cancel the callback. If you want the function
|
/// which when dropped will cancel the callback. If you want the function
|
||||||
/// to run forever, you can use the `forget` method in the handle.
|
/// to run forever, you can use the `forget` method in the handle.
|
||||||
pub fn on_frame<F:FnMut(&mut World)+'static>
|
pub fn on_frame<F:FnMut(&mut World)+'static>
|
||||||
(&mut self, mut callback: F) -> CallbackHandle {
|
(&mut self, mut callback:F) -> CallbackHandle {
|
||||||
let this = self.self_reference.as_ref().unwrap().clone_rc();
|
let this = self.self_reference.as_ref().unwrap().clone_rc();
|
||||||
let func = move || callback(&mut this.borrow_mut());
|
let func = move || callback(&mut this.borrow_mut());
|
||||||
self.event_loop.add_callback(func)
|
self.event_loop.add_callback(func)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.update();
|
||||||
|
}
|
||||||
|
|
||||||
/// Check dirty flags and update the state accordingly.
|
/// Check dirty flags and update the state accordingly.
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
if self.workspace_dirty.check_all() {
|
if self.workspace_dirty.check_all() {
|
||||||
|
@ -5,6 +5,9 @@ use crate::control::callback::CallbackHandle;
|
|||||||
use crate::control::callback::CallbackRegistry;
|
use crate::control::callback::CallbackRegistry;
|
||||||
use crate::system::web;
|
use crate::system::web;
|
||||||
use wasm_bindgen::prelude::Closure;
|
use wasm_bindgen::prelude::Closure;
|
||||||
|
use crate::debug::monitor;
|
||||||
|
use crate::debug::monitor::Monitor;
|
||||||
|
use crate::debug::monitor::Panel;
|
||||||
|
|
||||||
|
|
||||||
// =================
|
// =================
|
||||||
@ -58,22 +61,46 @@ impl EventLoop {
|
|||||||
|
|
||||||
/// The internal state of the `EventLoop`.
|
/// The internal state of the `EventLoop`.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug, Default)]
|
#[derivative(Debug)]
|
||||||
pub struct EventLoopData {
|
pub struct EventLoopData {
|
||||||
main : Option<Closure<dyn FnMut(f32)>>,
|
main : Option<Closure<dyn FnMut(f32)>>,
|
||||||
callbacks : CallbackRegistry,
|
callbacks : CallbackRegistry,
|
||||||
|
monitor : Monitor,
|
||||||
|
time : Panel,
|
||||||
|
fps : Panel,
|
||||||
|
mem : Panel,
|
||||||
main_id : i32,
|
main_id : i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for EventLoopData {
|
||||||
|
fn default() -> Self {
|
||||||
|
let main = default();
|
||||||
|
let callbacks = default();
|
||||||
|
let main_id = default();
|
||||||
|
let mut monitor = Monitor::new();
|
||||||
|
let time = monitor.add(monitor::FrameTime::new());
|
||||||
|
let fps = monitor.add(monitor::Fps::new());
|
||||||
|
let mem = monitor.add(monitor::WasmMemory::new());
|
||||||
|
Self {main,callbacks,monitor,time,fps,mem,main_id}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EventLoopData {
|
impl EventLoopData {
|
||||||
/// Create new instance.
|
/// Create new instance.
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
|
self.time.begin();
|
||||||
|
self.fps.begin();
|
||||||
|
self.mem.begin();
|
||||||
let callbacks = &mut self.callbacks;
|
let callbacks = &mut self.callbacks;
|
||||||
let callback_id = self.main.as_ref().map_or(default(), |main| {
|
let callback_id = self.main.as_ref().map_or(default(), |main| {
|
||||||
callbacks.run_all();
|
callbacks.run_all();
|
||||||
web::request_animation_frame(main).unwrap()
|
web::request_animation_frame(main).unwrap()
|
||||||
});
|
});
|
||||||
self.main_id = callback_id;
|
self.main_id = callback_id;
|
||||||
|
self.time.end();
|
||||||
|
self.fps.end();
|
||||||
|
self.mem.end();
|
||||||
|
self.monitor.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +146,6 @@ mod example_01 {
|
|||||||
let make_widget = |scope: &mut VarScope| {
|
let make_widget = |scope: &mut VarScope| {
|
||||||
let inst_1_ix = scope.add_instance();
|
let inst_1_ix = scope.add_instance();
|
||||||
let transform1 = transform.get(inst_1_ix);
|
let transform1 = transform.get(inst_1_ix);
|
||||||
// transform1.modify(|t| {t.append_translation_mut(&Vector3::new( 0.0,0.0,0.0));}); // DELETEME
|
|
||||||
Widget::new(Logger::new("widget"),transform1)
|
Widget::new(Logger::new("widget"),transform1)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,7 +157,7 @@ mod example_01 {
|
|||||||
|
|
||||||
|
|
||||||
let mut widgets: Vec<Widget> = default();
|
let mut widgets: Vec<Widget> = default();
|
||||||
let count = 1000;
|
let count = 100;
|
||||||
for _ in 0 .. count {
|
for _ in 0 .. count {
|
||||||
let widget = make_widget(inst_scope);
|
let widget = make_widget(inst_scope);
|
||||||
widgets.push(widget);
|
widgets.push(widget);
|
||||||
@ -168,23 +167,47 @@ mod example_01 {
|
|||||||
|
|
||||||
|
|
||||||
let mut i:i32 = 0;
|
let mut i:i32 = 0;
|
||||||
world.on_frame(move |_| on_frame(&mut i,&w1, &mut widgets,&performance)).forget();
|
world.on_frame(move |w| on_frame(w,&mut i,&w1, &mut widgets,&performance,wspace_id,sym_id,&transform)).forget();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(clippy::many_single_char_names)]
|
#[allow(clippy::many_single_char_names)]
|
||||||
pub fn on_frame(ii:&mut i32, w1:&Widget, widgets:&mut Vec<Widget>, performance:&Performance) {
|
pub fn on_frame(world:&mut World, ii:&mut i32, w1:&Widget, widgets:&mut Vec<Widget>, performance:&Performance, wspace_id:WorkspaceID, sym_id:SymbolId, transform : &Buffer<Matrix4<f32>>) {
|
||||||
// camera.mod_position(|p| {
|
// camera.mod_position(|p| {
|
||||||
// p.x -= 0.1;
|
// p.x -= 0.1;
|
||||||
// p.z += 1.0
|
// p.z += 1.0
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
let workspace : &mut Workspace = &mut world[wspace_id];
|
||||||
|
let symbol : &mut Symbol = &mut workspace[sym_id];
|
||||||
|
let mesh : &mut Mesh = &mut symbol.surface;
|
||||||
|
let scopes : &mut Scopes = &mut mesh.scopes;
|
||||||
|
let inst_scope: &mut VarScope = &mut scopes.instance;
|
||||||
|
|
||||||
|
let make_widget = |scope: &mut VarScope| {
|
||||||
|
let inst_1_ix = scope.add_instance();
|
||||||
|
let transform1 = transform.get(inst_1_ix);
|
||||||
|
Widget::new(Logger::new("widget"),transform1)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
w1.transform.mod_position(|p| p.y += 0.5);
|
w1.transform.mod_position(|p| p.y += 0.5);
|
||||||
w1.transform.update();
|
w1.transform.update();
|
||||||
|
|
||||||
*ii += 1;
|
*ii += 1;
|
||||||
|
|
||||||
if *ii < 1000i32 {
|
if *ii < 200i32 {
|
||||||
|
let count = 100;
|
||||||
|
if widgets.len() < 100_000 {
|
||||||
|
for _ in 0..count {
|
||||||
|
let widget = make_widget(inst_scope);
|
||||||
|
widgets.push(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let t = (performance.now() / 1000.0) as f32;
|
let t = (performance.now() / 1000.0) as f32;
|
||||||
let length = widgets.len() as f32;
|
let length = widgets.len() as f32;
|
||||||
for (i, object) in widgets.iter_mut().enumerate() {
|
for (i, object) in widgets.iter_mut().enumerate() {
|
||||||
|
@ -15,6 +15,7 @@ use web_sys::Node;
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub use web_sys::console;
|
pub use web_sys::console;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
// =============
|
// =============
|
||||||
@ -328,3 +329,8 @@ impl NodeRemover for Node {
|
|||||||
self.remove_child(node).unwrap_or_else(panic_msg);
|
self.remove_child(node).unwrap_or_else(panic_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(inline_js = "export function request_animation_frame2(f) { requestAnimationFrame(f) }")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn request_animation_frame2(closure: &Closure<dyn FnMut()>) -> i32;
|
||||||
|
}
|
@ -1,2 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
wasm-pack build --out-dir '../../target/web' lib/core
|
wasm-pack build $@ --no-typescript --out-dir '../../target/web' lib/core
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
cargo clean -p basegl -p basegl-backend-webgl -p basegl-prelude -p basegl-system-web
|
|
||||||
cargo clippy -- -D warnings
|
cargo clippy -- -D warnings
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
cargo test &&
|
cargo test &&
|
||||||
cargo run --manifest-path=script/rust/Cargo.toml --bin test-all -- \
|
cargo run --manifest-path=script/rust/Cargo.toml --bin test-all -- \
|
||||||
--node --firefox --chrome --headless
|
--node --firefox --chrome --headless
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
cargo watch -i .gitignore -i "pkg/*" -s "script/build.sh"
|
cargo watch -i .gitignore -i "pkg/*" -s "script/build.sh ${@}"
|
Loading…
Reference in New Issue
Block a user