Spaces:
Running
Running
File size: 5,563 Bytes
6d53e86 46ec188 bc152ba 46ec188 d13e19f 46ec188 1f14940 bc152ba 6d53e86 e8a6c79 6d53e86 e8a6c79 d13e19f 6d53e86 6802c16 e8a6c79 6802c16 cf65f18 538ade1 0391f6c 538ade1 6d53e86 d13e19f e8a6c79 d13e19f 6d53e86 e8a6c79 551d60d 6d53e86 538ade1 6802c16 538ade1 f15ce4c 538ade1 0391f6c 6802c16 538ade1 d13e19f 6d53e86 d13e19f 6d53e86 551d60d 6d53e86 6802c16 538ade1 0391f6c 6802c16 e8a6c79 538ade1 6d53e86 538ade1 6d53e86 0391f6c 6802c16 9eb5291 6802c16 ff401af 6802c16 abb941d 6802c16 538ade1 6802c16 538ade1 6802c16 e8a6c79 9eb5291 6802c16 538ade1 0391f6c 6802c16 538ade1 6802c16 538ade1 0391f6c 6802c16 538ade1 6d53e86 0391f6c 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 141 142 143 144 145 146 147 148 |
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);
const FIXED_DELTA_TIME = 1 / 60; // Fixed time step of 60 FPS for physics and game logic
const MAX_FRAME_TIME = 0.25; // Maximum time to simulate per frame to prevent spiral of death
const TARGET_FPS = 60; // Target frames per second
const FRAME_DURATION = 1000 / TARGET_FPS; // Duration of a single frame in milliseconds
async function Main() {
const adapter = await navigator.gpu?.requestAdapter();
const { device, context, presentationFormat } = await initializeWebGPU(navigator, adapter, canvas);
if (!device) return;
state.device = device;
// Initialize Resources
await InitializeResources(presentationFormat);
// Start the game loop
GameLoop(context);
}
// Initialize shaders, pipeline, textures, and buffers
async function InitializeResources(presentationFormat) {
// Load shader code
const shaderCode = await fetchShaderCode('shaders.wgsl');
const vertexSize = config.floatsPerVertex * 4;
// Create rendering pipeline
state.pipeline = await createPipeline(state.device, presentationFormat, vertexSize, shaderCode);
// Generate glyph texture atlas
const glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
document.body.appendChild(glyphCanvas);
glyphCanvas.style.backgroundColor = '#222';
// Create vertex and index buffers
CreateBuffers();
// Generate vertex buffer data and texture
GenerateVertexDataAndTexture(state, glyphCanvas, generateGlyphVerticesForText, COLORS, config, createTextureFromSource);
}
// Function to create vertex and index buffers
function CreateBuffers() {
const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * config.floatsPerVertex * 4;
state.vertexBuffer = state.device.createBuffer({
label: 'vertices',
size: vertexBufferSize,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
state.indexBuffer = state.device.createBuffer({
label: 'indices',
size: config.maxGlyphs * config.vertsPerGlyph * 4,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});
const indices = GenerateIndices(config.maxGlyphs);
state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
}
// Function to generate indices for glyphs
function GenerateIndices(maxGlyphs) {
// Generate index array for glyphs
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];
});
}
// Game loop function
function GameLoop(context) {
let lastTime = performance.now();
let accumulator = 0;
function Tick() {
const currentTime = performance.now();
const frameTime = (currentTime - lastTime) / 1000;
lastTime = currentTime;
const deltaTime = Math.min(frameTime, MAX_FRAME_TIME);
accumulator += deltaTime;
// Fixed time step updates for game logic
while (accumulator >= FIXED_DELTA_TIME) {
FixedUpdate(FIXED_DELTA_TIME);
accumulator -= FIXED_DELTA_TIME;
}
// Variable time step update for rendering
const alpha = accumulator / FIXED_DELTA_TIME;
Render(alpha, context);
// Schedule the next frame update
setTimeout(Tick, FRAME_DURATION);
}
Tick();
}
// Fixed update function for game logic
function FixedUpdate(deltaTime) {
state.time += deltaTime;
// Perform game logic updates here, such as physics and AI
}
// Render function
function Render(alpha, context) {
// Set up projection and view matrices
const fov = 60 * Math.PI / 180;
const aspect = canvas.clientWidth / 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 = context.getCurrentTexture().createView();
const encoder = state.device.createCommandEncoder();
const pass = encoder.beginRenderPass(RENDER_PASS_DESCRIPTOR);
pass.setPipeline(state.pipeline);
mat4.rotateY(viewProjectionMatrix, state.time, state.matrix);
mat4.translate(state.matrix, [-state.width / 2, -state.height / 2, 0], state.matrix);
state.device.queue.writeBuffer(state.uniformBuffer, 0, state.uniformValues);
pass.setBindGroup(0, state.bindGroup);
pass.setVertexBuffer(0, state.vertexBuffer);
pass.setIndexBuffer(state.indexBuffer, 'uint32');
pass.drawIndexed(state.numGlyphs * 6);
pass.end();
state.device.queue.submit([encoder.finish()]);
}
// Initialize application
Main();
|