All files / src/components/VirtualWalkthrough xr-exit-button-mask.ts

100% Statements 25/25
100% Branches 0/0
100% Functions 1/1
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46  3x     3x 3x                     3x 5x   5x   5x 5x 5x   5x   5x 5x 5x 5x   5x 5x 5x 5x 5x 5x 5x 5x 5x 5x   5x    
/** Backing disc radius as a fraction of the button's half-size. Matches the shader's pie radius. */
const DISC_RADIUS = 0.92;
 
/** Glyph arm reach and stroke width, as fractions of the drawn size. */
const GLYPH_ARM = 0.24;
const GLYPH_WIDTH = 0.09;
 
/**
 * Bakes the exit button's static artwork into a two-channel mask: red covers the backing disc, green
 * the X glyph. The shader composites the progress sweep between the two, which is what keeps the
 * glyph legible over the fill.
 *
 * The channels have to stay independent, so the glyph is drawn additively rather than over the disc,
 * and an opaque base goes down first. Uniform full alpha means the mask survives the texture upload
 * whether or not alpha ends up premultiplied, and antialiased edges keep their coverage.
 */
export const drawExitButtonMask = (ctx: CanvasRenderingContext2D, size: number) => {
  const c = size / 2;
 
  ctx.save();
 
  ctx.globalCompositeOperation = 'source-over';
  ctx.fillStyle = '#000000';
  ctx.fillRect(0, 0, size, size);
 
  ctx.globalCompositeOperation = 'lighter';
 
  ctx.fillStyle = '#ff0000';
  ctx.beginPath();
  ctx.arc(c, c, c * DISC_RADIUS, 0, Math.PI * 2);
  ctx.fill();
 
  const arm = size * GLYPH_ARM;
  ctx.strokeStyle = '#00ff00';
  ctx.lineWidth = size * GLYPH_WIDTH;
  ctx.lineCap = 'round';
  ctx.beginPath();
  ctx.moveTo(c - arm, c - arm);
  ctx.lineTo(c + arm, c + arm);
  ctx.moveTo(c + arm, c - arm);
  ctx.lineTo(c - arm, c + arm);
  ctx.stroke();
 
  ctx.restore();
};