Rust/WebAssembly Graphics Library

Introduction

This is a quick post to describe a little Rust crate that I created for fun: a WebAssembly graphics library.

The library is not meant for any serious work; it has no hardware acceleration and is not highly optimised. I created it to help me to learn Rust, WebAssembly, general graphics routines and unit testing and benchmarking in Rust. I’m sharing it mainly for fun, but also with the hope that it might help someone who is learning this type of thing too.

Why I made it

I have always been interested in graphical routines. Some of my earliest experiments on the Amstrad CPC464 and Commodore 64 involved rendering graphics of some kind. Since then, as the years have passed, I have dabbled in graphical routines in various different languages/frameworks (e.g. Delphi, C/SDL and C#).

Since then I have become very interested in both Rust and WebAssembly, so I decided to update my previous work to the present day.

What can it do?

The goal of the library is simplicity. As such, rendering canvases are simply arrays of 32-bit integers, allowing all 24-bit RGB colours to be used together with an 8-bit alpha channel.

Routines

The library provides the following routines: -

  • Clearing a canvas to an ARGB colour;
  • Copying one canvas to another at an arbitrary destination location;
  • Loading pixels from a Vec<u32>;
  • Performing UV sampling of any canvas;
  • Line drawing;
  • Outline and filled rectangle drawing;
  • Triangle drawing: outline, filled and textured; and
  • Arbitrary polygon drawing (convex and concave, filled or outline).

Rendering

The library is intended to be used as a WebAssembly module within a browser context, but as it renders to simple integer arrays it could theoretically be used in a wide variety of other situations.

For the WebAssembly and browser context, module functions are called from JavaScript to create the canvas and to issue drawing commands. Once a canvas has been rendered, JavaScript accesses the canvas’s memory directly, interprets it as pixel data and draws it to a HTML canvas element.

Rust, wasm-bindgen, tests and benchmarks

The library is written in Rust and uses the wasm-bindgen and wasm-pack projects to create bindings to and from JavaScript.

Tests

Whenever possible I write unit tests for my projects. In order to learn how to write tests in Rust I added a simple test suite to this project. The tests can be run using the cargo test command.

Benchmarks

Another goal of this project was to learn how to run code benchmarks in Rust. A library of graphics routines – which need to be as fast as possible – was a really good way to learn how to do this!

I decided to use the Criterion crate for this. To run the benchmarks, use the cargo bench command.

JavaScript side

The project is bundled with a simple demonstration web page. This page loads the library and then executes a rendering loop with a number of examples to show off the features of the library. Please check the demo!

The JavaScript side of the project was generated using the create-wasm-app NPM template.

Building

To build the project you’ll need a Rust development toolchain as well as wasm-pack. Once these are installed, simply run the following to build the WebAssembly module and JS bindings: -

wasm-pack build --release

To build the example application, change to the www directory and run npm install, followed by npm run build. To run a local development server, use npm start instead. The example app uses the create-wasm-app NPM template, so please check its GitHub repository for more details.

Conclusion

Ultimately this project is not intended to provide a graphics library for serious use. It was made for fun and as a learning exercise, and is an example of Rust and WebAssembly with benchmarks, tests and implementations of a number of graphical routines. I’m sharing it in the hope that it’ll help others who are researching these topics too!



Links