bsnes/target-ethos/utility/utility.cpp

317 lines
9.3 KiB
C++

#include "../ethos.hpp"
Utility* utility = nullptr;
void Utility::setInterface(Emulator::Interface* emulator) {
program->active = emulator;
presentation->synchronize();
}
//load from command-line, etc
void Utility::loadMedia(string pathname) {
pathname.transform("\\", "/");
if(pathname.endsWith("/")) pathname.rtrim("/");
if(!directory::exists(pathname)) return;
string type = extension(pathname);
//determine type by comparing extension against all emulation cores
for(auto& emulator : program->emulator) {
for(auto& media : emulator->media) {
if(media.bootable == false) continue;
if(type != media.type) continue;
loadMedia(emulator, media, {pathname, "/"});
libraryManager->setVisible(false);
return;
}
}
MessageWindow().setText("Unable to determine media type.").warning();
}
//load base cartridge
void Utility::loadMedia(Emulator::Interface* emulator, Emulator::Interface::Media& media, string pathname) {
unload();
setInterface(emulator);
path(0) = program->path({media.name, ".sys/"});
path(media.id) = pathname;
this->pathname.append(pathname);
system().load(media.id);
system().power();
presentation->setSystemName(media.name);
presentation->setVisible();
load();
}
//request from emulation core to load non-volatile media folder
void Utility::loadRequest(unsigned id, string name, string type) {
string pathname = libraryManager->load(type);
if(pathname.empty()) return;
path(id) = pathname;
this->pathname.append(pathname);
system().load(id);
}
//request from emulation core to load non-volatile media file
void Utility::loadRequest(unsigned id, string path) {
string pathname = {this->path(system().group(id)), path};
if(file::exists(pathname) == false) return;
mmapstream stream(pathname);
return system().load(id, stream);
}
//request from emulation core to save non-volatile media file
void Utility::saveRequest(unsigned id, string path) {
string pathname = {this->path(system().group(id)), path};
filestream stream(pathname, file::mode::write);
return system().save(id, stream);
}
void Utility::connect(unsigned port, unsigned device) {
if(program->active == nullptr) return;
system().connect(port, device);
}
void Utility::power() {
if(program->active == nullptr) return;
system().power();
}
void Utility::reset() {
if(program->active == nullptr) return;
system().reset();
}
void Utility::load() {
presentation->setTitle(system().title());
cheatEditor->load({pathname[0], "cheats.bml"});
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
system().paletteUpdate(config->video.colorEmulation);
synchronizeDSP();
resize();
updateShader();
cheatEditor->synchronize();
cheatEditor->refresh();
}
void Utility::unload() {
if(program->active == nullptr) return;
if(tracerEnable) tracerToggle();
cheatEditor->save({pathname[0], "cheats.bml"});
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
system().unload();
path.reset();
pathname.reset();
cheatEditor->reset();
stateManager->reset();
setInterface(nullptr);
video.clear();
audio.clear();
presentation->setTitle({Emulator::Name, " v", Emulator::Version});
cheatDatabase->setVisible(false);
cheatEditor->setVisible(false);
stateManager->setVisible(false);
}
void Utility::saveState(unsigned slot) {
if(program->active == nullptr) return;
serializer s = system().serialize();
if(s.size() == 0) return;
directory::create({pathname[0], "bsnes/"});
if(file::write({pathname[0], "bsnes/state-", slot, ".bsa"}, s.data(), s.size()) == false);
showMessage({"Saved to slot ", slot});
}
void Utility::loadState(unsigned slot) {
if(program->active == nullptr) return;
auto memory = file::read({pathname[0], "bsnes/state-", slot, ".bsa"});
if(memory.size() == 0) return showMessage({"Unable to locate slot ", slot, " state"});
serializer s(memory.data(), memory.size());
if(system().unserialize(s) == false) return showMessage({"Slot ", slot, " state incompatible"});
showMessage({"Loaded from slot ", slot});
}
void Utility::tracerToggle() {
if(program->active == nullptr) return;
tracerEnable = !tracerEnable;
bool result = system().tracerEnable(tracerEnable);
if( tracerEnable && result) return utility->showMessage("Tracer activated");
if( tracerEnable && !result) return tracerEnable = false, utility->showMessage("Unable to activate tracer");
if(!tracerEnable && result) return utility->showMessage("Tracer deactivated");
if(!tracerEnable && !result) return utility->showMessage("Unable to deactivate tracer");
}
void Utility::synchronizeDSP() {
if(program->active == nullptr) return;
if(config->video.synchronize == false) {
return dspaudio.setFrequency(system().audioFrequency());
}
double inputRatio = system().audioFrequency() / system().videoFrequency();
double outputRatio = config->timing.audio / config->timing.video;
double frequency = inputRatio / outputRatio * config->audio.frequency;
dspaudio.setFrequency(frequency);
}
void Utility::synchronizeRuby() {
video.set(Video::Synchronize, config->video.synchronize);
audio.set(Audio::Synchronize, config->audio.synchronize);
audio.set(Audio::Frequency, config->audio.frequency);
audio.set(Audio::Latency, config->audio.latency);
switch(config->audio.resampler) {
case 0: dspaudio.setResampler(DSP::ResampleEngine::Linear); break;
case 1: dspaudio.setResampler(DSP::ResampleEngine::Hermite); break;
case 2: dspaudio.setResampler(DSP::ResampleEngine::Sinc); break;
}
dspaudio.setResamplerFrequency(config->audio.frequency);
dspaudio.setVolume(config->audio.mute ? 0.0 : config->audio.volume * 0.01);
synchronizeDSP();
}
void Utility::updateShader() {
if(config->video.shader == "None") {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterNearest);
} else if(config->video.shader == "Blur") {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
return;
} else if(config->video.shader == "Display Emulation") {
if(program->active) {
string pathname = program->path("Video Shaders/");
pathname.append("Display Emulation/");
pathname.append(presentation->systemName, ".shader/");
if(directory::exists(pathname)) {
video.set(Video::Shader, (const char*)pathname);
} else {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
}
} else {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
}
} else {
video.set(Video::Shader, (const char*)config->video.shader);
}
}
void Utility::resize(bool resizeWindow) {
if(program->active == nullptr) {
auto geometry = presentation->geometry();
presentation->viewport.setGeometry({0, 0, geometry.width, geometry.height});
return;
}
Geometry geometry = presentation->geometry();
unsigned width = system().information.width;
unsigned height = system().information.height;
unsigned scaledWidth = geometry.width / width;
unsigned scaledHeight = geometry.height / height;
unsigned multiplier = max(1u, min(scaledWidth, scaledHeight));
if(config->video.aspectCorrection) {
width *= system().information.aspectRatio;
}
width *= multiplier;
height *= multiplier;
unsigned scaleMode = 0;
if(config->video.scaleMode == 1) {
width = (double)width * ((double)geometry.height / height);
height = geometry.height;
}
if(config->video.scaleMode == 2) {
width = geometry.width;
height = geometry.height;
}
if(resizeWindow == false) {
if(geometry.width < width ) width = geometry.width;
if(geometry.height < height) height = geometry.height;
presentation->viewport.setGeometry({
(geometry.width - width) / 2, (geometry.height - height) / 2, width, height
});
} else {
presentation->setGeometry({geometry.x, geometry.y, width, height});
presentation->viewport.setGeometry({0, 0, width, height});
}
presentation->synchronize();
}
void Utility::toggleFullScreen() {
static Geometry geometry;
if(presentation->fullScreen() == false) {
geometry = presentation->geometry();
presentation->setMenuVisible(false);
presentation->setStatusVisible(false);
presentation->setFullScreen(true);
input.acquire();
} else {
input.unacquire();
presentation->setMenuVisible(true);
presentation->setStatusVisible(true);
presentation->setFullScreen(false);
presentation->setGeometry(geometry);
}
resize();
}
void Utility::updateStatus() {
time_t currentTime = time(0);
string text;
if((currentTime - statusTime) <= 2) {
text = statusMessage;
} else if(program->active == nullptr) {
text = "No cartridge loaded";
} else if(program->pause || program->autopause) {
text = "Paused";
} else {
text = statusText;
}
if(text != presentation->statusText()) {
presentation->setStatusText(text);
}
}
void Utility::setStatusText(string text) {
statusText = text;
}
void Utility::showMessage(string message) {
statusTime = time(0);
statusMessage = message;
}
string Utility::libraryPath() {
string path = string::read({configpath(), "higan/library.bml"}).strip().ltrim<1>("Path: ").transform("\\", "/");
if(path.empty()) path = {userpath(), "Emulation/"};
if(path.endsWith("/") == false) path.append("/");
return path;
}
Utility::Utility() {
tracerEnable = false;
statusTime = 0;
}