WIP
This commit is contained in:
parent
34ac200437
commit
39b0160064
136 changed files with 7129 additions and 1950 deletions
|
|
@ -1,15 +1,19 @@
|
|||
import { appConfig } from '../config';
|
||||
import { clamp } from './clamp';
|
||||
import { exponentialDecay } from './exponential-decay';
|
||||
|
||||
export class DeltaTimeCalculator {
|
||||
private static FPS_EXPONENTIAL_DECAY_STRENGTH = 0.01;
|
||||
private static FPS_EXPONENTIAL_DECAY_STRENGTH =
|
||||
appConfig.deltaTime.fpsExponentialDecayStrength;
|
||||
|
||||
private previousTime: DOMHighResTimeStamp | null = null;
|
||||
private deltaTimeAccumulator: number | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly maxDeltaTimeInSeconds: number = 1 / 30,
|
||||
private readonly minDeltaTimeInSeconds: number = 1 / 240
|
||||
private readonly maxDeltaTimeInSeconds: number =
|
||||
appConfig.deltaTime.maxDeltaTimeSeconds,
|
||||
private readonly minDeltaTimeInSeconds: number =
|
||||
appConfig.deltaTime.minDeltaTimeSeconds
|
||||
) {
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
||||
}
|
||||
|
|
|
|||
58
src/utils/graphics/cached-buffer-write.test.ts
Normal file
58
src/utils/graphics/cached-buffer-write.test.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
createCachedFloat32BufferWrite,
|
||||
writeFloat32BufferIfChanged,
|
||||
} from './cached-buffer-write';
|
||||
|
||||
const createGpuWriteStub = () => {
|
||||
const writeBuffer = vi.fn();
|
||||
const device = {
|
||||
queue: {
|
||||
writeBuffer,
|
||||
},
|
||||
} as unknown as GPUDevice;
|
||||
|
||||
return { device, writeBuffer };
|
||||
};
|
||||
|
||||
describe('cached float32 buffer writes', () => {
|
||||
it('writes the first value set and skips unchanged values', () => {
|
||||
const { device, writeBuffer } = createGpuWriteStub();
|
||||
const buffer = {} as GPUBuffer;
|
||||
const cache = createCachedFloat32BufferWrite(3);
|
||||
const values = new Float32Array([1, 2, 3]);
|
||||
|
||||
expect(writeFloat32BufferIfChanged(device, buffer, values, cache)).toBe(true);
|
||||
expect(writeBuffer).toHaveBeenCalledTimes(1);
|
||||
expect(writeBuffer).toHaveBeenLastCalledWith(buffer, 0, values);
|
||||
|
||||
expect(writeFloat32BufferIfChanged(device, buffer, values, cache)).toBe(false);
|
||||
expect(writeBuffer).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('writes again when any float changes', () => {
|
||||
const { device, writeBuffer } = createGpuWriteStub();
|
||||
const buffer = {} as GPUBuffer;
|
||||
const cache = createCachedFloat32BufferWrite(3);
|
||||
|
||||
expect(
|
||||
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1, 2, 3]), cache)
|
||||
).toBe(true);
|
||||
expect(
|
||||
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1, 2, 4]), cache)
|
||||
).toBe(true);
|
||||
expect(writeBuffer).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('rejects cache length mismatches before writing', () => {
|
||||
const { device, writeBuffer } = createGpuWriteStub();
|
||||
const buffer = {} as GPUBuffer;
|
||||
const cache = createCachedFloat32BufferWrite(2);
|
||||
|
||||
expect(() =>
|
||||
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1]), cache)
|
||||
).toThrow('Cached buffer write length mismatch');
|
||||
expect(writeBuffer).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
36
src/utils/graphics/cached-buffer-write.ts
Normal file
36
src/utils/graphics/cached-buffer-write.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
export interface CachedFloat32BufferWrite {
|
||||
hasValue: boolean;
|
||||
previous: Float32Array;
|
||||
}
|
||||
|
||||
export const createCachedFloat32BufferWrite = (
|
||||
length: number
|
||||
): CachedFloat32BufferWrite => ({
|
||||
hasValue: false,
|
||||
previous: new Float32Array(length),
|
||||
});
|
||||
|
||||
export const writeFloat32BufferIfChanged = (
|
||||
device: GPUDevice,
|
||||
buffer: GPUBuffer,
|
||||
values: Float32Array,
|
||||
cache: CachedFloat32BufferWrite
|
||||
): boolean => {
|
||||
if (values.length !== cache.previous.length) {
|
||||
throw new Error('Cached buffer write length mismatch');
|
||||
}
|
||||
|
||||
let hasChanged = !cache.hasValue;
|
||||
for (let i = 0; i < values.length && !hasChanged; i++) {
|
||||
hasChanged = !Object.is(values[i], cache.previous[i]);
|
||||
}
|
||||
|
||||
if (!hasChanged) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cache.previous.set(values);
|
||||
cache.hasValue = true;
|
||||
device.queue.writeBuffer(buffer, 0, values);
|
||||
return true;
|
||||
};
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
export const persist = <T extends Record<string, number>>(wrapee: T): T => {
|
||||
const keys = Object.keys(wrapee);
|
||||
keys.sort();
|
||||
|
||||
const keysToShortKeys = Object.fromEntries(keys.map((key) => [key, key]));
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const newParams = new URLSearchParams();
|
||||
keys.forEach((key) => {
|
||||
if (params.has(keysToShortKeys[key])) {
|
||||
(wrapee as any)[key] = Number(params.get(keysToShortKeys[key]));
|
||||
newParams.set(keysToShortKeys[key], params.get(keysToShortKeys[key])!);
|
||||
}
|
||||
});
|
||||
|
||||
window.history.replaceState(
|
||||
{},
|
||||
'',
|
||||
`${window.location.pathname}?${newParams.toString()}`
|
||||
);
|
||||
|
||||
return new Proxy(wrapee, {
|
||||
set: (target, key: string, value: number) => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
params.set(keysToShortKeys[key], value.toString());
|
||||
|
||||
(target as any)[key] = value;
|
||||
|
||||
window.history.replaceState(
|
||||
{},
|
||||
'',
|
||||
`${window.location.pathname}?${params.toString()}`
|
||||
);
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
};
|
||||
Loading…
Reference in a new issue