Wasm in the Armory Engine

For those in the tank, wasm or WebAssembly is a low-level programming language for a virtual stack machine once designed as a portable compilation target for high-level languages ​​such as C, C ++, C #, Rust, Go. Simply put, you can write high performance, compact, and portable code using wasm. Our Armory uses wasm too. Thanks to him, the engine can run in the browser and on other platforms using Krom.





Traits in C and Rust

Wasm is also used in traits or scripts. To do this, we will write a cube rotation script in C.





Cube rotation code
#define WASM_EXPORT __attribute__((visibility("default")))

// Declare Armory API used in this module
// github.com/armory3d/armory/blob/master/Sources/armory/trait/internal/wasm_api.h
void notify_on_update(void* f);
int get_object(const char* name);
void set_transform(int object, float x, float y, float z,
	float rx, float ry, float rz, float sx, float sy, float sz);

WASM_EXPORT
void update() {
	static float rot = 0.0f;
	rot += 0.01f;
	set_transform(get_object("Cube"), 0, 0, 0, 0, 0, rot, 1, 1, 1); // Set cube rotation
}

// Include main function, Armory calls it when trait is instantiated
WASM_EXPORT
int main() {
	notify_on_update(update); // Register callback
	return 0;
}
      
      







Compile the source code in C will help us webassembly.studio . We will move the resulting wasm file to the blend_location / Bundled folder.





Next, let's create a cube in blender, go to properties - Object - Armory Traits, create a new wasm traits, select our wasm file in modules . Press F5 and watch the cube rotate. An example can be downloaded from here .





The same thing but only in Rust.





Rust code
extern {
  fn notify_on_update(f: extern fn() -> ()) -> ();
  fn get_object(name: *const i8) -> i32;
  fn set_transform(object: i32, x: f32, y: f32, z: f32, rx: f32, ry: f32, rz: f32, sx: f32, sy: f32, sz: f32) -> ();
}

#[no_mangle]
pub extern "C" fn update() -> () {
  unsafe {
    let name = std::ffi::CString::new("Cube").unwrap();
    let object = get_object(name.as_ptr());
    static mut rot: f32 = 0.1;
    rot += 0.01;
    set_transform(object, 0.0, 0.0, 0.0, 0.0, 0.0, rot, 1.0, 1.0, 1.0);
  }
}

#[no_mangle]
pub extern "C" fn main() -> i32 {
  unsafe {
    notify_on_update(update);
  }
  return 0;
}
      
      







We compile and transfer to Bundled .





Calling wasm from Haxe

Wasm can be called directly from properties written in haxe. Let's start with a simple C function.





#define WASM_EXPORT __attribute__((visibility("default")))

WASM_EXPORT
float test() {
	return 0.01f;
}
      
      



We compile the source to webassembly.studio . Place the resulting file in blend_location / Bundled.





Calling test () from Haxe.





package arm;
import iron.data.*

class MyTrait extends iron.Trait {
	public function new() {
		super();
		notifyOnInit(init);
	}

	function init() {
		Data.getBlob("main.wasm", function(b:kha.Blob) { // Load wasm blob
			var wasm = Wasm.instance(b); // Create wasm module
			var rot = 0.0;
			notifyOnUpdate(function() {
				rot += wasm.exports.test(); // Call function from wasm module!
				object.transform.setRotation(0, 0, rot);
			});
		});
	}
}
      
      



Examples can be downloaded from here .





  1. Armory Engine. Introduction





  2. Level creation in Armory





  3. Armory Basics. Traits












All Articles