Add tiny UI

This commit is contained in:
Andras Schmelczer 2023-04-30 11:27:26 +01:00
commit 6a752a57e9
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
30 changed files with 627 additions and 210 deletions

View file

@ -1,4 +1,4 @@
import { smartCompile } from '../../smart-compile';
import { smartCompile } from '../../webgpu/smart-compile';
import shader from './full-screen-quad.wgsl';
export const setUpFullScreenQuad = (

View file

@ -1,8 +1,10 @@
import { Random } from '../../random';
import { smartCompile } from '../../smart-compile';
import { smartCompile } from '../../webgpu/smart-compile';
import { setUpFullScreenQuad } from '../full-screen-quad/full-screen-quad';
import noise from './noise.wgsl';
const textureCache = new Map<string, GPUTexture>();
export const generateNoise = ({
device,
width = 1024,
@ -19,67 +21,71 @@ export const generateNoise = ({
lacunarity?: number;
amplitude?: number;
gain?: number;
}) => {
const { buffer, vertex } = setUpFullScreenQuad(device);
const quadVertexBuffer = buffer;
}): GPUTextureView => {
const cacheKey = `${width}x${height}x${octaves}x${lacunarity}x${amplitude}x${gain}`;
if (!textureCache.has(cacheKey)) {
const { buffer, vertex } = setUpFullScreenQuad(device);
const quadVertexBuffer = buffer;
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex,
fragment: {
module: smartCompile(device, noise),
entryPoint: 'fragment',
constants: {
octaves,
lacunarity,
amplitude,
gain,
seedR: Random.getRandom(),
seedG: Random.getRandom(),
seedB: Random.getRandom(),
seedA: Random.getRandom(),
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex,
fragment: {
module: smartCompile(device, noise),
entryPoint: 'fragment',
constants: {
octaves,
lacunarity,
amplitude,
gain,
seedR: Random.getRandom(),
seedG: Random.getRandom(),
seedB: Random.getRandom(),
seedA: Random.getRandom(),
},
targets: [
{
format: 'rgba16float',
},
],
},
targets: [
primitive: {
topology: 'triangle-strip',
},
});
const colorTexture = device.createTexture({
size: {
width,
height,
depthOrArrayLayers: 1,
},
format: 'rgba16float',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
});
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
format: 'rgba16float',
view: colorTexture.createView(),
clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
},
],
},
primitive: {
topology: 'triangle-strip',
},
});
};
const colorTexture = device.createTexture({
size: {
width,
height,
depthOrArrayLayers: 1,
},
format: 'rgba16float',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
});
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: colorTexture.createView(),
clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
},
],
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setVertexBuffer(0, quadVertexBuffer);
passEncoder.draw(4, 1);
passEncoder.end();
const commandEncoder = device.createCommandEncoder();
device.queue.submit([commandEncoder.finish()]);
textureCache.set(cacheKey, colorTexture);
}
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setVertexBuffer(0, quadVertexBuffer);
passEncoder.draw(4, 1);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
return colorTexture;
return textureCache.get(cacheKey).createView();
};

View file

@ -1,8 +1,12 @@
export const handleFullScreen = (
minimizeButton: HTMLElement,
maximizeButton: HTMLElement,
target: HTMLElement
) => {
export const handleFullScreen = ({
minimizeButton,
maximizeButton,
target,
}: {
minimizeButton: HTMLElement;
maximizeButton: HTMLElement;
target: HTMLElement;
}) => {
if (!document.fullscreenEnabled) {
minimizeButton.style.visibility = 'hidden';
maximizeButton.style.visibility = 'hidden';
@ -10,39 +14,23 @@ export const handleFullScreen = (
}
const isInFullScreen = (): boolean => document.fullscreenElement !== null;
const showButtons = () => {
const updateButtons = () => {
minimizeButton.style.visibility = isInFullScreen() ? 'visible' : 'hidden';
maximizeButton.style.visibility = isInFullScreen() ? 'hidden' : 'visible';
};
showButtons();
let currentWindowHeight = innerHeight;
const followToggle = () => {
showButtons();
currentWindowHeight = innerHeight;
};
const triggerToggle = async () => {
await (isInFullScreen() ? document.exitFullscreen() : target.requestFullscreen());
followToggle();
};
updateButtons();
addEventListener('keydown', (e) => {
// on full screen request, only apply it to the target
if (e.key === 'F11') {
triggerToggle();
e.preventDefault();
isInFullScreen() ? document.exitFullscreen() : target.requestFullscreen();
}
});
addEventListener('resize', () => {
if (isInFullScreen() && currentWindowHeight > innerHeight) {
followToggle();
}
});
addEventListener('fullscreenchange', updateButtons);
maximizeButton.addEventListener('click', triggerToggle);
minimizeButton.addEventListener('click', triggerToggle);
maximizeButton.addEventListener('click', target.requestFullscreen.bind(target));
minimizeButton.addEventListener('click', document.exitFullscreen.bind(document));
};

View file

@ -0,0 +1,16 @@
export const initializeGPU = async (): Promise<GPUDevice> => {
const gpu = navigator.gpu;
if (!gpu) {
throw new Error('WebGPU is not supported');
}
const adapter = await gpu.requestAdapter({
powerPreference: 'high-performance',
});
if (!adapter) {
throw new Error('Could not request adatper');
}
return await adapter.requestDevice(); // could request more resources
};