File size: 4,041 Bytes
eafd9a8
 
6d53e86
922216d
 
 
 
bc152ba
922216d
 
a279d3a
922216d
effc3a3
d998663
 
 
6d53e86
8288691
 
 
 
a279d3a
8288691
 
 
a279d3a
8288691
eafd9a8
8288691
 
41fe030
a279d3a
 
 
 
8288691
 
 
 
 
 
 
 
 
 
 
 
6af9568
922216d
8288691
 
922216d
 
8288691
 
 
 
 
 
922216d
8288691
 
 
922216d
8288691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eafd9a8
8288691
 
 
 
 
 
 
 
 
 
 
 
eafd9a8
8288691
 
eafd9a8
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
// index.js

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);
        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) {
            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), state.timing.frameDuration);
        }

        Tick(state);
    }

    await Main();
})();