import { getPath } from "./common.js"; import { loadGltf } from "./index2.js"; import { loadLight } from "./light.js"; import { loadFlat } from "./flat.js"; import { loadSnake } from "./snake.js"; import { loadFont } from "./font.js"; if (!navigator.gpu) { throw new Error("WebGPU not supported on this browser."); } const adapter = await navigator.gpu.requestAdapter(); if (!adapter) { throw new Error("No WebGPU adapter"); } const device = await adapter.requestDevice(); const canvas = document.querySelector("canvas"); canvas.width = canvas.clientWidth canvas.height = canvas.clientHeight const context = canvas.getContext("webgpu"); const canvasFormat = navigator.gpu.getPreferredCanvasFormat(); context.configure({ device: device, format: canvasFormat, alphaMode: 'premultiplied', }); const encoder = device.createCommandEncoder(); const renderPass = encoder.beginRenderPass({ colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: "clear", clearValue: { r: 0.9, g: 0.5, b: 0.2, a: 1 }, storeOp: "store", }] }); renderPass.end(); const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); const memory = new WebAssembly.Memory({ initial: 258 * 2 }); const module = await WebAssembly.instantiateStreaming(fetch("src/module.wasm"), { env: { memory: memory, log: console.log, log4: console.log, logStrInt: console.log, } }); module.memory = memory; function createDepthTexture() { return device.createTexture({ size: [canvas.width, canvas.height], format: 'depth24plus', usage: GPUTextureUsage.RENDER_ATTACHMENT, sampleCount: 4, }); } var depthTexture = undefined; const eyeValueX = document.getElementById("eye-value-x"); const eyeValueY = document.getElementById("eye-value-y"); const eyeValueZ = document.getElementById("eye-value-z"); const yawValue = document.getElementById("yaw"); const pitchValue = document.getElementById("pitch"); function recreateDepth(force) { if (force === true || canvas.clientWidth !== canvas.width || canvas.clientWidth !== canvas.height) { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; if (depthTexture !== undefined) { depthTexture.destroy(); } depthTexture = createDepthTexture(); } } const matrixSize = 4 * 4 * 4; const float4Size = 4 * 4; const float3Size = 4 * 3; const viewUniformBufferSize = (matrixSize * 2) + (float4Size * 2) + (4 * 4); const viewUniformBuffer = device.createBuffer({ label: "view uniform buffer", size: viewUniformBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, }); const cameraStateSize = (float3Size * 3) + (4 * 3) + (float3Size * 1); const viewStateAddress = module.instance.exports.mem_alloc(viewUniformBufferSize); const cameraStateAddress = module.instance.exports.mem_alloc(cameraStateSize); module.instance.exports.camera_init(cameraStateAddress); //const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory, module); //const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer); //const flatRenderer = await loadFlat(device, canvasFormat, viewUniformBuffer, module); //const snakeRenderer = await loadSnake(device, canvasFormat, viewUniformBuffer, module); const fontRenderer = await loadFont(device, canvasFormat, viewUniformBuffer, module); const KEY = { A: 65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, K: 75, L: 76, M: 77, N: 78, O: 79, P: 80, Q: 81, R: 82, S: 83, T: 84, U: 85, V: 86, W: 87, X: 88, Y: 89, Z: 90, Left: 37, Up: 38, Right: 39, Down: 40, }; const keyCodes = new Set(Object.values(KEY)); const keyState = {}; for (const code of Object.values(KEY)) { keyState[code] = false; } function handleKeydown(e) { //console.log(e.keyCode); if (keyCodes.has(e.keyCode)) { keyState[e.keyCode] = true; } } function handleKeyup(e) { if (keyCodes.has(e.keyCode)) { keyState[e.keyCode] = false; } } window.addEventListener('keydown', handleKeydown, false); window.addEventListener('keyup', handleKeyup, false); function updateView() { const lu = keyState[KEY.W] === true; const ll = keyState[KEY.A] === true; const ld = keyState[KEY.S] === true; const lr = keyState[KEY.D] === true; const lal = keyState[KEY.Q] === true; const lar = keyState[KEY.E] === true; const ru = keyState[KEY.Up] === true; const rl = keyState[KEY.Left] === true; const rd = keyState[KEY.Down] === true; const rr = keyState[KEY.Right] === true; module.instance.exports.camera_move(cameraStateAddress, lu, ll, ld, lr, lal, lar, ru, rl, rd, rr); const aspect = canvas.width / canvas.height; module.instance.exports.camera_view_projection(cameraStateAddress, viewStateAddress, aspect); device.queue.writeBuffer(viewUniformBuffer, 0, memory.buffer, viewStateAddress, viewUniformBufferSize); } /* const flatSliders = { particleSize: new Slider("particle size", 0.0, 0.05), particleMass1: new Slider("particle mass1", 0.0, 0.05), particleMass2: new Slider("particle mass2", 0.0, 1.0), particleCount: new Slider("particle count", 0.0, 1024.0), circleRadius: new Slider("circle radius", 0.0, 0.5), circleThickness: new Slider("circle thickness", 0.0, 0.01), testIntensity: new Slider("test intensity", 0.0, 2.0), mass12Mix: new Slider("mass12 mix", 0.0, 1.0, 1), lineThickness: new Slider("line thickness", 0.0, 0.005), lineLength: new Slider("line length", 0.0, 9.0), targetDensity: new Slider("target density", -10.0, 10.0), pressure: new Slider("pressure", 0.0, 1.0), }; */ const mousePosition = new Float32Array([0, 0, 0, 0]); /* const snakeSliders = { boneCount: new Slider("bone count", 0.0, 100.0, 100), boneLength: new Slider("bone length", 0.0, 0.5), velocityDamping: new Slider("velocity damp.", 0.0, 1.0), velocityAcceleration: new Slider("velocity acc.", 0.0, 1.0), }; */ function onClick(e) { mousePosition[0] = e.clientX / canvas.width; mousePosition[1] = 1.0 - (e.clientY / canvas.height); } //canvas.addEventListener("click", onClick); function onMouseMove(e) { const aspect = canvas.width / canvas.height; mousePosition[0] = ((e.clientX / canvas.width) * 2 - 1) * aspect; mousePosition[1] = (1.0 - (e.clientY / canvas.height)) * 2 - 1; } canvas.addEventListener("mousemove", onMouseMove); var canRender = false; var frameNumber = 0; var multisampleTexture = undefined; function render2() { if (canRender === true) { //const configuration = updateSliders(flatSliders); //const configuration = updateSliders(snakeSliders); canRender = false; recreateDepth(false); const canvasTexture = context.getCurrentTexture(); if ((multisampleTexture === undefined) || (multisampleTexture.width !== canvasTexture.width) || (multisampleTexture.height !== canvasTexture.height)) { if ((multisampleTexture !== undefined)) { multisampleTexture.destroy(); } multisampleTexture = device.createTexture({ format: canvasTexture.format, usage: GPUTextureUsage.RENDER_ATTACHMENT, size: [canvasTexture.width, canvasTexture.height], sampleCount: 4, }); } updateView(); const encoder = device.createCommandEncoder(); const renderPass = encoder.beginRenderPass({ colorAttachments: [{ view: multisampleTexture.createView(), //view: canvasTexture.createView(), resolveTarget: canvasTexture.createView(), loadOp: "clear", clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 }, storeOp: "store", }], depthStencilAttachment: { view: depthTexture.createView(), depthClearValue: 1.0, depthLoadOp: 'clear', depthStoreOp: 'store', }, }); //gltfRenderer.render(renderPass); //lightRenderer.render(renderPass); //flatRenderer.render(device, renderPass, frameNumber, configuration); //snakeRenderer.update(device, frameNumber, mousePosition, configuration); //snakeRenderer.render(renderPass, frameNumber); fontRenderer.update(device, frameNumber); fontRenderer.render(renderPass, frameNumber); renderPass.end(); const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); frameNumber = (frameNumber + 1) % 2; } requestAnimationFrame(render2); } function setCanRender() { canRender = true; } setInterval(setCanRender, 33.33); // 15 fps recreateDepth(true); requestAnimationFrame(render2);