draw(indices, mainGlyph, trans) { const mainGlGlyph = mainGlyph.glglyph; if (mainGlGlyph.data_changed) { if (!(isFinite(trans.dx) && isFinite(trans.dy))) { return; // not sure why, but it happens on init sometimes (#4367) } mainGlGlyph._baked_offset = [trans.dx, trans.dy]; // float32 precision workaround; used in _bake() and below mainGlGlyph._set_data(); mainGlGlyph.data_changed = false; } if (this.visuals_changed) { this._set_visuals(); this.visuals_changed = false; } // Decompose x-y scale into scalar scale and aspect-vector. let { sx } = trans; let { sy } = trans; const scale_length = Math.sqrt((sx * sx) + (sy * sy)); sx /= scale_length; sy /= scale_length; // Do we need to re-calculate segment data and cumsum? if (Math.abs(this._scale_aspect - (sy / sx)) > Math.abs(1e-3 * this._scale_aspect)) { mainGlGlyph._update_scale(sx, sy); this._scale_aspect = sy / sx; } // Select buffers from main glyph // (which may be this glyph but maybe not if this is a (non)selection glyph) this.prog.set_attribute('a_position', 'vec2', mainGlGlyph.vbo_position); this.prog.set_attribute('a_tangents', 'vec4', mainGlGlyph.vbo_tangents); this.prog.set_attribute('a_segment', 'vec2', mainGlGlyph.vbo_segment); this.prog.set_attribute('a_angles', 'vec2', mainGlGlyph.vbo_angles); this.prog.set_attribute('a_texcoord', 'vec2', mainGlGlyph.vbo_texcoord); // this.prog.set_uniform('u_length', 'float', [mainGlGlyph.cumsum]); this.prog.set_texture('u_dash_atlas', this.dash_atlas.tex); // Handle transformation to device coordinates const baked_offset = mainGlGlyph._baked_offset; this.prog.set_uniform('u_pixel_ratio', 'float', [trans.pixel_ratio]); this.prog.set_uniform('u_canvas_size', 'vec2', [trans.width, trans.height]); this.prog.set_uniform('u_offset', 'vec2', [trans.dx - baked_offset[0], trans.dy - baked_offset[1]]); this.prog.set_uniform('u_scale_aspect', 'vec2', [sx, sy]); this.prog.set_uniform('u_scale_length', 'float', [scale_length]); this.I_triangles = mainGlGlyph.I_triangles; if (this.I_triangles.length < 65535) { // Data is small enough to draw in one pass this.index_buffer.set_size(this.I_triangles.length*2); this.index_buffer.set_data(0, new Uint16Array(this.I_triangles)); return this.prog.draw(this.gl.TRIANGLES, this.index_buffer); // @prog.draw(@gl.LINE_STRIP, @index_buffer) # Use this to draw the line skeleton } else { // Work around the limit that the indexbuffer must be uint16. We draw in chunks. // First collect indices in chunks indices = this.I_triangles; const nvertices = this.I_triangles.length; const chunksize = 64008; // 65536 max. 64008 is divisible by 12 const chunks = []; for (let i = 0, end = Math.ceil(nvertices/chunksize); i < end; i++) { chunks.push([]); } for (let i = 0, end = indices.length; i < end; i++) { const uint16_index = indices[i] % chunksize; const chunk = Math.floor(indices[i] / chunksize); chunks[chunk].push(uint16_index); } // Then draw each chunk for (let chunk = 0, end = chunks.length; chunk < end; chunk++) { const these_indices = new Uint16Array(chunks[chunk]); const offset = chunk * chunksize * 4; if (these_indices.length === 0) { continue; } this.prog.set_attribute('a_position', 'vec2', mainGlGlyph.vbo_position, 0, offset * 2); this.prog.set_attribute('a_tangents', 'vec4', mainGlGlyph.vbo_tangents, 0, offset * 4); this.prog.set_attribute('a_segment', 'vec2', mainGlGlyph.vbo_segment, 0, offset * 2); this.prog.set_attribute('a_angles', 'vec2', mainGlGlyph.vbo_angles, 0, offset * 2); this.prog.set_attribute('a_texcoord', 'vec2', mainGlGlyph.vbo_texcoord, 0, offset * 2); // The actual drawing this.index_buffer.set_size(these_indices.length*2); this.index_buffer.set_data(0, these_indices); this.prog.draw(this.gl.TRIANGLES, this.index_buffer); } } }