import { showError } from "./debug"; import "./style.css"; import vsSource from "./shaders/basic.vert?raw"; import fsSource from "./shaders/basic.frag?raw"; import { loadBuffer, loadProgram, loadShader } from "./utils/shader"; import Vector2D from "./geometry/Vector2D"; import { createBasicVao } from "./utils/vao"; import Shape2D from "./geometry/Shape2D"; import outline from "./data/letter_outline.json"; import solid from "./data/letter_triangle.json"; import { Timeline, Track } from "./utils/sequence"; function render() { const canvas = document.querySelector("#canvas"); if (!canvas) { throw new Error("Canvas does not exist"); } const gl = canvas.getContext("webgl2"); if (!gl) { throw new Error("This browser does not support WebGL 2"); } const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); const program = loadProgram(gl, vertexShader, fragmentShader); gl.useProgram(program); const vertexPositionAttribLocation = gl.getAttribLocation(program, "vertexPosition"); if (vertexPositionAttribLocation < 0) { throw new Error("Failed to get attrib location for vertexPosition"); } const kVerts = new Float32Array(outline.k.vertices); const kBuffer = loadBuffer(gl, kVerts); const kVao = createBasicVao(gl, kBuffer, vertexPositionAttribLocation); const eVerts = new Float32Array(outline.e.vertices); const eBuffer = loadBuffer(gl, eVerts); const eVao = createBasicVao(gl, eBuffer, vertexPositionAttribLocation); const aVerts = new Float32Array(outline.a.vertices); const aBuffer = loadBuffer(gl, aVerts); const aVao = createBasicVao(gl, aBuffer, vertexPositionAttribLocation); const KVerts = new Float32Array(solid.k.vertices); const KBuffer = loadBuffer(gl, KVerts); const KVao = createBasicVao(gl, KBuffer, vertexPositionAttribLocation); const EVerts = new Float32Array(solid.e.vertices); const EBuffer = loadBuffer(gl, EVerts); const EVao = createBasicVao(gl, EBuffer, vertexPositionAttribLocation); const AVerts = new Float32Array(solid.a.vertices); const ABuffer = loadBuffer(gl, AVerts); const AVao = createBasicVao(gl, ABuffer, vertexPositionAttribLocation); const shapes: Shape2D[] = [ new Shape2D(new Vector2D(0, 0), 200, [0.22745, 0.35294, 0.25098], kVerts.length / 2, kVao, gl.LINES), new Shape2D(new Vector2D(0, 0), 200, [0.22745, 0.35294, 0.25098], eVerts.length / 2, eVao, gl.LINES), new Shape2D(new Vector2D(0, 0), 200, [0.22745, 0.35294, 0.25098], aVerts.length / 2, aVao, gl.LINES), new Shape2D(new Vector2D(0, 0), 800, [0.98823, 0.30980, 0.21960], KVerts.length / 2, KVao, gl.TRIANGLES), new Shape2D(new Vector2D(0, 0), 800, [0.98823, 0.30980, 0.21960], EVerts.length / 2, EVao, gl.TRIANGLES), new Shape2D(new Vector2D(0, 0), 800, [0.98823, 0.30980, 0.21960], AVerts.length / 2, AVao, gl.TRIANGLES), ] const pTrackK = new Track([ { time: 0.0, value: [300, -200] }, { time: 0.5, value: [300, 300] }, ]); const pTrackE = new Track([ { time: 0.5, value: [625, 900] }, { time: 1.0, value: [625, 300] }, ]); const pTrackA = new Track([ { time: 1.0, value: [900, -200] }, { time: 1.5, value: [900, 300] }, ]); const qTrackK = new Track([ { time: 5.0, value: [100, 610] }, { time: 5.5, value: [100, 75] }, ]); const qTrackE = new Track([ { time: 5.5, value: [450, -500] }, { time: 6.0, value: [450, 75] }, ]); const qTrackA = new Track([ { time: 6.0, value: [800, 610] }, { time: 6.5, value: [800, 75] }, ]); const bgTrack = new Track([ { time: 0, value: [0.0, 0.0, 0.0] }, { time: 4.5, value: [0.0, 0.0, 0.0] }, { time: 5.0, value: [0.22745, 0.35294, 0.25098] }, ]); const timeline = new Timeline({ "position0": pTrackK, "position1": pTrackE, "position2": pTrackA, "position3": qTrackK, "position4": qTrackE, "position5": qTrackA, "backgroundColor": bgTrack }, 9.5, true); const fragmentColorUniform = gl.getUniformLocation(program, "uColor"); const canvasSizeUniform = gl.getUniformLocation(program, "uCanvasSize"); const shapeLocationUniform = gl.getUniformLocation(program, "uLocation"); const shapeScaleUniform = gl.getUniformLocation(program, "uScale"); if (!(fragmentColorUniform && canvasSizeUniform && shapeLocationUniform && shapeScaleUniform)) { throw new Error(`Some uniform not found: ${fragmentColorUniform ? "" : "uColor"}; ${canvasSizeUniform ? "" : "uCanvasSize"}; ${shapeLocationUniform ? "" : "uLocation"}; ${shapeScaleUniform ? "" : "uScale"}; `); } let startTime = performance.now(); const frame = () => { const currentTime = (performance.now() - startTime) / 1000; const interpolatedValues = timeline.update(currentTime); const [r, g, b, a] = interpolatedValues.backgroundColor as number[]; canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; gl.clearColor(r, g, b, a); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, canvas.width, canvas.height); gl.uniform2f(canvasSizeUniform, canvas.width, canvas.height); shapes.forEach((shape, index) => { const positionKey = `position${index}`; const [x, y] = interpolatedValues[positionKey] as number[]; gl.uniform3f(fragmentColorUniform, shape.color[0], shape.color[1], shape.color[2]); gl.uniform2f(shapeLocationUniform, x, y); gl.uniform1f(shapeScaleUniform, shape.scale); gl.bindVertexArray(shape.vao); gl.drawArrays(shape.renderType, 0, shape.verticesCount); }); requestAnimationFrame(frame) } requestAnimationFrame(frame); } try { render(); } catch (err) { showError(err); }