diff --git a/example_macplus.html b/example_macplus.html
new file mode 100644
index 00000000..896a410c
--- /dev/null
+++ b/example_macplus.html
@@ -0,0 +1,35 @@
+
+
+
+ example computer program
+
+
+
+
+
+
+
+
+
diff --git a/loader.js b/loader.js
index 069922ab..b7d99d40 100644
--- a/loader.js
+++ b/loader.js
@@ -51,19 +51,22 @@ var Module = null;
}
// yea, this is a hack
+ var images;
if (/archive\.org$/.test(document.location.hostname)) {
- var images = { ia: img("/images/ialogo.png"),
- mame: img("/images/mame.png"),
- mess: img("/images/mame.png"),
- dosbox: img("/images/dosbox.png"),
- sae: img("/images/sae.png")
- };
+ images = { ia: img("/images/ialogo.png"),
+ mame: img("/images/mame.png"),
+ mess: img("/images/mame.png"),
+ dosbox: img("/images/dosbox.png"),
+ sae: img("/images/sae.png"),
+ pce: img("/images/pce.png")
+ };
} else {
images = { ia: img("other_logos/ia-logo-150x150.png"),
mame: img("other_logos/mame.png"),
mess: img("other_logos/mame.png"),
dosbox: img("other_logos/dosbox.png"),
- sae: img("other_logos/sae.png")
+ sae: img("other_logos/sae.png"),
+ pce: img("other_logos/pce.png")
};
}
@@ -109,7 +112,7 @@ var Module = null;
})
.then(function (data) {
if (splash.failed_loading) {
- return;
+ return null;
}
filelist = data;
splash.setTitle("Downloading emulator metadata...");
@@ -130,7 +133,7 @@ var Module = null;
})
.then(function (data) {
if (splash.failed_loading) {
- return;
+ return null;
}
modulecfg = JSON.parse(data);
@@ -146,6 +149,11 @@ var Module = null;
cfgr = SAELoader;
get_files = get_sae_files;
}
+ else if (module && module.indexOf("pce-") === 0) {
+ emulator_logo = images.pce;
+ cfgr = PCELoader;
+ get_files = get_pce_files;
+ }
else if (module) {
emulator_logo = images.mame;
cfgr = MAMELoader;
@@ -164,7 +172,7 @@ var Module = null;
cfgr.sampleRate(SAMPLE_RATE)];
if (/archive\.org$/.test(document.location.hostname)) {
- cfgr.muted(!(typeof $ !== 'undefined' && $.cookie && $.cookie('unmute')))
+ cfgr.muted(!(typeof $ !== 'undefined' && $.cookie && $.cookie('unmute')));
}
if (module && module.indexOf("dosbox") === 0) {
@@ -174,7 +182,9 @@ var Module = null;
} else if (module && module.indexOf("sae-") === 0) {
config_args.push(cfgr.model(modulecfg.driver),
cfgr.rom(modulecfg.bios_filenames));
- } else if (module) {
+ } else if (module && module.indexOf("pce-") === 0) {
+ config_args.push(cfgr.model(modulecfg.driver));
+ } else if (module) { // MAME
config_args.push(cfgr.driver(modulecfg.driver),
cfgr.extraArgs(modulecfg.extra_args));
}
@@ -232,7 +242,9 @@ var Module = null;
var node = urls[i],
drive = node.nodeName.split('_')[2],
title = 'Game File ('+ (i+1) +' of '+ (game ? len+1 : len) +')',
- url = get_zip_url(node.textContent);
+ filename = node.textContent,
+ url = (filename.includes("/")) ? get_zip_url(filename)
+ : get_zip_url(filename, get_item_name(game));
files.push(cfgr.mountZip(drive, cfgr.fetchFile(title, url)));
}
@@ -285,16 +297,16 @@ var Module = null;
var periph = k.match(/^mame_peripheral_([a-zA-Z0-9]+)$/)[1];
peripherals[periph] = meta[k];
game_files_counter[meta[k]] = 1;
- })
+ });
var game_files = Object.keys(game_files_counter),
len = game_files.length;
game_files.forEach(function (filename, i) {
- var title = "Game File ("+ (i+1) +" of "+ len +")";
+ var title = "Game File ("+ (i+1) +" of "+ len +")",
+ url = (filename.includes("/")) ? get_zip_url(filename)
+ : get_zip_url(filename, get_item_name(game));
files.push(cfgr.mountFile('/'+ filename,
- cfgr.fetchFile(title,
- get_zip_url(filename,
- get_item_name(game)))));
+ cfgr.fetchFile(title, url)));
});
Object.keys(peripherals).forEach(function (periph) {
files.push(cfgr.peripheral(periph, // we're not pushing a 'file' here,
@@ -333,21 +345,75 @@ var Module = null;
});
game_files.forEach(function (file, i) {
if (file) {
- var title = "Game File ("+ (i+1) +" of "+ game_files.length +")";
+ var title = "Game File ("+ (i+1) +" of "+ game_files.length +")",
+ url = (file.name.includes("/")) ? get_zip_url(file.name)
+ : get_zip_url(file.name, get_item_name(game));
files.push(cfgr.mountFile('/'+ file.name,
- cfgr.fetchFile(title,
- get_zip_url(file.name,
- get_item_name(game)))));
+ cfgr.fetchFile(title, url)));
files.push(cfgr.floppy(0, // we're not pushing a file here
file.name)); // but that's ok
}
});
files.push(cfgr.mountFile('/'+ modulecfg['driver'] + '.cfg',
- cfgr.fetchOptionalFile("CFG File",
+ cfgr.fetchOptionalFile("Config File",
get_other_emulator_config_url(module))));
return files;
}
+ function get_pce_files(cfgr, metadata, modulecfg, filelist) {
+ var files = [],
+ bios_files = modulecfg['bios_filenames'];
+ bios_files.forEach(function (fname, i) {
+ if (fname) {
+ var title = "ROM File ("+ (i+1) +" of "+ bios_files.length +")";
+ files.push(cfgr.mountFile('/'+ fname,
+ cfgr.fetchFile(title,
+ get_bios_url(fname))));
+ }
+ });
+
+ var meta = dict_from_xml(metadata),
+ game_files_counter = {};
+ list_from_xml(filelist).filter(function (node) {
+ return "getAttribute" in node;
+ })
+ .map(function (node) {
+ var file = dict_from_xml(node);
+ file.name = node.getAttribute("name");
+ return file;
+ })
+ .filter(function (file) {
+ return file.name.endsWith("." + meta.emulator_ext);
+ })
+ .forEach(function (file, i) {
+ if (modulecfg.peripherals && modulecfg.peripherals[i]) {
+ game_files_counter[file.name] = modulecfg.peripherals[i];
+ }
+ });
+ Object.keys(meta).filter(function (k) {
+ return k.startsWith("pce_drive_");
+ })
+ .forEach(function (k) {
+ var periph = k.match(/^pce_drive_([a-zA-Z0-9]+)$/)[1];
+ game_files_counter[meta[k]] = periph;
+ });
+
+ var game_files = Object.keys(game_files_counter),
+ len = game_files.length;
+ game_files.forEach(function (filename, i) {
+ var title = "Game File ("+ (i+1) +" of "+ len +")",
+ ext = filename.match(/\.([^.]*)$/)[1],
+ url = (filename.includes("/")) ? get_zip_url(filename)
+ : get_zip_url(filename, get_item_name(game));
+ files.push(cfgr.mountFile('/'+ game_files_counter[filename] +'.'+ ext,
+ cfgr.fetchFile(title, url)));
+ });
+
+ files.push(cfgr.mountFile('/pce-'+ modulecfg['driver'] + '.cfg',
+ cfgr.fetchOptionalFile("Config File",
+ get_other_emulator_config_url("pce-"+ modulecfg['driver']))));
+ return files;
+ }
var get_item_name = function (game_path) {
return game_path.split('/').shift();
};
@@ -503,7 +569,7 @@ var Module = null;
};
MAMELoader.peripheral = function (peripheral, game) {
- var p = {}
+ var p = {};
p[peripheral] = [game];
return { peripheral: p };
};
@@ -525,11 +591,11 @@ var Module = null;
SAELoader.model = function (model) {
return { amigaModel: model };
- }
+ };
SAELoader.fastMemory = function (megabytes) {
return { fast_memory: megabytes << 20 };
- }
+ };
SAELoader.rom = function (filenames) {
if (typeof filenames == "string")
@@ -538,14 +604,29 @@ var Module = null;
};
SAELoader.floppy = function (index, filename) {
- var f = {}
+ var f = {};
f[index] = filename;
return { floppy: f };
};
SAELoader.ntsc = function (v) {
return { ntsc: !!v };
+ };
+
+ /**
+ * PCELoader
+ */
+
+ function PCELoader() {
+ var config = Array.prototype.reduce.call(arguments, extend);
+ config.emulator_arguments = ["-c", "/emulator/pce-"+ config.pceModel +".cfg"];
+ return config;
}
+ PCELoader.__proto__ = BaseLoader;
+
+ PCELoader.model = function (model) {
+ return { pceModel: model };
+ };
var build_mame_arguments = function (muted, driver, native_resolution, sample_rate, peripheral, extra_args) {
var args = [driver,
@@ -568,7 +649,7 @@ var Module = null;
for (var p in peripheral) {
if (Object.prototype.propertyIsEnumerable.call(peripheral, p)) {
args.push('-' + p,
- '/emulator/'+ (peripheral[p][0].replace(/\//g,'_')))
+ '/emulator/'+ (peripheral[p][0].replace(/\//g,'_')));
}
}
}
@@ -664,29 +745,29 @@ var Module = null;
SAERunner.prototype.start = function () {
var err = this._sae.start();
- }
+ };
SAERunner.prototype.pause = function () {
this._sae.pause();
- }
+ };
SAERunner.prototype.stop = function () {
this._sae.stop();
- }
+ };
SAERunner.prototype.mute = function () {
var err = this._sae.mute(true);
if (err) {
- console.warn("unable to mute; SAE error number", err)
+ console.warn("unable to mute; SAE error number", err);
}
- }
+ };
SAERunner.prototype.unmute = function () {
var err = this._sae.mute(false);
if (err) {
- console.warn("unable to unmute; SAE error number", err)
+ console.warn("unable to unmute; SAE error number", err);
}
- }
+ };
SAERunner.prototype.onStarted = function (func) {
this._cfg.hook.event.started = func;
@@ -728,10 +809,10 @@ var Module = null;
var muted = false;
var SDL_PauseAudio;
- this.isMuted = function () { return muted; }
- this.mute = function () { return this.setMute(true); }
- this.unmute = function () { return this.setMute(false); }
- this.toggleMute = function () { return this.setMute(!muted); }
+ this.isMuted = function () { return muted; };
+ this.mute = function () { return this.setMute(true); };
+ this.unmute = function () { return this.setMute(false); };
+ this.toggleMute = function () { return this.setMute(!muted); };
this.setMute = function (state) {
muted = state;
if (runner) {
@@ -1462,13 +1543,40 @@ var Module = null;
return Array.prototype.slice.call(xml.childNodes);
}
+ function _SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, rmask, gmask, bmask, amask) {
+ // TODO: Actually fill pixel data to created surface.
+ // TODO: Take into account depth and pitch parameters.
+ // console.log('TODO: Partially unimplemented SDL_CreateRGBSurfaceFrom called!');
+ var surface = SDL.makeSurface(width, height, 0, false, 'CreateRGBSurfaceFrom', rmask, gmask, bmask, amask);
+
+ var surfaceData = SDL.surfaces[surface];
+ var surfaceImageData = surfaceData.ctx.getImageData(0, 0, width, height);
+ var surfacePixelData = surfaceImageData.data;
+
+ // Fill pixel data to created surface.
+ // Supports SDL_PIXELFORMAT_RGBA8888 and SDL_PIXELFORMAT_RGB888
+ var channels = amask ? 4 : 3; // RGBA8888 or RGB888
+ for (var pixelOffset = 0; pixelOffset < width*height; pixelOffset++) {
+ surfacePixelData[pixelOffset*4+0] = HEAPU8[pixels + (pixelOffset*channels+0)]; // R
+ surfacePixelData[pixelOffset*4+1] = HEAPU8[pixels + (pixelOffset*channels+1)]; // G
+ surfacePixelData[pixelOffset*4+2] = HEAPU8[pixels + (pixelOffset*channels+2)]; // B
+ surfacePixelData[pixelOffset*4+3] = amask ? HEAPU8[pixels + (pixelOffset*channels+3)] : 0xff; // A
+ };
+
+ surfaceData.ctx.putImageData(surfaceImageData, 0, 0);
+
+ return surface;
+ }
+
window.IALoader = IALoader;
window.DosBoxLoader = DosBoxLoader;
window.JSMESSLoader = MAMELoader; // depreciated; just for backwards compatibility
window.JSMAMELoader = MAMELoader; // ditto
window.MAMELoader = MAMELoader;
window.SAELoader = SAELoader;
+ window.PCELoader = PCELoader;
window.Emulator = Emulator;
+ window._SDL_CreateRGBSurfaceFrom = _SDL_CreateRGBSurfaceFrom;
})(typeof Promise === 'undefined' ? ES6Promise.Promise : Promise);
// legacy
diff --git a/other_logos/pce.png b/other_logos/pce.png
new file mode 100644
index 00000000..d51b7e19
Binary files /dev/null and b/other_logos/pce.png differ