Browse Source

Add support for custom pixel formats to the WASM program

rexim 5 years ago
parent
commit
3c2cb35c8e
6 changed files with 115 additions and 22 deletions
  1. 2 1
      .gitignore
  2. 4 1
      Makefile
  3. 1 1
      README.md
  4. 99 0
      bng.in.wat
  5. 9 3
      bng.js
  6. 0 16
      bng.wat

+ 2 - 1
.gitignore

@@ -4,4 +4,5 @@ png2bng
 png2bng_test
 bngviewer
 *.wasm
-*.bng
+*.bng
+bng.wat

+ 4 - 1
Makefile

@@ -7,7 +7,7 @@ png2bng: png2bng.c bng.h stb_image.h
 	$(CC) -O3 -o png2bng png2bng.c -lm
 
 tsodinw.bng: png2bng tsodinw.png
-	./png2bng tsodinw.png tsodinw.bng RAGB
+	./png2bng tsodinw.png tsodinw.bng GRAB
 
 bngviewer: bngviewer.c bng.h
 	$(CC) $(BNGVIEWER_CFLAGS) -O3 -o bngviewer bngviewer.c $(BNGVIEWER_LIBS)
@@ -15,6 +15,9 @@ bngviewer: bngviewer.c bng.h
 bng.wasm: bng.wat
 	wat2wasm bng.wat
 
+bng.wat: bng.in.wat
+	cpp -P bng.in.wat > bng.wat
+
 .PHONY: test
 
 test: png2bng_test

+ 1 - 1
README.md

@@ -22,6 +22,6 @@
       - [x] Call a WASM function that turns the file into Image Data
       - [x] Take out the Image Data from WASM memory and display it
     - [ ] Add more interesting features to bng to test the support
-      - [ ] Different pixel formats
+      - [x] Different pixel formats
       - [ ] Different compressions
     - [ ] Reusable BNG library that works both natively and being compiled to WASM

+ 99 - 0
bng.in.wat

@@ -0,0 +1,99 @@
+#define WIDTH_OFFSET 4
+#define HEIGHT_OFFSET 8
+#define PIXEL_FORMAT_OFFSET 12
+#define DATA_OFFSET 16
+
+(module
+ (memory (import "js" "mem") 1)
+ (func $print (import "js" "print") (param i32))
+ (func $byte_offset
+       (param $index i32)
+       (result i32)
+       (i32.mul 
+        (i32.sub 
+         (i32.sub (i32.const 4) (get_local $index))
+         (i32.const 1))
+        (i32.const 8)))
+ (func $get_byte
+       (param $pixel i32)
+       (param $index i32)
+       (result i32)
+       (i32.shr_u 
+        (i32.and 
+         (get_local $pixel)
+         (i32.shl (i32.const 255) (call $byte_offset (get_local $index))))
+        (call $byte_offset (get_local $index))))
+ (func $set_byte
+       (param $pixel i32)
+       (param $index i32)
+       (param $byte i32)
+       (result i32)
+       (i32.or
+        (get_local $pixel)
+        (i32.shl (get_local $byte) (call $byte_offset (get_local $index)))))
+ (func $convert_pixel
+       (param $pixel i32)
+       (result i32)
+       (local $result i32)
+       (set_local $result (i32.const 0))
+       (set_local $result
+                  (call $set_byte (get_local $result)
+                        (i32.const 0)
+                        (call $get_byte (get_local $pixel)
+                              (i32.load8_u (i32.const PIXEL_FORMAT_OFFSET)))))
+       (set_local $result
+                  (call $set_byte (get_local $result)
+                        (i32.const 1)
+                        (call $get_byte (get_local $pixel)
+                              (i32.load8_u (i32.add (i32.const PIXEL_FORMAT_OFFSET)
+                                                    (i32.const 1))))))
+       (set_local $result
+                  (call $set_byte (get_local $result)
+                        (i32.const 2)
+                        (call $get_byte (get_local $pixel)
+                              (i32.load8_u (i32.add (i32.const PIXEL_FORMAT_OFFSET)
+                                                    (i32.const 2))))))
+       (set_local $result
+                  (call $set_byte (get_local $result)
+                        (i32.const 3)
+                        (call $get_byte (get_local $pixel)
+                              (i32.load8_u (i32.add (i32.const PIXEL_FORMAT_OFFSET)
+                                                    (i32.const 3))))))
+       (get_local $result))
+ (func (export "bng_process")
+       (local $index i32)
+       (local $count i32)
+       (local $address i32)
+       (set_local $count (i32.mul (call $bng_width) (call $bng_height)))
+       (block
+        $exit
+        (loop
+         $repeat
+         (br_if $exit (i32.ge_s
+                       (get_local $index)
+                       (get_local $count)))
+         (set_local $address
+                    (i32.add
+                     (i32.const DATA_OFFSET)
+                     (i32.mul
+                      (get_local $index)
+                      (i32.const 4))))
+         (i32.store (get_local $address) (call $convert_pixel (i32.load (get_local $address))))
+         (set_local $index (i32.add (get_local $index) (i32.const 1)))
+         (br $repeat))))
+ (func (export "bng_offset")
+       (result i32)
+       (i32.const DATA_OFFSET))
+ (func $bng_width (export "bng_width")
+       (result i32)
+       (i32.load (i32.const WIDTH_OFFSET)))
+ (func $bng_height (export "bng_height")
+       (result i32)
+       (i32.load (i32.const HEIGHT_OFFSET)))
+ (func (export "bng_size")
+       (result i32)
+       (i32.mul
+        (i32.mul
+         (call $bng_width)
+         (call $bng_height))
+        (i32.const 4))))

+ 9 - 3
bng.js

@@ -1,16 +1,22 @@
+const IMAGE_FILENAME = "tsodinw.bng";
+
 async function bng() {
-    let bngFile = await fetch("tsodinw.bng");
+    let bngFile = await fetch(IMAGE_FILENAME);
     let fileData = await bngFile.arrayBuffer();
-    let memory = new WebAssembly.Memory({initial: 10, maximum: 10});
+    let memory = new WebAssembly.Memory({initial: 300, maximum: 1000});
     new Uint8Array(memory.buffer).set(new Uint8Array(fileData));
     let bngProgram = await WebAssembly.instantiateStreaming(
         fetch("bng.wasm"),
         { js: { mem: memory, print: arg => console.log(arg) } });
+    let offset = bngProgram.instance.exports.bng_offset();
     let size = bngProgram.instance.exports.bng_size();
     let width = bngProgram.instance.exports.bng_width();
     let height = bngProgram.instance.exports.bng_height();
-    let imageData = new ImageData(new Uint8ClampedArray(memory.buffer).slice(12, 12 + size), width, height);
+    bngProgram.instance.exports.bng_process();
+    let imageData = new ImageData(new Uint8ClampedArray(memory.buffer).slice(offset, offset + size), width, height);
     let canvas = document.querySelector("#bng");
+    canvas.width = width;
+    canvas.height = height;
     let context = canvas.getContext("2d");
     context.putImageData(imageData, 0, 0);
 }

+ 0 - 16
bng.wat

@@ -1,16 +0,0 @@
-(module
- (memory (import "js" "mem") 1)
- (func $print (import "js" "print") (param i32))
- (func (export "bng_size")
-       (result i32)
-       (i32.mul
-        (i32.mul
-         (i32.load (i32.const 4))
-         (i32.load (i32.const 8)))
-        (i32.const 4)))
- (func (export "bng_width")
-       (result i32)
-       (i32.load (i32.const 4)))
-  (func (export "bng_height")
-       (result i32)
-       (i32.load (i32.const 8))))