èªãã æ¬
å
¥éWebAssembly
The Art Of WebAssemblyã®ç¿»èš³æžã§ãã
æ¬æžãèªã¿ãªãããµã³ãã«ã³ãŒããåçµããã®ã§ææ³ãæžããŠãããŸãã
èè
ã®Webãµã€ãã«ã¯ä»ã«ãWebAssemblyã«ã€ããŠã®ãããã¯ããããŸãã
ãµã³ãã«ã³ãŒãã¯GitHubããèŠããŸãã
canvasã«3000åã®objectã®è¡çªå€å®ãrenderingãããµã³ãã«ãåãããšãããŸã§ãããŸããã
https://wasmbook.com/collide.html
ãã£ãã
Rustã§WASMã®ecosystemã«ãµããŠããåã«çŽ ã®WASMã«ã€ããŠãªããšãªãã§ãç解ããããšæã£ãŠããŸããã(ããçšåºŠçæãããã°ã«ãŒã³ãŒãèªããªããšèœã¡çããªã)
æ¬æžã§ã¯WATãæžããŠWASMã«å€æããŠåãããªããWASMã®ä»æ§ãè¿œã£ãŠããã®ã§ãWASMã ããåŠã¹ããšæã£ãŠèªãã§ã¿ãŸããã
ãŸãšã
- ç¹ã«ãã¬ãŒã ã¯ãŒã¯ãçšããã«WATãæžããŠWASMã«å€æããŠãnode/browserããåãããããã«ãªããŸãã
- WASMãã¹ã¿ãã¯ãã·ã³ãšããŠåäœããŠããããšãããããŸãã
- çŸç¶ã®WASM(1.0)ãšJavascriptã®åœ¹å²åæ ãããããŸãã
- ããã©ãŒãã³ã¹ã®ãã¥ãŒãã³ã°ãããããã°æ¹æ³ã«ã€ããŠãæžããŠãããŸã
ããããWASMãšã¯
ããããWebAssembly(WASM)ãšã¯ãªã«ããšãã話ãªã®ã§ããã以äžã®ããã«å®çŸ©ãããŠããŸãã
WebAssemblyãšã¯ãã¹ã¿ãã¯ãã·ã³çšã®ä»®æ³åœä»€ã»ããã¢ãŒããã¯ãã£(Virtual ISA)ã
WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.
https://webassembly.org/
ã¹ã¿ãã¯ãã·ã³çšãšããã®ã¯ãCPUåœä»€ã«ã¬ãžã¹ã¿ãŒãã§ãŠããªããšããæå³ã§ãåžžã«æé»çã«ååšããã°ããŒãã«ãªã¹ã¿ãã¯ãæäœããããšã§ããŒã¿ãåŠçããŠãããŸãã
ãŸããçŸæç¹ã®MVP(Minimum Viable Product) 1.0ã§ã¯ãJavaScript(React,Vue)ã眮ãæãããããªããšã¯ã§ããªãããæå³ãããŠãããªãããã§ãã
ãã®ããããããããèŠãŠããã®ã§ãããWASMããDOMãæäœã§ããªãã®ã§jsã眮ãæãããšããã®ã¯ã§ããªããã§ãã
WATãšã¯
WebAssembly Text(WAT)ã¯ãWASMã®ã¢ã»ã³ããªèšèª(ã®ãããªãã®)ã§ãã
WASM,WATéã§çžäºã«å€æã§ããŸãã
æºå
以äžãæºåããŸãã
- WASMã®å®è¡ç°å¢ãšããŠnode
- WATãWASMã«å€æããcli(
wat2wasm
)
nodeã¯v16ãå©çšããŸãããæ¬æžã§ã¯12.14.0
ãåæãšãªã£ãŠããŸãã
äœè«ã§ãããnodeã®version管çã¯nvmããRust補ã®fnmã«åãæ¿ããŸããã
nodeãinstallãããšããã以äžã®ãããªæãã§ãã
次ã«WATãWASMã«å€æããããã®wat2wasm
ãinstallããŸãã
========================================================
========================================================
ããã§ã«ã¬ã³ããã£ã¬ã¯ããªã«file.wasm
ãçæãããã®ã§äžèº«ãèŠãŠã¿ãŸãã
toolã¯ãªãã§ãããã®ã§ããèªåã¯hexyl
ãå©çšããŠããŸãã(cargo install hexyl
)
WASMã®Binary Formatã«é¢ããä»æ§ã§moduleã¯ä»¥äžã®ããã«å®çŸ©ãããŠããŸãã
magic ::= 0x00 0x61 0x73 0x6D
version ::= 0x01 0x00 0x00 0x00
module ::= magic
version
(çç¥)
ãšããããšã§ãå
é ã0asm
ã®MAGIC NUMBERã§æ¬¡ã®4byteãBinary Formatã®version 1ã«ãªã£ãŠããŸãã(61=a, 73=s, 6d=m)
WASMã¯ãªãã«ãšã³ãã£ã¢ã³ãªã®ã§ã01ãå
é ã«ããŠããŸããã
WATãWASMã«å€æã§ããŠããããšã確èªã§ããã°æºåå®äºã§ãã
WATã®ã¡ã³ã¿ã«ã¢ãã«
ãã£ããHello Worldã«å ¥ããããšãããªã®ã§ãããWASMã«ã¯Stringåã®ããŒã¿æ§é ããªãã£ãããçµã¿èŸŒã¿ç°å¢(å®è¡ç°å¢)ãšã®import/exportãæåã¯ãããã¥ããã£ããããã®ã§ãWATã®æžãæ¹ããèŠãŠãããŸãã
WATã§ã¯æé»çãªã°ããŒãã«ã®ã¹ã¿ãã¯ãæäœããããšã§æŒç®ãé¢æ°ãšã®ããåããè¡ããŸãã
äŸãã°å®æ°ã®10ãš20ãå ç®ããã«ã¯
i32.const 10 ;; [ 10 ]
i32.const 20 ;; [ 10 20 ]
i32.add ;; [ 30 ]
ã®ããã«æžããŸããåæ¥ã®åœä»€ãå®è¡ãããããšã®ã¹ã¿ãã¯ã®ç¶æ
ãã³ã¡ã³ãã§æžããŠãããŸãã
ã¬ãžã¹ã¿ãŒãæå®ããåœä»€ããªãã®ãã¹ã¿ãã¯ãã·ãŒã³çšãšããããšãªãã ãããšæããŸãã
WATã§ã¯ããã²ãšã€ãS expression(SåŒ)ãšããæžãæ¹ããµããŒããããŠãããäžèšã®å ç®ã¯ä»¥äžã®ããã«ãæžããŸãã
(i32.add (i32.const 10) (i32.const 20))
SåŒãšéåžžã®èšæ³ã¯æ··åšãããããšãã§ããŸãã
ãŸããWASMã®å®è¡åäœã§ããmoduleãã²ãšã€ã®SåŒãšããŠè¡šçŸãããŸãã
Nodeããã®åããæ¹
WATã®æžãæ¹ããªããšãªãããã£ãã®ã§nodeããåãããŠã¿ãŸãã
node add.js 10 20
ã®ããã«åŒæ°ã§äžããããæ°ãWASMã§å ç®ããŠçµæã衚瀺ããåŠçãäœã£ãŠãããŸãã
WATã®æšå¥šæ¡åŒµåã¯wat
ãããã§ã
addInt.wat
(module
(func (export "addInt") ;; 1
(param $value_1 i32) (param $value_2 i32) ;; 2
(result i32) ;; 3
local.get $value_1
local.get $value_2
i32.add ;; 4
)
)
ãŸããå ç®ãè¡ãWASM moduleãäœæããŸãã
(module)
ã¯ã決ãŸãã§å¿
ãæžããŸããmoduleã¯WASMã«ããããdeploy,loading,compileã®åäœã§ãã 次ã«WASMã§ã¯é¢æ°åäœã§æ©èœãå®çŸ©ããŠããã®ã§ãjsããåŒã³åºãé¢æ°ãå®çŸ©ããŸãã
- jsåŽãããã®é¢æ°ã
addInt
ãšããŠåŒã¹ãããã«ãªããŸããexportãå€ãªãšããã«å®çŸ©ãããªãšæããããããŸããããããã¯syntactic sugarã®ããã§ã - é¢æ°ã¯äºã€ã®i32åã®åŒæ°ããšãããšã宣èšããŠããŸãã
- é¢æ°ã¯i32åã®çµæãæ»ãå€ãšããŠè¿ãããšã宣èšããŠããŸãã
$value_1
ãš$value_2
ã®å ç®çµæãstackã«æ®ããŠããããšã§çµæãè¿ããŸãã
wat2wasm addInt.wat
ã§``addInt.wasm`ãçæã§ããã°å®äºã§ãã
次ã«ãã®WASMãåŒã³åºãjsãæžããŸãã
addInt.js
;
; // 1
;
;
;
- WASMãfileããèªã¿èŸŒã¿ãŸããbrowserã®å Žåã¯ãããfetch(ãããã¯ãŒã¯è¶ã)ã«ãªããŸãã
- WASMãinstanceåããŸããã¡ã³ã¿ã«ã¢ãã«çã«ã¯ããã§ãèªã¿èŸŒãã wasmã®moduleã®åæååŠçãèµ°ããŸãã
- WASMããexportããé¢æ°ã¯
instance.exports
ã«æ ŒçŽãããŠããã®ã§åŒã³åºããŸãã
jsããWASMãåŒã³åºãããšãã§ããŸããð
ãã®ããã«WASMåŽã§exportããé¢æ°ãjsåŽããåŒã³åºãããšã§å©çšããŸãã
Browserããã®åããæ¹
次ã«WASMãbrowserããå®è¡ããŠã¿ãŸãã
WASMã®binaryãååŸããŠinstantiateããã®ã¡ã«ãexportãããé¢æ°ãåŒã³åºããšããåºæ¬çãªæµãã¯åãã§ãã
ãŸããbrowserã«WASMãšhtmlãserveãããã®ã§ãhttp serverã建ãŠãããããã«ããŸãã(localã®fileãserveã§ããã°ãªãã§ãããã§ã)
次ã«ä»¥äžã®å
容ã®index.html
ãäœããŸãã
Add Int
Add Values
logAddInt
ã¯jsããwasmã«æž¡ãé¢æ°ã§ããwasmããåŒã°ãããçµæãDOMã«è¿œèšããŠãããŸãã- jsããwasmã«æž¡ãobjectã§ãã
logAddInt
ã¯wasmåŽãšäžèŽããŠããå¿ èŠããããŸãã - wasmã®instanceåã§ããbinaryã
fetch()
ã§ååŸããŠããŸãã第äºåŒæ°ã§importçšã®objectãæž¡ããŸãã - jsããcallããwasmã®é¢æ°ã§ããbuttonã®onclickã«èšå®ããŸãã
addInt.wat
ã以äžã®ããã«å€æŽããŸãã
(module
(import "env" "logAddInt" (func $logAddInt (param i32 i32 i32))) ;; 1
(func (export "addInt")
(param $value_1 i32) (param $value_2 i32)
(local $sum i32)
local.get $value_1
local.get $value_2
i32.add
local.set $sum
(call $logAddInt (local.get $value_1) (local.get $value_2) (local.get $sum)) ;; 2
)
)
- wasmãçµã¿èŸŒã¿ç°å¢(å®è¡ç°å¢/hostç°å¢)ããååŸããé¢æ°ã宣èšããŸãã
- importããé¢æ°ã®åŒã³åºãã§ãã
å€æŽããããwat2wasm addInt.wat
ã§wasmã«å€æããŸãã
æåŸã«htmlãšwasmãserveããããã®server.js
ãäœæããŸãã
;
;
__dirname+"/"8080, ;
ããã§ä»¥äžã®ããã«serverãèµ·åããã®ã¡browserã§localhost:8080
ã«ã¢ã¯ã»ã¹ããŸãã
[f:id:yamaguchi7073xtt:20220705044410p:plain]
ãã®ããã«çµã¿èŸŒã¿ç°å¢(browser, node)ãšwasméã§ã¯import/exportããäºãã®é¢æ°ãåŒã³åãããšãã§ããããšã確ãããããŸããã
Hello World
WATãWASMã«å€æããŠçµã¿èŸŒã¿ç°å¢(node,browser)ããå®è¡ããããšãã§ããã®ã§ãHello Worldããã£ãŠã¿ãŸãã
ãŸã以äžã®WATãäœæããŸãã
(module
(import "env" "print_string" (func $print_string(param i32))) ;; 1
(import "env" "buffer" (memory 1)) ;; 2
(global $start_string (import "env" "start_string") i32) ;; 3
(global $string_len i32 (i32.const 12))
(data (global.get $start_string) "hello world!") ;; 4
(func (export "helloworld")
(call $print_string (global.get $string_len)) ;; 5
)
)
- WASMããI/Oãããããšãã§ããªãã®ã§ãçµã¿èŸŒã¿ç°å¢ããhello worldåºåçšã®é¢æ°ãimportããŸãã
- ç·åœ¢ã¡ã¢ãªãå©çšããããšã宣èšããŸããå®éã®ã¡ã¢ãªã¯jsåŽã§ç¢ºä¿ããŠWASMã«æž¡ããŸãã
- ç·åœ¢ã¡ã¢ãªã®ã©ã®äœçœ®ã«hello worldæååãçæããããjsåŽããæå®ããŸãã
- æå®ãããç·åœ¢ã¡ã¢ãªäœçœ®ã«UTF-8ã®byteåãçæããŸãã
- importããæåååºåçšé¢æ°ã«åºåããæååã®é·ããæž¡ããŸãã
jsãšWASMã®åœ¹å²åæ ããããããã§ãã以äžã®ããã«ãªã£ãŠããŸãã
- jsåŽ
- ã¡ã¢ãªç¢ºä¿
- 確ä¿ããã¡ã¢ãªã®ã©ã®äœçœ®ã«hello worldãåºåããããæå®
- åºåããæååã®é·ããåŒæ°ã«ãšãé¢æ°ãWASMã«æž¡ã
- WASMåŽ
- importããã¡ã¢ãªã®æå®ãããäœçœ®ã«"hello world" UTF-8 byteåãçæ
- åºåçšé¢æ°ã«"hello world"ã®é·ããåŒæ°ã«ããŠåŒã³åºã
jsåŽã¯ä»¥äžã®ããã«äœæããŸãã(helloworld.js
)
;
;
; // 1
; // 2
;
;
- éå§200byteç®ã«hello worldãåºåããããšãæå®
- WASMã«æž¡ãã¡ã¢ãªã確ä¿ããŸã
- 確ä¿ããã¡ã¢ãªãWASMã«æž¡ããŸã
- 確ä¿ããã¡ã¢ãªäœçœ®ãUTF8ãšããŠè§£éããŸã
ç¡äºãhello world!ãWASMã§ã§ããŸããð
ãŸãããã§ç»å Žããç·åœ¢ã¡ã¢ãª(WebAssembly.Memory
)ã«ã€ããŠã¯6ç« ã§è©³ãã説æãããŠããŸãã
èªåã®ç解ãšããŠã¯WASMãšjséã§å
±æã§ããBufferã§ãããŒãž(64KB)åäœã§ç¢ºä¿ãããã®ãšèããŠãããŸãã
ãã®ç·åœ¢ã¡ã¢ãªã®å®çšçãªå©çšäŸã¯æåŸã®DOMæäœã§ãµããŸãã
is_prime
Hello Worldãæžãã ã®ã§ãWATã®å¶åŸ¡ãããŒ(loop,if)ãèŠãŠãããŸããå ç®ããäžæ©é²ãã§ãçŽ æ°ãå€å®ããmoduleãäœã£ãŠãããŸãã
ãŸãWATããã§ããé·ããªãã®ã§å°ãã€ã¥ã¿ãŠãããŸãã
(module
;; å¶æ°ã®å€å®
(func $even_check (param $n i32) (result i32)
local.get $n ;; [ n ]
i32.const 2 ;; [ n 2 ]
i32.rem_u ;; [ 0 ] | [ 1 ]
i32.const 0 ;; [ 0 0 ] | [ 1 0 ]
i32.eq ;; $n % 2 == 0 ;; [ 1 ] | [ 0 ]
)
)
helperé¢æ°ãšããŠå¶æ°ãå€å®ããeven_check
ãå®çŸ©ããŸãã
ã³ã¡ã³ãã§åœä»€å®è¡åŸã®ã¹ã¿ãã¯ã®æ§åãæžããŠãããŸãã(|
ã¯ãŸãã¯ã®æå³ã§ã)
WASMã«ã¯ããŒã¿åãšããŠbooleanããªã0以å€ãtrue, 0ãfalseãšããŠæ±ãããŸãã
rem_u
ã¯é€ç®ã®äœããåºåããŸãã
;; 2ãšçãããã®å€å®
(func $eq_2 (param $n i32) (result i32)
local.get $n
i32.const 2
i32.eq
)
;; n = m * q. nãmã®åæ°ãã®å€å®ã
(func $multiple_check (param $n i32) (param $m i32) (result i32)
local.get $n
local.get $m
i32.rem_u ;; $n % $m
i32.const 0
i32.eq
)
次ã«2ãšçãããå€å®ããeq_2
ãšç¬¬äžåŒæ°ã第äºåŒæ°ã®åæ°ããå€å®ããmultiple_check
ãå®çŸ©ããŸãã
;; çŽ æ°ã®å€å®
(func (export "is_prime") (param $n i32) (result i32)
(local $i i32)
;; 1ãšçãããã®å€å®
(if (i32.eq (local.get $n) (i32.const 1))
(then
i32.const 0
return
)
)
;; 2ãšçãããã®å€å®
(if (call $eq_2 (local.get $n))
(then
i32.const 1
return
)
)
(block $not_prime
(call $even_check (local.get $n))
br_if $not_prime ;; å¶æ°ãªã®ã§çŽ æ°ã§ã¯ãªã
(local.set $i (i32.const 1))
(loop $prime_test_loop
;; $i += 2
;; teeã¯setãšåãã ãstackãpopããªã
(local.tee $i
(i32.add (local.get $i) (i32.const 2)))
local.get $n ;; stack = [ $i $n ]
i32.ge_u ;; $i >= $n
if
;; $nã調ã¹ãã£ãã®ã§çŽ æ°ãšå€å®
i32.const 1
return
end
;; stack = [];
;; $nã$iã®åæ°ãªãçŽ æ°ã§ã¯ãªã
(call $multiple_check (local.get $n) (local.get $i))
br_if $not_prime
;; loopãç¹°ãè¿ã
br $prime_test_loop
) ;; $prime_test_loop end
)
;; br $not_prime jump here
i32.const 0
)
ããã§ãæ¡ä»¶åå²(if
)ãšloopã«ã€ããŠç°¡åã«è§£èª¬ããŸãã
if
ã¯å®è¡æã®ã¹ã¿ãã¯ã®å
é ãè©äŸ¡ããŠtrue(0以å€)ãªãend
ãŸã§ã®åœä»€ãå®è¡ããŸããããã§ã¯å©çšããŠããŸãããelse
ãæžããŸãã
blockã¯å°ã
ãããã¥ããã®ã§ãããbr
(branch)åœä»€ã§blockãæãåºãããšãã§ããŸããbr_if
ã¯ã¹ã¿ãã¯ã®å
é ãè©äŸ¡ããŠtrueãªãbr
ããåœä»€ã§ããäžã®äŸã§ã¯br $not_prime
ã§blockåãæãåºãã®ã§çµæçã«false(0)ãæ»ãå€ãšãªããŸãã
loopãçŽæã«åããŠèªåã§ã¯loopããŠãããŸãããæ瀺çã«loopã®å
é ã«jumpããbr
åœä»€ãå©çšããŠã¯ãããŠloopã§ããŸãã
äžã®äŸã§ã¯br $prime_test_loop
ã§loopã®å
é ã«æ»ããŸãã
local.tee $i
ã¯ãã¹ã¿ãã¯ã®å
é ã$i
ã«ä»£å
¥ãã€ã€ããã®å€ãã¹ã¿ãã¯ã«æ®ããŸã(åºåããŸã)
loopå¶åŸ¡çšã®indexå€æ°ãã€ã³ã¯ãªã¡ã³ããã€ã€ãçµäºå€å®ããå Žåã«ãã䜿ãããŠããŸããã
ãã®WATãWASMã«å€æããŠãåŒã³åºãjsãäœæããŸãã
;
;
;
;
ç¡äºå€å®ã§ããŸããã
DOMæäœ
æåŸã«canvasãæäœããäŸãèŠãŠãããŸãã
WASMããcanvasã¯æäœã§ããªãã®ã§ãcanvasã«æç»ããã¡ã¢ãªãWASMåŽã§æäœããŠãããjsåŽã§ã¬ã³ããªã³ã°ããããšã§å®çŸããŸãã
ããã§äœãã®ã¯ããã移åããè€æ°ã®ãªããžã§ã¯ããã¬ã³ããªã³ã°ãããªããžã§ã¯ãå士ãè¡çªããŠããããå€å®ããWASMã§ãã
ãªããžã§ã¯ãã¯x,y座æšãšx,yããããã®é床ãä¿æããŸãã
WASMã¯canvasã«æç»ãããã¡ã¢ãªé åãšãªããžã§ã¯ãã®ç¶æ
ã管çããé åã管çããŸãã
ãŸããhtmlã¯ä»¥äžã®ããã«ãªããŸãã
collide.html
Collision Detection
canvasã®frameãæç»ãããã³ã«ãWASMåŽã®main
ãåŒã³åºããŸãã
WASMåŽã¯main
ã®äžã§äºã€ã®ããšãè¡ããŸãã
- objectã®ç¶æ å€æŽ
- canvasã®æç»é åã®æŽæ°
WATã¯ä»¥äžã®ããã«ãªããŸãã
(module
(global $cnvs_size (import "env" "cnvs_size") i32)
(global $no_hit_color (import "env" "no_hit_color") i32)
(global $hit_color (import "env" "hit_color") i32)
(global $obj_start (import "env" "obj_start") i32)
(global $obj_size (import "env" "obj_size") i32)
(global $obj_cnt (import "env" "obj_cnt") i32)
(global $x_offset (import "env" "x_offset") i32)
(global $y_offset (import "env" "y_offset") i32)
(global $xv_offset (import "env" "xv_offset") i32)
(global $yv_offset (import "env" "yv_offset") i32)
(import "env" "buffer" (memory 80))
(func $clear_canvas
(local $i i32)
(local $pixel_bytes i32)
global.get $cnvs_size
global.get $cnvs_size
i32.mul
i32.const 4
i32.mul
local.set $pixel_bytes;; $pixel_bytes = $width * $height * 4
(loop $pixel_loop
(i32.store (local.get $i) (i32.const 0xff_00_00_00))
(i32.add (local.get $i) (i32.const 4))
local.set $i ;; $i += 4
(i32.lt_u (local.get $i) (local.get $pixel_bytes))
br_if $pixel_loop
)
)
(func $abs
(param $value i32)
(result i32)
(i32.lt_s (local.get $value) (i32.const 0))
if
i32.const 0
local.get $value
i32.sub
return
end
local.get $value
)
(func $set_pixel
(param $x i32)
(param $y i32)
(param $c i32)
(i32.ge_u (local.get $x) (global.get $cnvs_size))
if
return
end
(i32.ge_u (local.get $y) (global.get $cnvs_size))
if
return
end
local.get $y
global.get $cnvs_size
i32.mul
local.get $x
i32.add
i32.const 4
i32.mul
local.get $c
i32.store
)
(func $draw_obj
(param $x i32)
(param $y i32)
(param $c i32)
(local $max_x i32)
(local $max_y i32)
(local $xi i32)
(local $yi i32)
local.get $x
local.tee $xi
global.get $obj_size
i32.add
local.set $max_x
local.get $y
local.tee $yi
global.get $obj_size
i32.add
local.set $max_y
(block $break (loop $draw_loop
local.get $xi
local.get $yi
local.get $c
call $set_pixel
local.get $xi
i32.const 1
i32.add
local.tee $xi
local.get $max_x
i32.ge_u
if
local.get $x
local.set $xi
local.get $yi
i32.const 1
i32.add
local.tee $yi
local.get $max_y
i32.ge_u
br_if $break
end
br $draw_loop
))
)
(func $set_obj_attr
(param $obj_number i32)
(param $attr_offset i32)
(param $value i32)
local.get $obj_number
i32.const 16
i32.mul
global.get $obj_start
i32.add
local.get $attr_offset
i32.add
local.get $value
i32.store
)
(func $get_obj_attr
(param $obj_number i32)
(param $attr_offset i32)
(result i32)
local.get $obj_number
i32.const 16
i32.mul
global.get $obj_start
i32.add
local.get $attr_offset
i32.add
i32.load
)
(func $main (export "main")
(local $i i32)
(local $j i32)
(local $outer_ptr i32)
(local $inner_ptr i32)
(local $x1 i32)
(local $x2 i32)
(local $y1 i32)
(local $y2 i32)
(local $xdist i32)
(local $ydist i32)
(local $i_hit i32)
(local $xv i32)
(local $yv i32)
(call $clear_canvas)
(loop $move_loop
(call $get_obj_attr (local.get $i) (global.get $x_offset))
local.set $x1
(call $get_obj_attr (local.get $i) (global.get $y_offset))
local.set $y1
(call $get_obj_attr (local.get $i) (global.get $xv_offset))
local.set $xv
(call $get_obj_attr (local.get $i) (global.get $yv_offset))
local.set $yv
(i32.add (local.get $xv) (local.get $x1))
i32.const 0x1ff ;; 511
i32.and
local.set $x1
(i32.add (local.get $yv) (local.get $y1))
i32.const 0x1ff ;; 511
i32.and
local.set $y1
(call $set_obj_attr
(local.get $i)
(global.get $x_offset)
(local.get $x1)
)
(call $set_obj_attr
(local.get $i)
(global.get $y_offset)
(local.get $y1)
)
local.get $i
i32.const 1
i32.add
local.tee $i
global.get $obj_cnt
i32.lt_u
if
br $move_loop
end
)
i32.const 0
local.set $i
(loop $outer_loop (block $outer_break
i32.const 0
local.tee $j
local.set $i_hit
(call $get_obj_attr (local.get $i) (global.get $x_offset))
local.set $x1
(call $get_obj_attr (local.get $i) (global.get $y_offset))
local.set $y1
(loop $inner_loop (block $inner_break
local.get $i
local.get $j
i32.eq
if
local.get $j
i32.const 1
i32.add
local.set $j
end
local.get $j
global.get $obj_cnt
i32.ge_u
if
br $inner_break
end
(call $get_obj_attr (local.get $j) (global.get $x_offset))
local.set $x2
(i32.sub (local.get $x1) (local.get $x2))
call $abs
local.tee $xdist
global.get $obj_size
i32.ge_u
;; è¡çªããŠããªã
if
local.get $j
i32.const 1
i32.add
local.set $j
br $inner_loop
end
(call $get_obj_attr (local.get $j) (global.get $y_offset))
local.set $y2
(i32.sub (local.get $y1) (local.get $y2))
call $abs
local.tee $ydist
global.get $obj_size
i32.ge_u
;; è¡çªããŠããªã
if
local.get $j
i32.const 1
i32.add
local.set $j
br $inner_loop
end
i32.const 1
local.set $i_hit
))
local.get $i_hit
i32.const 0
i32.eq
if
(call $draw_obj
(local.get $x1) (local.get $y1) (global.get $no_hit_color))
else
(call $draw_obj
(local.get $x1) (local.get $y1) (global.get $hit_color))
end
local.get $i
i32.const 1
i32.add
local.tee $i
global.get $obj_cnt
i32.lt_u
if
br $outer_loop
end
))
)
)
é·ãã§ãããæåŸã®main
ããèŠãŠãããšãšãŠãåçŽãªåŠçãããŠããã ããªã®ãããããŸãã
(func $main (export "main")
(local $i i32)
(local $j i32)
(local $x1 i32)
(local $x2 i32)
(local $y1 i32)
(local $y2 i32)
(local $xdist i32)
(local $ydist i32)
(local $i_hit i32)
(local $xv i32)
(local $yv i32)
(call $clear_canvas)
ãŸããå¿
èŠãªlocalå€æ°ã宣èšããŸãã
Frameæ¯ã«åãªããžã§ã¯ãã®ç¶æ
ãæŽæ°ããã®ã§ã$i
ã¯çŸåšã®åŠç察象ã®ãªããžã§ã¯ãã®indexã§ãã$j
ã¯åãªããžã§ã¯ããšã®è¡çªå€å®ãããããã®inner loopã®indexã§ãã
æåã«$clear_canvas
ãåŒã³åºããŠã¬ã³ããªã³ã°é åããªã»ããããŸãã
(func $clear_canvas
(local $i i32)
(local $pixel_bytes i32)
global.get $cnvs_size
global.get $cnvs_size
i32.mul
i32.const 4
i32.mul
local.set $pixel_bytes;; $pixel_bytes = $width * $height * 4
(loop $pixel_loop
(i32.store (local.get $i) (i32.const 0xff_00_00_00))
(i32.add (local.get $i) (i32.const 4))
local.set $i ;; $i += 4
(i32.lt_u (local.get $i) (local.get $pixel_bytes))
br_if $pixel_loop
)
)
1pixel 4byteãªã®ã§4byteãã€ã€ã³ã¯ãªã¡ã³ãããªãããé»è²(0xff_00_00_00
)ã«ããŠãããŸãã
次ã«
(loop $move_loop
(call $get_obj_attr (local.get $i) (global.get $x_offset))
local.set $x1
(call $get_obj_attr (local.get $i) (global.get $y_offset))
local.set $y1
(call $get_obj_attr (local.get $i) (global.get $xv_offset))
local.set $xv
(call $get_obj_attr (local.get $i) (global.get $yv_offset))
local.set $yv
(i32.add (local.get $xv) (local.get $x1))
i32.const 0x1ff ;; 511
i32.and
local.set $x1
(i32.add (local.get $yv) (local.get $y1))
i32.const 0x1ff ;; 511
i32.and
local.set $y1
(call $set_obj_attr
(local.get $i)
(global.get $x_offset)
(local.get $x1)
)
(call $set_obj_attr
(local.get $i)
(global.get $y_offset)
(local.get $y1)
)
local.get $i
i32.const 1
i32.add
local.tee $i
global.get $obj_cnt
i32.lt_u
if
br $move_loop
end
)
åŠç察象ã®ãªããžã§ã¯ãã®x,y,xv,xy
ãååŸããŠãããããã®é床ãå ç®ããã®ã¡ãã¡ã¢ãªãæŽæ°ããŸãã
0x1ff
ãšandããšãããšã§ãæç»é åãã¯ã¿ã§ããªããžã§ã¯ãã®äœçœ®ããªã»ãããããããã«ãªã£ãŠããŸãã
ãããæŒç®ã§ãããªããšãã§ããã®ããšæããŸãããæ¬æžã§ã¯ãããæŒç®ã«ã€ããŠãäžå¯§ã«è§£èª¬ãããŠãããŸãã
ãããŸã§ã§ãframeã®æç»æ¯ã«ãªããžã§ã¯ãã®äœçœ®æ
å ±ãæŽæ°ãããããšãããããŸããã
æåŸã«ããªããžã§ã¯ãã®è¡çªå€å®ãè¡ããæç»é åãæŽæ°ããŸãã
i32.const 0
local.set $i
(loop $outer_loop (block $outer_break
i32.const 0
local.tee $j
local.set $i_hit
(call $get_obj_attr (local.get $i) (global.get $x_offset))
local.set $x1
(call $get_obj_attr (local.get $i) (global.get $y_offset))
local.set $y1
(loop $inner_loop (block $inner_break
local.get $i
local.get $j
i32.eq
if
local.get $j
i32.const 1
i32.add
local.set $j
end
local.get $j
global.get $obj_cnt
i32.ge_u
if
br $inner_break
end
(call $get_obj_attr (local.get $j) (global.get $x_offset))
local.set $x2
(i32.sub (local.get $x1) (local.get $x2))
call $abs
local.tee $xdist
global.get $obj_size
i32.ge_u
;; è¡çªããŠããªã
if
local.get $j
i32.const 1
i32.add
local.set $j
br $inner_loop
end
(call $get_obj_attr (local.get $j) (global.get $y_offset))
local.set $y2
(i32.sub (local.get $y1) (local.get $y2))
call $abs
local.tee $ydist
global.get $obj_size
i32.ge_u
;; è¡çªããŠããªã
if
local.get $j
i32.const 1
i32.add
local.set $j
br $inner_loop
end
i32.const 1
local.set $i_hit
))
local.get $i_hit
i32.const 0
i32.eq
if
(call $draw_obj
(local.get $x1) (local.get $y1) (global.get $no_hit_color))
else
(call $draw_obj
(local.get $x1) (local.get $y1) (global.get $hit_color))
end
local.get $i
i32.const 1
i32.add
local.tee $i
global.get $obj_cnt
i32.lt_u
if
br $outer_loop
end
))
ãªããžã§ã¯ãã®è¡çªå€å®ã¯|x1 - x2|
< object_size
ã〠|y1 - y2| < object_size
ã§å€å®ããŸãã WATãWASMã«å€æããŠ
ãå®è¡ããŠãlocalhost:8080/collide.html
ã«ã¢ã¯ã»ã¹ããŠã¿ããšä»¥äžã®ããã«æç»ãããŸããð
ãµããããªãã£ãããš
æ¬èšäºã§ã¯ãµããããŸããã§ããããæ¬æžã§ã¯ããã«ããããWASMã®ããã©ãŒãã³ã¹ãã¥ãŒãã³ã°ããããã°ããããªãããã®å®çšçãªç¥èãè¿°ã¹ãããŠãããŸãã