document.addEventListener('DOMContentLoaded', main); function draw(state, context) { const gl = context.gl; const locations = context.locations; const buffers = context.buffers; const width = window.innerWidth; const height = window.innerHeight; gl.viewport(0, 0, context.canvas.width, context.canvas.height); gl.clearColor(context.bgcolor.r, context.bgcolor.g, context.bgcolor.b, 1); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(context.program); gl.enableVertexAttribArray(locations['a_pos']); gl.enableVertexAttribArray(locations['a_color']); gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height); gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom); gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y); gl.uniform1i(locations['u_layer'], 0); const total_pos_size = context.static_positions_f32.byteLength + context.dynamic_positions_f32.byteLength; const total_color_size = context.static_colors_u8.byteLength + context.dynamic_colors_u8.byteLength; const total_point_count = (context.static_positions.length + context.dynamic_positions.length) / 2; gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_pos']); gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 0, 0); gl.bufferData(gl.ARRAY_BUFFER, total_pos_size, gl.DYNAMIC_DRAW); gl.bufferSubData(gl.ARRAY_BUFFER, 0, context.static_positions_f32); gl.bufferSubData(gl.ARRAY_BUFFER, context.static_positions_f32.byteLength, context.dynamic_positions_f32); gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_color']); gl.vertexAttribPointer(locations['a_color'], 3, gl.UNSIGNED_BYTE, true, 0, 0); gl.bufferData(gl.ARRAY_BUFFER, total_color_size, gl.DYNAMIC_DRAW); gl.bufferSubData(gl.ARRAY_BUFFER, 0, context.static_colors_u8); gl.bufferSubData(gl.ARRAY_BUFFER, context.static_colors_u8.byteLength, context.dynamic_colors_u8); gl.drawArrays(gl.TRIANGLES, 0, total_point_count); } function main() { const state = { 'canvas': { 'offset': { 'x': 0, 'y': 0 }, 'zoom': 1.0, }, 'cursor': { 'x': 0, 'y': 0, }, 'moving': false, 'drawing': false, 'spacedown': false, 'stroke_width': 8, 'current_stroke': { 'color': 0, 'points': [], }, 'strokes': [], }; const context = { 'canvas': null, 'gl': null, 'program': null, 'buffers': {}, 'locations': {}, 'static_positions': [], 'dynamic_positions': [], 'static_colors': [], 'dynamic_colors': [], 'static_positions_f32': new Float32Array(0), 'dynamic_positions_f32': new Float32Array(0), 'static_colors_u8': new Uint8Array(0), 'dynamic_colors_u8': new Uint8Array(0), 'bgcolor': {'r': 0, 'g': 0, 'b': 0}, }; init_webgl(state, context); init_listeners(state, context); window.requestAnimationFrame(() => draw(state, context)); }