mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-06-03 21:41:38 +00:00
experimental mp3/zlib support
This commit is contained in:
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -7,9 +7,6 @@ import axios from 'axios';
|
||||
const DiabloSize = 1316452;
|
||||
const SpawnSize = 1196648;
|
||||
|
||||
const SpawnMpqSize = 50274091;
|
||||
const RetailMpqSize = 517501282;
|
||||
|
||||
/* eslint-disable-next-line no-restricted-globals */
|
||||
const worker = self;
|
||||
|
||||
@@ -22,12 +19,19 @@ let is_spawn = false;
|
||||
|
||||
const ChunkSize = 1 << 20;
|
||||
class RemoteFile {
|
||||
constructor(url, size) {
|
||||
this.url = url;
|
||||
this.byteLength = size;
|
||||
constructor(url) {
|
||||
const request = new XMLHttpRequest();
|
||||
request.open('HEAD', url, false);
|
||||
request.send();
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
worker.postMessage({action: "error", error: `Failed to load remote file`});
|
||||
}
|
||||
this.byteLength = parseInt(request.getResponseHeader('Content-Length'));
|
||||
|
||||
this.buffer = new Uint8Array(size);
|
||||
this.chunks = new Uint8Array(((size + ChunkSize - 1) >> 20) | 0);
|
||||
this.url = url;
|
||||
|
||||
this.buffer = new Uint8Array(this.byteLength);
|
||||
this.chunks = new Uint8Array(((this.byteLength + ChunkSize - 1) >> 20) | 0);
|
||||
}
|
||||
|
||||
subarray(start, end) {
|
||||
@@ -46,7 +50,7 @@ class RemoteFile {
|
||||
request.setRequestHeader('Range', `bytes=${missing0 * ChunkSize}-${Math.min(missing1 * ChunkSize + ChunkSize - 1, this.byteLength - 1)}`);
|
||||
request.responseType = 'arraybuffer';
|
||||
request.send();
|
||||
if (request.status < 200 || request.status > 206) {
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
worker.postMessage({action: "error", error: `Failed to load remote file`});
|
||||
} else {
|
||||
const header = request.getResponseHeader('Content-Range');
|
||||
@@ -196,18 +200,18 @@ const DApi_renderOffscreen = {
|
||||
|
||||
let audioBatch = null, audioTransfer = null;
|
||||
let maxSoundId = 0, maxBatchId = 0;
|
||||
["create_sound", "duplicate_sound"].forEach(func => {
|
||||
["create_sound_raw", "create_sound", "duplicate_sound"].forEach(func => {
|
||||
DApi[func] = function(...params) {
|
||||
if (audioBatch) {
|
||||
maxBatchId = params[0] + 1;
|
||||
audioBatch.push({func, params});
|
||||
if (func === "create_sound") {
|
||||
if (func !== "duplicate_sound") {
|
||||
audioTransfer.push(params[1].buffer);
|
||||
}
|
||||
} else {
|
||||
maxSoundId = params[0] + 1;
|
||||
const transfer = [];
|
||||
if (func === "create_sound") {
|
||||
if (func !== "duplicate_sound") {
|
||||
transfer.push(params[1].buffer);
|
||||
}
|
||||
worker.postMessage({action: "audio", func, params}, transfer);
|
||||
@@ -293,7 +297,7 @@ async function init_game(mpq, spawn, offscreen) {
|
||||
const name = (spawn ? 'spawn.mpq' : 'diabdat.mpq');
|
||||
if (!files.has(name)) {
|
||||
// This should never happen, but we do support remote loading
|
||||
files.set(name, new RemoteFile(`${process.env.PUBLIC_URL}/${name}`, spawn ? SpawnMpqSize : RetailMpqSize));
|
||||
files.set(name, new RemoteFile(`${process.env.PUBLIC_URL}/${name}`));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ function onRender(api, ctx, {bitmap, images, text, clip, belt}) {
|
||||
|
||||
function testOffscreen() {
|
||||
return false;
|
||||
// This works but I couldn't see any performance difference, and support for 2D canvas in workers is very poor.
|
||||
// In this mode, instead of sending a batch of areas to draw back to the main thread, the worker does all drawing on its own and sends a complete bitmap object back.
|
||||
// However, this effectively clears the worker's canvas, so we need to redraw the whole frame every time, which defeats the performance gained from reduced copying.
|
||||
/*try {
|
||||
const canvas = document.createElement("canvas");
|
||||
const offscreen = canvas.transferControlToOffscreen();
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function init_sound() {
|
||||
const sounds = new Map();
|
||||
|
||||
return {
|
||||
create_sound(id, data, length, channels, rate) {
|
||||
create_sound_raw(id, data, length, channels, rate) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
@@ -31,6 +31,17 @@ export default function init_sound() {
|
||||
for (let i = 0; i < channels; ++i) {
|
||||
buffer.copyToChannel(data.subarray(i * length, i * length + length), i);
|
||||
}
|
||||
sounds.set(id, {
|
||||
buffer: Promise.resolve(buffer),
|
||||
gain: context.createGain(),
|
||||
panner: new StereoPannerNode(context, {pan: 0}),
|
||||
});
|
||||
},
|
||||
create_sound(id, data) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
const buffer = context.decodeAudioData(data.buffer);
|
||||
sounds.set(id, {
|
||||
buffer,
|
||||
gain: context.createGain(),
|
||||
@@ -55,16 +66,19 @@ export default function init_sound() {
|
||||
const src = sounds.get(id);
|
||||
if (src) {
|
||||
if (src.source) {
|
||||
src.source.stop();
|
||||
src.source.then(source => source.stop());
|
||||
}
|
||||
src.gain.gain.value = Math.pow(2.0, volume / 1000.0);
|
||||
const relVolume = Math.pow(2.0, pan / 1000.0);
|
||||
src.panner.pan.value = 1.0 - 2.0 / (1.0 + relVolume);
|
||||
src.source = context.createBufferSource();
|
||||
src.source.buffer = src.buffer;
|
||||
src.source.loop = !!loop;
|
||||
src.source.connect(src.gain).connect(src.panner).connect(context.destination);
|
||||
src.source.start();
|
||||
src.source = src.buffer.then(buffer => {
|
||||
const source = context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = !!loop;
|
||||
source.connect(src.gain).connect(src.panner).connect(context.destination);
|
||||
source.start();
|
||||
return source;
|
||||
});
|
||||
}
|
||||
},
|
||||
set_volume(id, volume) {
|
||||
@@ -76,14 +90,14 @@ export default function init_sound() {
|
||||
stop_sound(id) {
|
||||
const src = sounds.get(id);
|
||||
if (src && src.source) {
|
||||
src.source.stop();
|
||||
src.source.then(source => source.stop());
|
||||
delete src.source;
|
||||
}
|
||||
},
|
||||
delete_sound(id) {
|
||||
const src = sounds.get(id);
|
||||
if (src && src.source) {
|
||||
src.source.stop();
|
||||
src.source.then(source => source.stop());
|
||||
}
|
||||
sounds.delete(id);
|
||||
},
|
||||
@@ -91,7 +105,7 @@ export default function init_sound() {
|
||||
stop_all() {
|
||||
for (let [, sound] of sounds) {
|
||||
if (sound.source) {
|
||||
sound.source.stop();
|
||||
sound.source.then(source => source.stop());
|
||||
}
|
||||
}
|
||||
sounds.clear();
|
||||
|
||||
Reference in New Issue
Block a user