Spaces:
Running
Running
File size: 5,323 Bytes
6d53e86 46ec188 bc152ba 46ec188 d13e19f 46ec188 9905bd0 bc152ba 6d53e86 e8a6c79 6d53e86 e8a6c79 d13e19f 9905bd0 6d53e86 9905bd0 6802c16 9905bd0 d178651 6802c16 cf65f18 9905bd0 cf65f18 9905bd0 538ade1 0391f6c 9905bd0 0391f6c 9905bd0 0391f6c 9905bd0 6d53e86 d13e19f 9905bd0 551d60d 6d53e86 6802c16 538ade1 f15ce4c 538ade1 6802c16 538ade1 9905bd0 6d53e86 9905bd0 6d53e86 551d60d 6d53e86 6802c16 9905bd0 538ade1 6802c16 538ade1 6d53e86 538ade1 6d53e86 9905bd0 9eb5291 9905bd0 ff401af 6802c16 abb941d 6802c16 9905bd0 538ade1 9905bd0 538ade1 9905bd0 6802c16 9905bd0 9eb5291 6802c16 538ade1 6802c16 9905bd0 6802c16 538ade1 9905bd0 538ade1 9905bd0 538ade1 9905bd0 538ade1 9905bd0 538ade1 9905bd0 538ade1 9905bd0 6d53e86 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 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 130 131 132 133 134 135 136 137 138 139 140 |
import { mat4 } from 'https://webgpufundamentals.org/3rdparty/wgpu-matrix.module.js';
import { initializeWebGPU } from './wgpu-device.js';
import { createState } from './wgpu-state.js';
import { generateGlyphTextureAtlas, createTextureFromSource } from './wgpu-utility.js';
import { createPipeline } from './wgpu-pipeline.js';
import { fetchShaderCode } from './wgpu-shader.js';
import { GenerateVertexDataAndTexture } from './wgpu-texture.js';
import { generateGlyphVerticesForText } from './wgpu-text.js';
import { config } from './wgpu-config.js';
import { CANVAS, CTX, COLORS, RENDER_PASS_DESCRIPTOR } from './wgpu-constants.js';
// Canvas element for rendering
const canvas = document.querySelector('canvas');
// State initialization
const state = createState(config);
state.canvas = canvas;
const FIXED_DELTA_TIME = 1 / 60;
const MAX_FRAME_TIME = 0.25;
const TARGET_FPS = 60;
const FRAME_DURATION = 1000 / TARGET_FPS;
// Ensure timing object exists within state
state.timing = state.timing || {};
state.timing.fixedDeltaTime = FIXED_DELTA_TIME;
state.timing.maxFrameTime = MAX_FRAME_TIME;
state.timing.targetFps = TARGET_FPS;
state.timing.frameDuration = FRAME_DURATION;
async function Main() {
const adapter = await navigator.gpu?.requestAdapter();
const { device, context, presentationFormat } = await initializeWebGPU(navigator, adapter, state.canvas);
if (!device) return;
state.webgpu.device = device;
state.webgpu.context = context;
state.webgpu.presentationFormat = presentationFormat;
// Initialize Resources
await InitializeResources();
// Start the game loop
GameLoop();
}
async function InitializeResources() {
const shaderCode = await fetchShaderCode('shaders.wgsl');
const vertexSize = config.floatsPerVertex * 4;
state.webgpu.pipeline = await createPipeline(state.webgpu.device, state.webgpu.presentationFormat, vertexSize, shaderCode);
const glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
document.body.appendChild(glyphCanvas);
glyphCanvas.style.backgroundColor = '#222';
CreateBuffers();
GenerateVertexDataAndTexture(state, glyphCanvas, generateGlyphVerticesForText, COLORS, config, createTextureFromSource);
}
function CreateBuffers() {
const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * config.floatsPerVertex * 4;
state.webgpu.vertexBuffer = state.webgpu.device.createBuffer({
label: 'vertices',
size: vertexBufferSize,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
state.webgpu.indexBuffer = state.webgpu.device.createBuffer({
label: 'indices',
size: config.maxGlyphs * config.vertsPerGlyph * 4,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});
const indices = GenerateIndices(config.maxGlyphs);
state.webgpu.device.queue.writeBuffer(state.webgpu.indexBuffer, 0, new Uint32Array(indices));
}
function GenerateIndices(maxGlyphs) {
return Array.from({ length: maxGlyphs * 6 }, (_, i) => {
const ndx = Math.floor(i / 6) * 4;
return (i % 6 < 3 ? [ndx, ndx + 1, ndx + 2] : [ndx + 2, ndx + 1, ndx + 3])[i % 3];
});
}
function GameLoop() {
let lastTime = performance.now();
state.timing.accumulator = 0;
function Tick() {
const currentTime = performance.now();
const frameTime = (currentTime - lastTime) / 1000;
lastTime = currentTime;
const deltaTime = Math.min(frameTime, state.timing.maxFrameTime);
state.timing.accumulator += deltaTime;
while (state.timing.accumulator >= state.timing.fixedDeltaTime) {
FixedUpdate(state.timing.fixedDeltaTime);
state.timing.accumulator -= state.timing.fixedDeltaTime;
}
const alpha = state.timing.accumulator / state.timing.fixedDeltaTime;
Render(alpha);
setTimeout(Tick, state.timing.frameDuration);
}
Tick();
}
function FixedUpdate(deltaTime) {
state.timing.time += deltaTime;
}
function Render(alpha) {
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()]);
}
Main();
|