aboutsummaryrefslogtreecommitdiffhomepage
path: root/canvasWorker.js
blob: 51878f62b4c247194ef790397c78710d529f8470 (plain) (blame)
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
let canvas, gl;

const createShader = (gl, type, source) => {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) return shader;

  console.error(gl.getShaderInfoLog(shader));
  gl.deleteShader(shader);
};

const createProgram = (gl, vertexShader, fragmentShader) => {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  const success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (success) return program;

  console.error(gl.getProgramInfoLog(program));
  gl.deleteProgram(program);
};

const initGL = () => {
  const vertexShaderSource = `
  attribute vec2 a_position;
  uniform vec2 u_resolution;
  void main() {
	vec2 inverted = vec2(a_position.x, u_resolution.y - a_position.y); // !! :)
    vec2 zeroToOne = inverted / u_resolution;
    vec2 zeroToTwo = zeroToOne * 2.0;
	vec2 clipSpace = zeroToTwo - 1.0;
    gl_Position = vec4(clipSpace, 0, 1);
  }`;
  const fragmentShaderSource = `
  precision mediump float;
  uniform vec4 u_color;
  void main() {
    gl_FragColor = u_color;
  }`;

  const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
  const fragmentShader = createShader(
    gl,
    gl.FRAGMENT_SHADER,
    fragmentShaderSource,
  );

  const program = createProgram(gl, vertexShader, fragmentShader);
  const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
  const colorUniformLocation = gl.getUniformLocation(program, "u_color");
  const resolutionUniformLocation = gl.getUniformLocation(
    program,
    "u_resolution",
  );

  const positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.useProgram(program);
  gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
  gl.enableVertexAttribArray(positionAttributeLocation);
  gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

  return (positions, color) => {
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.uniform4f(colorUniformLocation, ...color);
    gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
  };
};

let useWebGL = true;

let draw;
self.onmessage = (msg) => {
  if (msg.data == "clear") {
    if (useWebGL) {
      gl.clearColor(0, 0, 0, 0);
      gl.clear(gl.COLOR_BUFFER_BIT);
    } else {
      gl.clearRect(0, 0, canvas.width, canvas.height);
    }
  } else if ("canvas" in msg.data) {
    canvas = msg.data.canvas;
    useWebGL = msg.data.useWebGL;
    if (useWebGL) {
      console.log("using WebGL");
      // i hate this
      try {
        gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
        if (!gl)
          gl = canvas.getContext("experimental-webgl", {
            preserveDrawingBuffer: true,
          });
      } catch (e) {
      } finally {
        if (!gl) {
          console.error("WebGL not supported, using canvas instead.");
          useWebGL = false;
          gl = canvas.getContext("2d");
          return;
        }
      }
      gl.viewport(0, 0, canvas.width, canvas.height);
      draw = initGL();
    } else {
      useWebGL = false;
      console.log("using canvas");
      gl = canvas.getContext("2d");
    }
  } else if (useWebGL) {
    const [color, x, y, width, height] = msg.data;
    let colorArr =
      color == "white"
        ? [1, 1, 1, 1]
        : color == "black"
          ? [0, 0, 0, 1]
          : [0.1, 0.1, 0.1, 0.3];
    draw([x, y + height, x + width, y + height, x + width, y, x, y], colorArr);
  } else {
    const [color, x, y, width, height] = msg.data;
    if (width < 4 || height < 4) return;
    gl.fillStyle = color;
    gl.fillRect(x, y, width, height);
  }
};