Add tiny UI
This commit is contained in:
parent
e3d0af56e2
commit
6a752a57e9
30 changed files with 627 additions and 210 deletions
|
|
@ -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 = (
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
};
|
||||
|
|
|
|||
16
src/utils/webgpu/initialize-gpu.ts
Normal file
16
src/utils/webgpu/initialize-gpu.ts
Normal 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
|
||||
};
|
||||
Loading…
Reference in a new issue