Add uniforms
[wasm.git] / main.js
1 const canvas = document.querySelector('canvas')
2
3 // hidpi
4 const width = canvas.width, height = canvas.height
5 canvas.style.width = width + 'px'
6 canvas.style.height = height + 'px'
7 canvas.width = width * window.devicePixelRatio
8 canvas.height = height * window.devicePixelRatio
9
10 const gl = canvas.getContext('webgl')
11
12 const shaderMap = new Map()
13 var currentShaderId = 0
14 function createShaderId() {
15         const id = currentShaderId
16         currentShaderId += 1
17         return id
18 }
19
20 const programMap = new Map()
21 var currentProgramId = 0
22 function createProgramId() {
23         const id = currentProgramId
24         currentProgramId += 1
25         return id
26 }
27
28 const bufferMap = new Map()
29 var currentBufferId = 0
30 function createBufferId() {
31         const id = currentBufferId
32         currentBufferId += 1
33         return id
34 }
35
36 const uniformLocMap = new Map()
37 var currentUniformLocId = 0
38 function createUniformLocId() {
39         const id = currentUniformLocId
40         currentUniformLocId += 1
41         return id
42 }
43
44 var memory
45 var decoder = new TextDecoder('utf-8')
46
47 function getUint32(addr) {
48         const view = new DataView(memory.buffer)
49         return view.getUint32(addr, true)
50 }
51
52 function setUint32(addr, val) {
53         const view = new DataView(memory.buffer)
54         view.setUint32(addr, val, true)
55 }
56
57 function getString(addr) {
58         const view = new DataView(memory.buffer)
59         var len = 0
60         while (view.getUint8(addr + len) != 0) len++
61         return decoder.decode(memory.buffer.slice(addr, addr + len))
62 }
63
64 const imports = {
65         env: {
66                 glCreateShader: shaderType => {
67                         const id = createShaderId()
68                         const shader = gl.createShader(shaderType)
69                         shaderMap.set(id, shader)
70                         return id
71                 },
72                 glShaderSource: (id, numSrcs, srcs, lens) => {
73                         const shader = shaderMap.get(id)
74                         var totalSource = ''
75                         for (let i = 0; i < numSrcs; i++) {
76                                 const addr = srcs + i * 4
77                                 const src = getUint32(addr)
78                                 const len = getUint32(lens + i * 4)
79                                 totalSource += decoder.decode(memory.buffer.slice(src, src + len))
80                         }
81                         gl.shaderSource(shader, totalSource)
82                 },
83                 glCompileShader: id => gl.compileShader(shaderMap.get(id)),
84                 glCreateProgram: () => {
85                         const id = createProgramId()
86                         const prog = gl.createProgram()
87                         programMap.set(id, prog)
88                         return id
89                 },
90                 glAttachShader: (progId, shaderId) => {
91                         gl.attachShader(programMap.get(progId), shaderMap.get(shaderId))
92                 },
93                 glLinkProgram: (progId) => gl.linkProgram(programMap.get(progId)),
94                 glUseProgram: (progId) => gl.useProgram(programMap.get(progId)),
95                 glGetAttribLocation: (progId, name) =>
96                         gl.getAttribLocation(programMap.get(progId), getString(name)),
97                 glEnableVertexAttribArray: (loc) => gl.enableVertexAttribArray(loc),
98                 glVertexAttribPointer: (loc, size, type, normalized, stride, offset) => {
99                         gl.vertexAttribPointer(loc, size, type, normalized, stride, offset)
100                 },
101                 glGenBuffers: (num, addr) => {
102                         for (let i = 0; i < num; i++) {
103                                 const id = createBufferId()
104                                 const buffer = gl.createBuffer()
105                                 bufferMap.set(id, buffer)
106                                 setUint32(addr + i * 4, id)
107                         }
108                 },
109                 glBindBuffer: (target, bufferId) => gl.bindBuffer(target, bufferMap.get(bufferId)),
110                 glBufferData: (target, size, addr, usage) => {
111                         const data = new Float32Array(memory.buffer.slice(addr, addr + size * 4))
112                         gl.bufferData(target, data, usage)
113                 },
114                 glGetUniformLocation: (progId, name) => {
115                         const id = createUniformLocId()
116                         const loc = gl.getUniformLocation(programMap.get(progId), getString(name))
117                         uniformLocMap.set(id, loc)
118                         return id
119                 },
120                 glUniformMatrix4fv: (loc, count, transpose, addr) => {
121                         if (count != 1) throw Error('count must be 1')
122                         const vals = new Float32Array(memory.buffer.slice(addr, addr + 4 * 16))
123                         gl.uniformMatrix4fv(uniformLocMap.get(loc), transpose, vals)
124                 }
125         }
126 }
127
128 const sock = new WebSocket('ws://localhost:8889')
129 sock.onmessage = function (e) {
130         console.log(e.data)
131 }
132
133 var instance
134
135 function draw(tick) {
136         instance.exports.update(tick)
137         gl.drawArrays(gl.TRIANGLES, 0, 3)
138         requestAnimationFrame(draw);
139 }
140
141 function instantiate(bytes) {
142   return WebAssembly.compile(bytes).
143                 then(m => {
144                         const inst = new WebAssembly.Instance(m, imports)
145                         memory = inst.exports.memory
146                         return inst
147                 })
148 }
149
150 fetch('test.wasm')
151         .then(response => response.arrayBuffer())
152         .then(bytes => instantiate(bytes))
153         .then(i => {
154                 instance = i
155                 instance.exports.setup()
156                 requestAnimationFrame(draw);
157         })