File size: 4,057 Bytes
6d53e86
922216d
 
 
 
bc152ba
922216d
 
a279d3a
922216d
effc3a3
d998663
 
 
6d53e86
8288691
 
 
 
a279d3a
8288691
 
 
a279d3a
 
 
 
8288691
 
 
41fe030
a279d3a
 
 
 
8288691
 
 
 
 
 
 
 
 
 
 
 
6af9568
922216d
8288691
 
922216d
 
8288691
 
 
 
 
 
922216d
8288691
 
 
922216d
8288691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
922216d
8288691
 
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
import { mat4 } from 'https://webgpufundamentals.org/3rdparty/wgpu-matrix.module.js';

import { CANVAS, CTX, COLORS, RENDER_PASS_DESCRIPTOR } from './wgpu-constants.js';
import { config } from './wgpu-config.js';

import { createState } from './wgpu-state.js';
import { initializeDevice } from './wgpu-device.js';
import { CreateBuffers } from './wgpu-buffer.js';
import { InitializePipeline } from './wgpu-pipeline.js';

import { generateGlyphTextureAtlas, createTextureFromSource } from './wgpu-utility.js';
import { InitializeShaders } from './wgpu-shader.js';
import { GenerateVertexDataAndTexture } from './wgpu-texture.js';
import { generateGlyphVerticesForText } from './wgpu-text.js';

(async () => {
    const state = createState(config);

    async function Main() {
        await InitializeAdapter(state);
        await InitializeCanvas(state);
        await initializeDevice(state);
        await InitializeShaders(state);
        await InitializePipeline(state);

        state.timing.lastTime = performance.now();

        await InitializeResources(state);
        GameLoop(state);
    }

    async function InitializeAdapter(state) {
        state.webgpu.adapter = await navigator.gpu.requestAdapter();
    }

    async function InitializeCanvas(state) {
        state.canvas.width = config.canvas.width;
        state.canvas.height = config.canvas.height;
    }

    async function InitializeResources(state) {
        state.webgpu.glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
        document.body.appendChild(state.webgpu.glyphCanvas);
        state.webgpu.glyphCanvas.style.backgroundColor = '#222';

        CreateBuffers(state, config);
        GenerateVertexDataAndTexture(state, state.webgpu.glyphCanvas, generateGlyphVerticesForText, COLORS, config, createTextureFromSource);
    }

    function FixedUpdate(state) {
        state.timing.time += state.timing.fixedDeltaTime;
    }

    function Render(state) {
        const fov = 60 * Math.PI / 180;
        const aspect = state.canvas.clientWidth / state.canvas.clientHeight;
        const projectionMatrix = mat4.perspective(fov, aspect, config.render.zNear, config.render.zFar);
        const viewMatrix = mat4.lookAt([0, 0, 5], [0, 0, 0], [0, 1, 0]);
        const viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);

        RENDER_PASS_DESCRIPTOR.colorAttachments[0].view = state.webgpu.context.getCurrentTexture().createView();
        const encoder = state.webgpu.device.createCommandEncoder();
        const pass = encoder.beginRenderPass(RENDER_PASS_DESCRIPTOR);

        pass.setPipeline(state.webgpu.pipeline);
        mat4.rotateY(viewProjectionMatrix, state.timing.time, state.matrices.matrix);
        mat4.translate(state.matrices.matrix, [-state.glyphs.width / 2, -state.glyphs.height / 2, 0], state.matrices.matrix);

        state.webgpu.device.queue.writeBuffer(state.webgpu.uniformBuffer, 0, state.matrices.uniformValues);

        pass.setBindGroup(0, state.webgpu.bindGroup);
        pass.setVertexBuffer(0, state.webgpu.vertexBuffer);
        pass.setIndexBuffer(state.webgpu.indexBuffer, 'uint32');
        pass.drawIndexed(state.glyphs.numGlyphs * 6);
        pass.end();

        state.webgpu.device.queue.submit([encoder.finish()]);
    }

    function GameLoop(state) {
        function Tick() {
            state.timing.currentTime = performance.now();
            state.timing.frameTime = (state.timing.currentTime - state.timing.lastTime) / 1000;
            state.timing.lastTime = state.timing.currentTime;
            state.timing.deltaTime = Math.min(state.timing.frameTime, state.timing.maxFrameTime);
            state.timing.accumulator += state.timing.deltaTime;

            while (state.timing.accumulator >= state.timing.fixedDeltaTime) {
                FixedUpdate(state);
                state.timing.accumulator -= state.timing.fixedDeltaTime;
            }

            Render(state);
            setTimeout(Tick, state.timing.frameDuration);
        }

        Tick();
    }

    await Main();
})();