File size: 3,905 Bytes
922216d
 
6d53e86
922216d
 
 
 
bc152ba
922216d
 
effc3a3
d13e19f
922216d
effc3a3
d998663
 
 
6d53e86
922216d
99b5acd
 
41fe030
99b5acd
0870851
6af9568
0870851
6af9568
 
 
0391f6c
 
effc3a3
80dd0f2
d998663
551d60d
6d53e86
 
 
b27f287
f15ce4c
538ade1
 
d998663
 
6802c16
538ade1
effc3a3
538ade1
9905bd0
538ade1
 
 
922216d
9905bd0
 
538ade1
922216d
9905bd0
 
 
922216d
9905bd0
922216d
9905bd0
 
 
 
538ade1
922216d
9905bd0
6d53e86
 
922216d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6802c16
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
// 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 { initializeTiming } from './wgpu-timing.js';
import { createPipeline } 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 function InitializeCanvas(state) {
    state.canvas.width = config.canvas.width;
    state.canvas.height = config.canvas.height;

    state.webgpu.adapter = await navigator.gpu.requestAdapter();
    await initializeDevice(state);

    if (!state.webgpu.device) {
        alert('Failed to initialize WebGPU');
        return;
    }
}

async function InitializeResources(state) {
    state.webgpu.pipeline = await createPipeline(state.webgpu.device, state.webgpu.presentationFormat, state.webgpu.vertexSize, state.webgpu.shaderCode);

    const glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
    document.body.appendChild(glyphCanvas);
    glyphCanvas.style.backgroundColor = '#222';

    CreateBuffers(state, config);
    GenerateVertexDataAndTexture(state, 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();
}

const state = createState(config);

async function Main() {
    await InitializeCanvas(state);
    initializeTiming(state);
    await InitializeShaders(state);
    await InitializeResources(state);
    GameLoop(state);
}

Main();