1 const canvas = document.querySelector('canvas')
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
10 const gl = canvas.getContext('webgl')
12 const shaderMap = new Map()
13 var currentShaderId = 0
14 function createShaderId() {
15 const id = currentShaderId
20 const programMap = new Map()
21 var currentProgramId = 0
22 function createProgramId() {
23 const id = currentProgramId
28 const bufferMap = new Map()
29 var currentBufferId = 0
30 function createBufferId() {
31 const id = currentBufferId
36 const uniformLocMap = new Map()
37 var currentUniformLocId = 0
38 function createUniformLocId() {
39 const id = currentUniformLocId
40 currentUniformLocId += 1
45 var decoder = new TextDecoder('utf-8')
47 function getUint32(addr) {
48 const view = new DataView(memory.buffer)
49 return view.getUint32(addr, true)
52 function setUint32(addr, val) {
53 const view = new DataView(memory.buffer)
54 view.setUint32(addr, val, true)
57 function getString(addr) {
58 const view = new DataView(memory.buffer)
60 while (view.getUint8(addr + len) != 0) len++
61 return decoder.decode(memory.buffer.slice(addr, addr + len))
66 glCreateShader: shaderType => {
67 const id = createShaderId()
68 const shader = gl.createShader(shaderType)
69 shaderMap.set(id, shader)
72 glShaderSource: (id, numSrcs, srcs, lens) => {
73 const shader = shaderMap.get(id)
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))
81 gl.shaderSource(shader, totalSource)
83 glCompileShader: id => gl.compileShader(shaderMap.get(id)),
84 glCreateProgram: () => {
85 const id = createProgramId()
86 const prog = gl.createProgram()
87 programMap.set(id, prog)
90 glAttachShader: (progId, shaderId) => {
91 gl.attachShader(programMap.get(progId), shaderMap.get(shaderId))
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)
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)
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)
114 glGetUniformLocation: (progId, name) => {
115 const id = createUniformLocId()
116 const loc = gl.getUniformLocation(programMap.get(progId), getString(name))
117 uniformLocMap.set(id, loc)
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)
128 const sock = new WebSocket('ws://localhost:8889')
129 sock.onmessage = function (e) {
135 function draw(tick) {
136 instance.exports.update(tick)
137 gl.drawArrays(gl.TRIANGLES, 0, 3)
138 requestAnimationFrame(draw);
141 function instantiate(bytes) {
142 return WebAssembly.compile(bytes).
144 const inst = new WebAssembly.Instance(m, imports)
145 memory = inst.exports.memory
151 .then(response => response.arrayBuffer())
152 .then(bytes => instantiate(bytes))
155 instance.exports.setup()
156 requestAnimationFrame(draw);