Spaces:
Running
Running
// index.js | |
import { mat4 } from 'https://webgpufundamentals.org/3rdparty/wgpu-matrix.module.js'; | |
import { initializeWebGPU } from './wgpu-device.js'; | |
import { createState } from './wgpu-state.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'; | |
import { config } from './wgpu-config.js'; | |
import { CANVAS, CTX, COLORS, RENDER_PASS_DESCRIPTOR } from './wgpu-constants.js'; | |
import { CreateBuffers } from './wgpu-buffer.js'; | |
const state = createState(config); | |
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; | |
initializeTiming(state); | |
await InitializeShaders(state); | |
await InitializeResources(state); | |
GameLoop(state); | |
} | |
async function InitializeResources(state) { | |
const vertexSize = config.floatsPerVertex * 4; | |
state.webgpu.pipeline = await createPipeline(state.webgpu.device, state.webgpu.presentationFormat, 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 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); | |
} | |
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()]); | |
} | |
Main(); | |