mirror of https://github.com/bsnes-emu/bsnes.git
Update to 20180730 release.
byuu says: These WIPs-within-WIPs are getting more and more broken ... this isn't going the way I wanted. But ... this time around, I've revamped the entire ruby API again, to solve a bunch of tough problems that have always made using ruby really clunky. But there are *so many* ruby drivers that it's going to take a long time to work through them all. This WIP is only going to run bsnes, and only on FreeBSD, and only with some drivers. hiro's Application::initialize() now calls hiro::initialize(), which you define inside of your hiro apps. This lets you call Application::setName(...) before anything else in hiro runs. This is essential on Xorg to set program icons, for instance. With the ruby rewrite and the change to hiro, I can get away from the need to make everything in bsnes/higan pointers to objects, and can now just declare them as regular objects.
This commit is contained in:
parent
5deba5cbc1
commit
212da0a966
|
@ -615,9 +615,12 @@ auto OscillatorWindow::updateWindow() -> void {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <nall/main.hpp>
|
auto hiro::initialize() -> void {
|
||||||
auto nall::main(string_vector args) -> void {
|
|
||||||
Application::setName("genius");
|
Application::setName("genius");
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <nall/main.hpp>
|
||||||
|
auto nall::main(vector<string> arguments) -> void {
|
||||||
new ListWindow;
|
new ListWindow;
|
||||||
new GameWindow;
|
new GameWindow;
|
||||||
new MemoryWindow;
|
new MemoryWindow;
|
||||||
|
@ -625,12 +628,12 @@ auto nall::main(string_vector args) -> void {
|
||||||
|
|
||||||
//internal command used to synchronize all genius databases from an old format to a new format
|
//internal command used to synchronize all genius databases from an old format to a new format
|
||||||
//if enabled, use with extreme caution and make backups first
|
//if enabled, use with extreme caution and make backups first
|
||||||
/*if(args.size() == 3 && args[1] == "--sync") {
|
/*if(arguments.size() == 3 && arguments[1] == "--sync") {
|
||||||
for(auto& filename : directory::contents(args[2], "*.bml")) {
|
for(auto& filename : directory::contents(arguments[2], "*.bml")) {
|
||||||
if(filename.beginsWith("Boards")) continue;
|
if(filename.beginsWith("Boards")) continue;
|
||||||
print(filename, "\n");
|
print(filename, "\n");
|
||||||
listWindow->loadDatabase({args[2], filename});
|
listWindow->loadDatabase({arguments[2], filename});
|
||||||
listWindow->saveDatabase({args[2], filename});
|
listWindow->saveDatabase({arguments[2], filename});
|
||||||
}
|
}
|
||||||
return print("[Done]\n");
|
return print("[Done]\n");
|
||||||
}*/
|
}*/
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "bsnes.hpp"
|
#include "bsnes.hpp"
|
||||||
#include <sfc/interface/interface.hpp>
|
#include <sfc/interface/interface.hpp>
|
||||||
unique_pointer<Video> video;
|
Video video;
|
||||||
unique_pointer<Audio> audio;
|
Audio audio;
|
||||||
unique_pointer<Input> input;
|
Input input;
|
||||||
unique_pointer<Emulator::Interface> emulator;
|
unique_pointer<Emulator::Interface> emulator;
|
||||||
|
|
||||||
auto locate(string name) -> string {
|
auto locate(string name) -> string {
|
||||||
|
@ -18,6 +18,10 @@ auto locate(string name) -> string {
|
||||||
return {Path::userData(), "bsnes/", name};
|
return {Path::userData(), "bsnes/", name};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto hiro::initialize() -> void {
|
||||||
|
Application::setName("bsnes");
|
||||||
|
}
|
||||||
|
|
||||||
#include <nall/main.hpp>
|
#include <nall/main.hpp>
|
||||||
auto nall::main(vector<string> arguments) -> void {
|
auto nall::main(vector<string> arguments) -> void {
|
||||||
string locale; // = "日本語";
|
string locale; // = "日本語";
|
||||||
|
@ -26,7 +30,6 @@ auto nall::main(vector<string> arguments) -> void {
|
||||||
locale = argument.trimLeft("--locale=", 1L);
|
locale = argument.trimLeft("--locale=", 1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Application::setName("bsnes");
|
|
||||||
Application::setScreenSaver(!settings["UserInterface/SuppressScreenSaver"].boolean());
|
Application::setScreenSaver(!settings["UserInterface/SuppressScreenSaver"].boolean());
|
||||||
Application::locale().scan(locate("locales/"));
|
Application::locale().scan(locate("locales/"));
|
||||||
Application::locale().select(locale);
|
Application::locale().select(locale);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
using namespace nall;
|
using namespace nall;
|
||||||
using namespace ruby;
|
using namespace ruby;
|
||||||
using namespace hiro;
|
using namespace hiro;
|
||||||
extern unique_pointer<Video> video;
|
extern Video video;
|
||||||
extern unique_pointer<Audio> audio;
|
extern Audio audio;
|
||||||
extern unique_pointer<Input> input;
|
extern Input input;
|
||||||
|
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
extern unique_pointer<Emulator::Interface> emulator;
|
extern unique_pointer<Emulator::Interface> emulator;
|
||||||
|
|
|
@ -6,7 +6,7 @@ auto InputManager::bindHotkeys() -> void {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] {
|
hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] {
|
||||||
input->acquired() ? input->release() : input->acquire();
|
input.acquired() ? input.release() : input.acquire();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
hotkeys.append(InputHotkey("Toggle Cheat Codes").onPress([] {
|
hotkeys.append(InputHotkey("Toggle Cheat Codes").onPress([] {
|
||||||
|
@ -47,11 +47,11 @@ auto InputManager::bindHotkeys() -> void {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
hotkeys.append(InputHotkey("Fast Forward").onPress([] {
|
hotkeys.append(InputHotkey("Fast Forward").onPress([] {
|
||||||
video->setBlocking(false);
|
video.setBlocking(false);
|
||||||
audio->setBlocking(false);
|
audio.setBlocking(false);
|
||||||
}).onRelease([] {
|
}).onRelease([] {
|
||||||
video->setBlocking(settings["Video/Blocking"].boolean());
|
video.setBlocking(settings["Video/Blocking"].boolean());
|
||||||
audio->setBlocking(settings["Audio/Blocking"].boolean());
|
audio.setBlocking(settings["Audio/Blocking"].boolean());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
|
hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
|
||||||
|
|
|
@ -150,7 +150,7 @@ auto InputMapping::poll() -> int16 {
|
||||||
|
|
||||||
auto InputMapping::rumble(bool enable) -> void {
|
auto InputMapping::rumble(bool enable) -> void {
|
||||||
for(auto& mapping : mappings) {
|
for(auto& mapping : mappings) {
|
||||||
::input->rumble(mapping.device->id(), enable);
|
input.rumble(mapping.device->id(), enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ auto InputManager::initialize() -> void {
|
||||||
hotkeys.reset();
|
hotkeys.reset();
|
||||||
|
|
||||||
if(!input) return;
|
if(!input) return;
|
||||||
input->onChange({&InputManager::onChange, this});
|
input.onChange({&InputManager::onChange, this});
|
||||||
|
|
||||||
lastPoll = chrono::millisecond();
|
lastPoll = chrono::millisecond();
|
||||||
frequency = max(1u, settings["Input/Frequency"].natural());
|
frequency = max(1u, settings["Input/Frequency"].natural());
|
||||||
|
@ -264,7 +264,7 @@ auto InputManager::poll() -> void {
|
||||||
if(thisPoll - lastPoll < frequency) return;
|
if(thisPoll - lastPoll < frequency) return;
|
||||||
lastPoll = thisPoll;
|
lastPoll = thisPoll;
|
||||||
|
|
||||||
auto devices = input->poll();
|
auto devices = input.poll();
|
||||||
bool changed = devices.size() != this->devices.size();
|
bool changed = devices.size() != this->devices.size();
|
||||||
if(!changed) {
|
if(!changed) {
|
||||||
for(auto n : range(devices.size())) {
|
for(auto n : range(devices.size())) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
AboutWindow::AboutWindow() {
|
auto AboutWindow::create() -> void {
|
||||||
aboutWindow = this;
|
|
||||||
|
|
||||||
setTitle({tr("About {0}", "bsnes"), " ..."});
|
setTitle({tr("About {0}", "bsnes"), " ..."});
|
||||||
setBackgroundColor({255, 255, 240});
|
setBackgroundColor({255, 255, 240});
|
||||||
layout.setPadding(10);
|
layout.setPadding(10);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "../bsnes.hpp"
|
#include "../bsnes.hpp"
|
||||||
#include "about.cpp"
|
#include "about.cpp"
|
||||||
unique_pointer<AboutWindow> aboutWindow;
|
AboutWindow aboutWindow;
|
||||||
unique_pointer<Presentation> presentation;
|
unique_pointer<Presentation> presentation;
|
||||||
|
|
||||||
Presentation::Presentation() {
|
Presentation::Presentation() {
|
||||||
|
@ -122,7 +122,7 @@ Presentation::Presentation() {
|
||||||
speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program->updateAudioFrequency(); });
|
speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program->updateAudioFrequency(); });
|
||||||
speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program->updateAudioFrequency(); });
|
speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program->updateAudioFrequency(); });
|
||||||
pauseEmulation.setText("Pause Emulation").onToggle([&] {
|
pauseEmulation.setText("Pause Emulation").onToggle([&] {
|
||||||
if(pauseEmulation.checked()) audio->clear();
|
if(pauseEmulation.checked()) audio.clear();
|
||||||
});
|
});
|
||||||
frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] {
|
frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] {
|
||||||
pauseEmulation.setChecked(false);
|
pauseEmulation.setChecked(false);
|
||||||
|
@ -140,7 +140,7 @@ Presentation::Presentation() {
|
||||||
invoke("https://doc.byuu.org/bsnes/");
|
invoke("https://doc.byuu.org/bsnes/");
|
||||||
});
|
});
|
||||||
about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] {
|
about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] {
|
||||||
aboutWindow->setCentered(*this).setVisible().setFocused();
|
aboutWindow.setCentered(*this).setVisible().setFocused();
|
||||||
});
|
});
|
||||||
|
|
||||||
viewport.setDroppable().onDrop([&](vector<string> locations) {
|
viewport.setDroppable().onDrop([&](vector<string> locations) {
|
||||||
|
@ -241,14 +241,14 @@ auto Presentation::clearViewport() -> void {
|
||||||
uint length;
|
uint length;
|
||||||
uint width = 16;
|
uint width = 16;
|
||||||
uint height = 16;
|
uint height = 16;
|
||||||
if(video->acquire(output, length, width, height)) {
|
if(video.acquire(output, length, width, height)) {
|
||||||
for(uint y : range(height)) {
|
for(uint y : range(height)) {
|
||||||
auto line = output + y * (length >> 2);
|
auto line = output + y * (length >> 2);
|
||||||
for(uint x : range(width)) *line++ = 0xff000000;
|
for(uint x : range(width)) *line++ = 0xff000000;
|
||||||
}
|
}
|
||||||
if(!emulator->loaded()) drawIcon(output, length, width, height);
|
if(!emulator->loaded()) drawIcon(output, length, width, height);
|
||||||
video->release();
|
video.release();
|
||||||
video->output();
|
video.output();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,14 +326,14 @@ auto Presentation::toggleFullscreenMode() -> void {
|
||||||
}
|
}
|
||||||
menuBar.setVisible(false);
|
menuBar.setVisible(false);
|
||||||
setFullScreen(true);
|
setFullScreen(true);
|
||||||
video->setExclusive(settings["Video/Exclusive"].boolean());
|
video.setExclusive(settings["Video/Exclusive"].boolean());
|
||||||
if(video->exclusive()) setVisible(false);
|
if(video.exclusive()) setVisible(false);
|
||||||
if(!input->acquired()) input->acquire();
|
if(!input.acquired()) input.acquire();
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
} else {
|
} else {
|
||||||
if(input->acquired()) input->release();
|
if(input.acquired()) input.release();
|
||||||
if(video->exclusive()) setVisible(true);
|
if(video.exclusive()) setVisible(true);
|
||||||
video->setExclusive(false);
|
video.setExclusive(false);
|
||||||
setFullScreen(false);
|
setFullScreen(false);
|
||||||
menuBar.setVisible(true);
|
menuBar.setVisible(true);
|
||||||
if(settings["UserInterface/ShowStatusBar"].boolean()) {
|
if(settings["UserInterface/ShowStatusBar"].boolean()) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
struct AboutWindow : Window {
|
struct AboutWindow : Window {
|
||||||
Application::Namespace tr{"AboutWindow"};
|
Application::Namespace tr{"AboutWindow"};
|
||||||
|
auto create() -> void;
|
||||||
AboutWindow();
|
|
||||||
|
|
||||||
VerticalLayout layout{this};
|
VerticalLayout layout{this};
|
||||||
Canvas canvas{&layout, Size{400, 85}, 0};
|
Canvas canvas{&layout, Size{400, 85}, 0};
|
||||||
|
@ -113,5 +112,5 @@ struct Presentation : Window {
|
||||||
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
|
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unique_pointer<AboutWindow> aboutWindow;
|
extern AboutWindow aboutWindow;
|
||||||
extern unique_pointer<Presentation> presentation;
|
extern unique_pointer<Presentation> presentation;
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
auto Program::updateAudioDriver(Window parent) -> void {
|
auto Program::updateAudioDriver(Window parent) -> void {
|
||||||
auto changed = (bool)audio;
|
auto changed = (bool)audio;
|
||||||
audio = Audio::create(settings["Audio/Driver"].text());
|
audio.create(settings["Audio/Driver"].text());
|
||||||
audio->setContext(presentation->viewport.handle());
|
audio.setContext(presentation->viewport.handle());
|
||||||
audio->setChannels(2);
|
audio.setChannels(2);
|
||||||
if(changed) {
|
if(changed) {
|
||||||
settings["Audio/Device"].setValue(audio->defaultDevice());
|
settings["Audio/Device"].setValue(audio.device());
|
||||||
settings["Audio/Frequency"].setValue(audio->defaultFrequency());
|
settings["Audio/Frequency"].setValue(audio.frequency());
|
||||||
settings["Audio/Latency"].setValue(audio->defaultLatency());
|
settings["Audio/Latency"].setValue(audio.latency());
|
||||||
}
|
}
|
||||||
updateAudioExclusive();
|
updateAudioExclusive();
|
||||||
updateAudioDevice();
|
updateAudioDevice();
|
||||||
updateAudioBlocking();
|
updateAudioBlocking();
|
||||||
updateAudioDynamic();
|
updateAudioDynamic();
|
||||||
|
|
||||||
if(!audio->ready()) {
|
if(!audio.ready()) {
|
||||||
MessageDialog({
|
MessageDialog({
|
||||||
"Error: failed to initialize [", settings["Audio/Driver"].text(), "] audio driver."
|
"Error: failed to initialize [", settings["Audio/Driver"].text(), "] audio driver."
|
||||||
}).setParent(parent).error();
|
}).setParent(parent).error();
|
||||||
|
@ -23,36 +23,36 @@ auto Program::updateAudioDriver(Window parent) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioExclusive() -> void {
|
auto Program::updateAudioExclusive() -> void {
|
||||||
audio->setExclusive(settings["Audio/Exclusive"].boolean());
|
audio.setExclusive(settings["Audio/Exclusive"].boolean());
|
||||||
updateAudioFrequency();
|
updateAudioFrequency();
|
||||||
updateAudioLatency();
|
updateAudioLatency();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioDevice() -> void {
|
auto Program::updateAudioDevice() -> void {
|
||||||
audio->clear();
|
audio.clear();
|
||||||
if(!audio->availableDevices().find(settings["Audio/Device"].text())) {
|
if(!audio.hasDevice(settings["Audio/Device"].text())) {
|
||||||
settings["Audio/Device"].setValue(audio->defaultDevice());
|
settings["Audio/Device"].setValue(audio.device());
|
||||||
}
|
}
|
||||||
audio->setDevice(settings["Audio/Device"].text());
|
audio.setDevice(settings["Audio/Device"].text());
|
||||||
updateAudioFrequency();
|
updateAudioFrequency();
|
||||||
updateAudioLatency();
|
updateAudioLatency();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioBlocking() -> void {
|
auto Program::updateAudioBlocking() -> void {
|
||||||
audio->clear();
|
audio.clear();
|
||||||
audio->setBlocking(settings["Audio/Blocking"].boolean());
|
audio.setBlocking(settings["Audio/Blocking"].boolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioDynamic() -> void {
|
auto Program::updateAudioDynamic() -> void {
|
||||||
audio->setDynamic(settings["Audio/Dynamic"].boolean());
|
audio.setDynamic(settings["Audio/Dynamic"].boolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioFrequency() -> void {
|
auto Program::updateAudioFrequency() -> void {
|
||||||
audio->clear();
|
audio.clear();
|
||||||
if(!audio->availableFrequencies().find(settings["Audio/Frequency"].real())) {
|
if(!audio.hasFrequency(settings["Audio/Frequency"].real())) {
|
||||||
settings["Audio/Frequency"].setValue(audio->defaultFrequency());
|
settings["Audio/Frequency"].setValue(audio.frequency());
|
||||||
}
|
}
|
||||||
audio->setFrequency(settings["Audio/Frequency"].real());
|
audio.setFrequency(settings["Audio/Frequency"].real());
|
||||||
double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer();
|
double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer();
|
||||||
for(auto item : presentation->speedGroup.objects<MenuRadioItem>()) {
|
for(auto item : presentation->speedGroup.objects<MenuRadioItem>()) {
|
||||||
if(item.checked()) frequency *= item.property("multiplier").real();
|
if(item.checked()) frequency *= item.property("multiplier").real();
|
||||||
|
@ -61,11 +61,11 @@ auto Program::updateAudioFrequency() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioLatency() -> void {
|
auto Program::updateAudioLatency() -> void {
|
||||||
audio->clear();
|
audio.clear();
|
||||||
if(!audio->availableLatencies().find(settings["Audio/Latency"].natural())) {
|
if(!audio.hasLatency(settings["Audio/Latency"].natural())) {
|
||||||
settings["Audio/Latency"].setValue(audio->defaultLatency());
|
settings["Audio/Latency"].setValue(audio.latency());
|
||||||
}
|
}
|
||||||
audio->setLatency(settings["Audio/Latency"].natural());
|
audio.setLatency(settings["Audio/Latency"].natural());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateAudioEffects() -> void {
|
auto Program::updateAudioEffects() -> void {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
auto Program::updateInputDriver(Window parent) -> void {
|
auto Program::updateInputDriver(Window parent) -> void {
|
||||||
auto changed = (bool)input;
|
auto changed = (bool)input;
|
||||||
input = Input::create(settings["Input/Driver"].text());
|
input.create(settings["Input/Driver"].text());
|
||||||
input->setContext(presentation->viewport.handle());
|
input.setContext(presentation->viewport.handle());
|
||||||
if(changed) {
|
if(changed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ auto Program::updateInputDriver(Window parent) -> void {
|
||||||
settingsWindow->input.reloadPorts();
|
settingsWindow->input.reloadPorts();
|
||||||
settingsWindow->hotkeys.reloadMappings();
|
settingsWindow->hotkeys.reloadMappings();
|
||||||
|
|
||||||
if(!input->ready()) {
|
if(!input.ready()) {
|
||||||
MessageDialog({
|
MessageDialog({
|
||||||
"Error: failed to initialize [", settings["Input/Driver"].text(), "] input driver."
|
"Error: failed to initialize [", settings["Input/Driver"].text(), "] input driver."
|
||||||
}).setParent(parent).error();
|
}).setParent(parent).error();
|
||||||
|
|
|
@ -210,15 +210,15 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
|
||||||
screenshot.width = width;
|
screenshot.width = width;
|
||||||
screenshot.height = height;
|
screenshot.height = height;
|
||||||
|
|
||||||
if(video->acquire(output, length, width, height)) {
|
if(video.acquire(output, length, width, height)) {
|
||||||
length >>= 2;
|
length >>= 2;
|
||||||
|
|
||||||
for(auto y : range(height)) {
|
for(auto y : range(height)) {
|
||||||
memory::copy<uint32>(output + y * length, data + y * pitch, width);
|
memory::copy<uint32>(output + y * length, data + y * pitch, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
video->release();
|
video.release();
|
||||||
video->output();
|
video.output();
|
||||||
}
|
}
|
||||||
|
|
||||||
inputManager->frame();
|
inputManager->frame();
|
||||||
|
@ -241,7 +241,7 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::audioSample(const double* samples, uint channels) -> void {
|
auto Program::audioSample(const double* samples, uint channels) -> void {
|
||||||
audio->output(samples);
|
audio.output(samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
||||||
|
|
|
@ -26,7 +26,7 @@ Program::Program(vector<string> arguments) {
|
||||||
new CheatWindow;
|
new CheatWindow;
|
||||||
new StateWindow;
|
new StateWindow;
|
||||||
new ToolsWindow;
|
new ToolsWindow;
|
||||||
new AboutWindow;
|
aboutWindow.create();
|
||||||
|
|
||||||
if(settings["Crashed"].boolean()) {
|
if(settings["Crashed"].boolean()) {
|
||||||
MessageDialog(
|
MessageDialog(
|
||||||
|
@ -67,12 +67,12 @@ auto Program::main() -> void {
|
||||||
if(Application::modal()) return;
|
if(Application::modal()) return;
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
video->poll();
|
video.poll();
|
||||||
inputManager->poll();
|
inputManager->poll();
|
||||||
inputManager->pollHotkeys();
|
inputManager->pollHotkeys();
|
||||||
|
|
||||||
if(paused()) {
|
if(paused()) {
|
||||||
audio->clear();
|
audio.clear();
|
||||||
usleep(20 * 1000);
|
usleep(20 * 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ auto Program::paused() -> bool {
|
||||||
|
|
||||||
auto Program::focused() -> bool {
|
auto Program::focused() -> bool {
|
||||||
//exclusive mode creates its own top-level window: presentation window will not have focus
|
//exclusive mode creates its own top-level window: presentation window will not have focus
|
||||||
if(video && video->exclusive()) return true;
|
if(video && video.exclusive()) return true;
|
||||||
if(presentation && presentation->focused()) return true;
|
if(presentation && presentation->focused()) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
auto Program::updateVideoDriver(Window parent) -> void {
|
auto Program::updateVideoDriver(Window parent) -> void {
|
||||||
auto changed = (bool)video;
|
auto changed = (bool)video;
|
||||||
video = Video::create(settings["Video/Driver"].text());
|
video.create(settings["Video/Driver"].text());
|
||||||
video->setContext(presentation->viewport.handle());
|
video.setContext(presentation->viewport.handle());
|
||||||
if(changed) {
|
if(changed) {
|
||||||
settings["Video/Format"].setValue(video->defaultFormat());
|
settings["Video/Format"].setValue(video.format());
|
||||||
}
|
}
|
||||||
updateVideoExclusive();
|
updateVideoExclusive();
|
||||||
updateVideoBlocking();
|
updateVideoBlocking();
|
||||||
|
@ -11,16 +11,16 @@ auto Program::updateVideoDriver(Window parent) -> void {
|
||||||
updateVideoFormat();
|
updateVideoFormat();
|
||||||
updateVideoShader();
|
updateVideoShader();
|
||||||
|
|
||||||
if(video->ready()) {
|
if(video.ready()) {
|
||||||
presentation->clearViewport();
|
presentation->clearViewport();
|
||||||
updateVideoShader();
|
updateVideoShader();
|
||||||
}
|
}
|
||||||
|
|
||||||
video->onUpdate([&](uint width, uint height) {
|
video.onUpdate([&](uint width, uint height) {
|
||||||
if(!emulator->loaded()) presentation->clearViewport();
|
if(!emulator->loaded()) presentation->clearViewport();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!video->ready()) {
|
if(!video.ready()) {
|
||||||
MessageDialog({
|
MessageDialog({
|
||||||
"Error: failed to initialize [", settings["Video/Driver"].text(), "] video driver."
|
"Error: failed to initialize [", settings["Video/Driver"].text(), "] video driver."
|
||||||
}).setParent(parent).error();
|
}).setParent(parent).error();
|
||||||
|
@ -33,22 +33,22 @@ auto Program::updateVideoDriver(Window parent) -> void {
|
||||||
|
|
||||||
auto Program::updateVideoExclusive() -> void {
|
auto Program::updateVideoExclusive() -> void {
|
||||||
//only enabled in fullscreen mode via Presentation::toggleFullScreen()
|
//only enabled in fullscreen mode via Presentation::toggleFullScreen()
|
||||||
video->setExclusive(false);
|
video.setExclusive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateVideoBlocking() -> void {
|
auto Program::updateVideoBlocking() -> void {
|
||||||
video->setBlocking(settings["Video/Blocking"].boolean());
|
video.setBlocking(settings["Video/Blocking"].boolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateVideoFlush() -> void {
|
auto Program::updateVideoFlush() -> void {
|
||||||
video->setFlush(settings["Video/Flush"].boolean());
|
video.setFlush(settings["Video/Flush"].boolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateVideoFormat() -> void {
|
auto Program::updateVideoFormat() -> void {
|
||||||
if(!video->availableFormats().find(settings["Video/Format"].text())) {
|
if(!video.hasFormat(settings["Video/Format"].text())) {
|
||||||
settings["Video/Format"].setValue(video->defaultFormat());
|
settings["Video/Format"].setValue(video.format());
|
||||||
}
|
}
|
||||||
video->setFormat(settings["Video/Format"].text());
|
video.setFormat(settings["Video/Format"].text());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateVideoShader() -> void {
|
auto Program::updateVideoShader() -> void {
|
||||||
|
@ -56,11 +56,11 @@ auto Program::updateVideoShader() -> void {
|
||||||
&& settings["Video/Shader"].text() != "None"
|
&& settings["Video/Shader"].text() != "None"
|
||||||
&& settings["Video/Shader"].text() != "Blur"
|
&& settings["Video/Shader"].text() != "Blur"
|
||||||
) {
|
) {
|
||||||
video->setSmooth(false);
|
video.setSmooth(false);
|
||||||
video->setShader(settings["Video/Shader"].text());
|
video.setShader(settings["Video/Shader"].text());
|
||||||
} else {
|
} else {
|
||||||
video->setSmooth(settings["Video/Shader"].text() == "Blur");
|
video.setSmooth(settings["Video/Shader"].text() == "Blur");
|
||||||
video->setShader("");
|
video.setShader("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
videoLayout.setSize({2, 2});
|
videoLayout.setSize({2, 2});
|
||||||
videoDriverLabel.setText("Driver:");
|
videoDriverLabel.setText("Driver:");
|
||||||
videoDriverOption.onChange([&] {
|
videoDriverOption.onChange([&] {
|
||||||
videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video->driver());
|
videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video.driverName());
|
||||||
});
|
});
|
||||||
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
|
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
|
||||||
videoFormatLabel.setText("Format:");
|
videoFormatLabel.setText("Format:");
|
||||||
|
@ -30,7 +30,7 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
audioLayout.setSize({2, 2});
|
audioLayout.setSize({2, 2});
|
||||||
audioDriverLabel.setText("Driver:");
|
audioDriverLabel.setText("Driver:");
|
||||||
audioDriverOption.onChange([&] {
|
audioDriverOption.onChange([&] {
|
||||||
audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio->driver());
|
audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio.driverName());
|
||||||
});
|
});
|
||||||
audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); });
|
audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); });
|
||||||
audioDeviceLabel.setText("Device:");
|
audioDeviceLabel.setText("Device:");
|
||||||
|
@ -56,7 +56,7 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
inputLayout.setSize({2, 1});
|
inputLayout.setSize({2, 1});
|
||||||
inputDriverLabel.setText("Driver:");
|
inputDriverLabel.setText("Driver:");
|
||||||
inputDriverOption.onChange([&] {
|
inputDriverOption.onChange([&] {
|
||||||
inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input->driver());
|
inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input.driverName());
|
||||||
});
|
});
|
||||||
inputDriverUpdate.setText("Change").onActivate([&] { inputDriverChange(); });
|
inputDriverUpdate.setText("Change").onActivate([&] { inputDriverChange(); });
|
||||||
|
|
||||||
|
@ -70,17 +70,17 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
|
|
||||||
auto DriverSettings::videoDriverChanged() -> void {
|
auto DriverSettings::videoDriverChanged() -> void {
|
||||||
videoDriverOption.reset();
|
videoDriverOption.reset();
|
||||||
for(auto& driver : video->availableDrivers()) {
|
for(auto& driver : video.hasDrivers()) {
|
||||||
ComboButtonItem item{&videoDriverOption};
|
ComboButtonItem item{&videoDriverOption};
|
||||||
item.setText(driver);
|
item.setText(driver);
|
||||||
if(driver == video->driver()) item.setSelected();
|
if(driver == video.driverName()) item.setSelected();
|
||||||
}
|
}
|
||||||
videoDriverActive.setText({"Active driver: ", video->driver()});
|
videoDriverActive.setText({"Active driver: ", video.driverName()});
|
||||||
videoDriverOption.doChange();
|
videoDriverOption.doChange();
|
||||||
videoFormatChanged();
|
videoFormatChanged();
|
||||||
videoExclusiveToggle.setChecked(video->exclusive()).setEnabled(video->hasExclusive());
|
videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive());
|
||||||
videoBlockingToggle.setChecked(video->blocking()).setEnabled(video->hasBlocking());
|
videoBlockingToggle.setChecked(video.blocking()).setEnabled(video.hasBlocking());
|
||||||
videoFlushToggle.setChecked(video->flush()).setEnabled(video->hasFlush());
|
videoFlushToggle.setChecked(video.flush()).setEnabled(video.hasFlush());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,38 +105,38 @@ auto DriverSettings::videoDriverChange() -> void {
|
||||||
|
|
||||||
auto DriverSettings::videoFormatChanged() -> void {
|
auto DriverSettings::videoFormatChanged() -> void {
|
||||||
videoFormatOption.reset();
|
videoFormatOption.reset();
|
||||||
for(auto& format : video->availableFormats()) {
|
for(auto& format : video.hasFormats()) {
|
||||||
ComboButtonItem item{&videoFormatOption};
|
ComboButtonItem item{&videoFormatOption};
|
||||||
item.setText(format);
|
item.setText(format);
|
||||||
if(format == video->format()) item.setSelected();
|
if(format == video.format()) item.setSelected();
|
||||||
}
|
}
|
||||||
videoFormatOption.setEnabled(video->hasFormat());
|
//videoFormatOption.setEnabled(video.hasFormat());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DriverSettings::videoFormatChange() -> void {
|
auto DriverSettings::videoFormatChange() -> void {
|
||||||
auto item = videoFormatOption.selected();
|
auto item = videoFormatOption.selected();
|
||||||
settings["Video/Format"].setValue(item.text());
|
settings["Video/Format"].setValue(item.text());
|
||||||
video->setFormat(item.text());
|
video.setFormat(item.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
auto DriverSettings::audioDriverChanged() -> void {
|
auto DriverSettings::audioDriverChanged() -> void {
|
||||||
audioDriverOption.reset();
|
audioDriverOption.reset();
|
||||||
for(auto& driver : audio->availableDrivers()) {
|
for(auto& driver : audio.hasDrivers()) {
|
||||||
ComboButtonItem item{&audioDriverOption};
|
ComboButtonItem item{&audioDriverOption};
|
||||||
item.setText(driver);
|
item.setText(driver);
|
||||||
if(driver == audio->driver()) item.setSelected();
|
if(driver == audio.driverName()) item.setSelected();
|
||||||
}
|
}
|
||||||
audioDriverActive.setText({"Active driver: ", audio->driver()});
|
audioDriverActive.setText({"Active driver: ", audio.driverName()});
|
||||||
audioDriverOption.doChange();
|
audioDriverOption.doChange();
|
||||||
audioDeviceChanged();
|
audioDeviceChanged();
|
||||||
audioFrequencyChanged();
|
audioFrequencyChanged();
|
||||||
audioLatencyChanged();
|
audioLatencyChanged();
|
||||||
audioExclusiveToggle.setChecked(audio->exclusive()).setEnabled(audio->hasExclusive());
|
audioExclusiveToggle.setChecked(audio.exclusive()).setEnabled(audio.hasExclusive());
|
||||||
audioBlockingToggle.setChecked(audio->blocking()).setEnabled(audio->hasBlocking());
|
audioBlockingToggle.setChecked(audio.blocking()).setEnabled(audio.hasBlocking());
|
||||||
audioDynamicToggle.setChecked(audio->dynamic()).setEnabled(audio->hasDynamic());
|
audioDynamicToggle.setChecked(audio.dynamic()).setEnabled(audio.hasDynamic());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,12 +161,12 @@ auto DriverSettings::audioDriverChange() -> void {
|
||||||
|
|
||||||
auto DriverSettings::audioDeviceChanged() -> void {
|
auto DriverSettings::audioDeviceChanged() -> void {
|
||||||
audioDeviceOption.reset();
|
audioDeviceOption.reset();
|
||||||
for(auto& device : audio->availableDevices()) {
|
for(auto& device : audio.hasDevices()) {
|
||||||
ComboButtonItem item{&audioDeviceOption};
|
ComboButtonItem item{&audioDeviceOption};
|
||||||
item.setText(device);
|
item.setText(device);
|
||||||
if(device == audio->device()) item.setSelected();
|
if(device == audio.device()) item.setSelected();
|
||||||
}
|
}
|
||||||
audioDeviceOption.setEnabled(audio->hasDevice());
|
//audioDeviceOption.setEnabled(audio->hasDevice());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,12 +180,12 @@ auto DriverSettings::audioDeviceChange() -> void {
|
||||||
|
|
||||||
auto DriverSettings::audioFrequencyChanged() -> void {
|
auto DriverSettings::audioFrequencyChanged() -> void {
|
||||||
audioFrequencyOption.reset();
|
audioFrequencyOption.reset();
|
||||||
for(auto& frequency : audio->availableFrequencies()) {
|
for(auto& frequency : audio.hasFrequencies()) {
|
||||||
ComboButtonItem item{&audioFrequencyOption};
|
ComboButtonItem item{&audioFrequencyOption};
|
||||||
item.setText({(uint)frequency, "hz"});
|
item.setText({(uint)frequency, "hz"});
|
||||||
if(frequency == audio->frequency()) item.setSelected();
|
if(frequency == audio.frequency()) item.setSelected();
|
||||||
}
|
}
|
||||||
audioFrequencyOption.setEnabled(audio->hasFrequency());
|
//audioFrequencyOption.setEnabled(audio->hasFrequency());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +197,12 @@ auto DriverSettings::audioFrequencyChange() -> void {
|
||||||
|
|
||||||
auto DriverSettings::audioLatencyChanged() -> void {
|
auto DriverSettings::audioLatencyChanged() -> void {
|
||||||
audioLatencyOption.reset();
|
audioLatencyOption.reset();
|
||||||
for(auto& latency : audio->availableLatencies()) {
|
for(auto& latency : audio.hasLatencies()) {
|
||||||
ComboButtonItem item{&audioLatencyOption};
|
ComboButtonItem item{&audioLatencyOption};
|
||||||
item.setText(latency);
|
item.setText(latency);
|
||||||
if(latency == audio->latency()) item.setSelected();
|
if(latency == audio.latency()) item.setSelected();
|
||||||
}
|
}
|
||||||
audioLatencyOption.setEnabled(audio->hasLatency());
|
//audioLatencyOption.setEnabled(audio->hasLatency());
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,12 +216,12 @@ auto DriverSettings::audioLatencyChange() -> void {
|
||||||
|
|
||||||
auto DriverSettings::inputDriverChanged() -> void {
|
auto DriverSettings::inputDriverChanged() -> void {
|
||||||
inputDriverOption.reset();
|
inputDriverOption.reset();
|
||||||
for(auto& driver : input->availableDrivers()) {
|
for(auto& driver : input.hasDrivers()) {
|
||||||
ComboButtonItem item{&inputDriverOption};
|
ComboButtonItem item{&inputDriverOption};
|
||||||
item.setText(driver);
|
item.setText(driver);
|
||||||
if(driver == input->driver()) item.setSelected();
|
if(driver == input.driverName()) item.setSelected();
|
||||||
}
|
}
|
||||||
inputDriverActive.setText({"Active driver: ", input->driver()});
|
inputDriverActive.setText({"Active driver: ", input.driverName()});
|
||||||
inputDriverOption.doChange();
|
inputDriverOption.doChange();
|
||||||
layout.setGeometry(layout.geometry());
|
layout.setGeometry(layout.geometry());
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ auto Application::initialize() -> void {
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if(initialized == false) {
|
if(initialized == false) {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
hiro::initialize();
|
||||||
return pApplication::initialize();
|
return pApplication::initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ using nall::vector;
|
||||||
|
|
||||||
namespace hiro {
|
namespace hiro {
|
||||||
|
|
||||||
|
auto initialize() -> void;
|
||||||
|
|
||||||
struct Font;
|
struct Font;
|
||||||
struct Keyboard;
|
struct Keyboard;
|
||||||
|
|
||||||
|
|
|
@ -57,10 +57,12 @@ Icarus icarus;
|
||||||
#include "ui/import-dialog.cpp"
|
#include "ui/import-dialog.cpp"
|
||||||
#include "ui/error-dialog.cpp"
|
#include "ui/error-dialog.cpp"
|
||||||
|
|
||||||
|
auto hiro::initialize() -> void {
|
||||||
|
Application::setName("icarus");
|
||||||
|
}
|
||||||
|
|
||||||
#include <nall/main.hpp>
|
#include <nall/main.hpp>
|
||||||
auto nall::main(vector<string> arguments) -> void {
|
auto nall::main(vector<string> arguments) -> void {
|
||||||
Application::setName("icarus");
|
|
||||||
|
|
||||||
if(arguments.size() == 2 && arguments[1] == "--name") {
|
if(arguments.size() == 2 && arguments[1] == "--name") {
|
||||||
return print("icarus");
|
return print("icarus");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
namespace nall { namespace DSP { namespace Resampler {
|
namespace nall { namespace DSP { namespace Resampler {
|
||||||
|
|
||||||
struct Cubic {
|
struct Cubic {
|
||||||
inline auto reset(double inputFrequency, double outputFrequency, uint queueSize = 0) -> void;
|
inline auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void;
|
||||||
inline auto setInputFrequency(double inputFrequency) -> void;
|
inline auto setInputFrequency(double inputFrequency) -> void;
|
||||||
inline auto pending() const -> bool;
|
inline auto pending() const -> bool;
|
||||||
inline auto read() -> double;
|
inline auto read() -> double;
|
||||||
|
@ -24,13 +24,12 @@ private:
|
||||||
|
|
||||||
auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void {
|
auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void {
|
||||||
this->inputFrequency = inputFrequency;
|
this->inputFrequency = inputFrequency;
|
||||||
this->outputFrequency = outputFrequency;
|
this->outputFrequency = outputFrequency ? outputFrequency : this->inputFrequency;
|
||||||
if(!queueSize) queueSize = outputFrequency * 0.02; //20ms
|
|
||||||
|
|
||||||
ratio = inputFrequency / outputFrequency;
|
ratio = inputFrequency / outputFrequency;
|
||||||
fraction = 0.0;
|
fraction = 0.0;
|
||||||
for(auto& sample : history) sample = 0.0;
|
for(auto& sample : history) sample = 0.0;
|
||||||
samples.resize(queueSize);
|
samples.resize(queueSize ? queueSize : this->outputFrequency * 0.02); //default to 20ms max queue size
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cubic::setInputFrequency(double inputFrequency) -> void {
|
auto Cubic::setInputFrequency(double inputFrequency) -> void {
|
||||||
|
|
|
@ -2,26 +2,23 @@
|
||||||
|
|
||||||
//simple circular ring buffer
|
//simple circular ring buffer
|
||||||
|
|
||||||
|
#include <nall/range.hpp>
|
||||||
|
#include <nall/serializer.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct queue {
|
struct queue {
|
||||||
queue() = default;
|
queue() = default;
|
||||||
|
queue(const queue& source) { operator=(source); }
|
||||||
queue(const queue& source) {
|
queue(queue&& source) { operator=(move(source)); }
|
||||||
operator=(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
queue(queue&& source) {
|
|
||||||
operator=(move(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator=(const queue& source) -> queue& {
|
auto operator=(const queue& source) -> queue& {
|
||||||
if(this == &source) return *this;
|
if(this == &source) return *this;
|
||||||
reset();
|
reset();
|
||||||
_size = source._size;
|
_size = source._size;
|
||||||
_data = new T[_size];
|
_data = new T[_size];
|
||||||
for(auto n : range(_size)) _data[n] = source._data[n];
|
for(uint n : range(_size)) _data[n] = source._data[n];
|
||||||
_read = source._read;
|
_read = source._read;
|
||||||
_write = source._write;
|
_write = source._write;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -42,21 +39,14 @@ struct queue {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const { return _size; }
|
||||||
return _size;
|
template<typename U = T> auto size() const -> uint { return _size * sizeof(T) / sizeof(U); }
|
||||||
}
|
auto empty() const -> bool { return _read == _write; }
|
||||||
|
auto pending() const -> bool { return _read != _write; }
|
||||||
|
auto full() const -> bool { return _write == _size; }
|
||||||
|
|
||||||
auto size() const -> uint {
|
auto data() -> T* { return _data; }
|
||||||
return _size;
|
auto data() const -> const T* { return _data; }
|
||||||
}
|
|
||||||
|
|
||||||
auto data() -> T* {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data() const -> const T* {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reset() {
|
auto reset() {
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
|
@ -70,26 +60,29 @@ struct queue {
|
||||||
reset();
|
reset();
|
||||||
_size = size;
|
_size = size;
|
||||||
_data = new T[_size];
|
_data = new T[_size];
|
||||||
for(auto n : range(_size)) _data[n] = value;
|
for(uint n : range(_size)) _data[n] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pending() const -> bool {
|
auto flush() -> void {
|
||||||
return _read != _write;
|
_read = 0;
|
||||||
|
_write = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto read() -> T {
|
auto read() -> T {
|
||||||
T result = _data[_read];
|
if(_read >= _size) _read = 0;
|
||||||
if(++_read >= _size) _read = 0;
|
return _data[_read++];
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto last() const -> T {
|
|
||||||
return _data[_write];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto write(const T& value) -> void {
|
auto write(const T& value) -> void {
|
||||||
_data[_write] = value;
|
if(_write >= _size) _write = 0;
|
||||||
if(++_write >= _size) _write = 0;
|
_data[_write++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto serialize(serializer& s) -> void {
|
||||||
|
s.array(_data, _size);
|
||||||
|
s.integer(_size);
|
||||||
|
s.integer(_read);
|
||||||
|
s.integer(_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -12,9 +12,10 @@ ifeq ($(ruby),)
|
||||||
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||||
ruby += input.sdl input.xlib input.udev
|
ruby += input.sdl input.xlib input.udev
|
||||||
else ifeq ($(platform),bsd)
|
else ifeq ($(platform),bsd)
|
||||||
ruby += video.glx video.glx2 video.xvideo video.xshm
|
# ruby += video.glx video.glx2 video.xvideo video.xshm
|
||||||
ruby += audio.oss audio.openal
|
ruby += video.glx2 video.xshm
|
||||||
ruby += input.sdl input.xlib
|
ruby += audio.oss #audio.openal
|
||||||
|
ruby += input.sdl #input.xlib
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
struct Audio {
|
|
||||||
static auto create(string driver = "") -> Audio*;
|
|
||||||
static auto optimalDriver() -> string;
|
|
||||||
static auto safestDriver() -> string;
|
|
||||||
static auto availableDrivers() -> vector<string>;
|
|
||||||
|
|
||||||
virtual ~Audio() = default;
|
|
||||||
|
|
||||||
virtual auto driver() -> string { return "None"; }
|
|
||||||
virtual auto ready() -> bool { return true; }
|
|
||||||
|
|
||||||
virtual auto hasExclusive() -> bool { return false; }
|
|
||||||
virtual auto hasContext() -> bool { return false; }
|
|
||||||
virtual auto hasDevice() -> bool { return false; }
|
|
||||||
virtual auto hasBlocking() -> bool { return false; }
|
|
||||||
virtual auto hasDynamic() -> bool { return false; }
|
|
||||||
virtual auto hasChannels() -> bool { return false; }
|
|
||||||
virtual auto hasFrequency() -> bool { return false; }
|
|
||||||
virtual auto hasLatency() -> bool { return false; }
|
|
||||||
|
|
||||||
virtual auto availableDevices() -> vector<string> { return {"Default"}; }
|
|
||||||
virtual auto availableChannels() -> vector<uint> { return {2}; }
|
|
||||||
virtual auto availableFrequencies() -> vector<double> { return {48000.0}; }
|
|
||||||
virtual auto availableLatencies() -> vector<uint> { return {0}; }
|
|
||||||
|
|
||||||
virtual auto defaultDevice() -> string { return availableDevices().first(); }
|
|
||||||
virtual auto defaultChannels() -> uint { return availableChannels().first(); }
|
|
||||||
virtual auto defaultFrequency() -> double { return availableFrequencies().first(); }
|
|
||||||
virtual auto defaultLatency() -> uint { return availableLatencies().first(); }
|
|
||||||
|
|
||||||
virtual auto exclusive() -> bool { return _exclusive; }
|
|
||||||
virtual auto context() -> uintptr { return _context; }
|
|
||||||
virtual auto device() -> string { return _device; }
|
|
||||||
virtual auto blocking() -> bool { return _blocking; }
|
|
||||||
virtual auto dynamic() -> bool { return _dynamic; }
|
|
||||||
virtual auto channels() -> uint { return _channels; }
|
|
||||||
virtual auto frequency() -> double { return _frequency; }
|
|
||||||
virtual auto latency() -> uint { return _latency; }
|
|
||||||
|
|
||||||
virtual auto setExclusive(bool exclusive) -> bool;
|
|
||||||
virtual auto setContext(uintptr context) -> bool;
|
|
||||||
virtual auto setDevice(string device) -> bool;
|
|
||||||
virtual auto setBlocking(bool blocking) -> bool;
|
|
||||||
virtual auto setDynamic(bool dynamic) -> bool;
|
|
||||||
virtual auto setChannels(uint channels) -> bool;
|
|
||||||
virtual auto setFrequency(double frequency) -> bool;
|
|
||||||
virtual auto setLatency(uint latency) -> bool;
|
|
||||||
|
|
||||||
virtual auto clear() -> void {}
|
|
||||||
virtual auto level() -> double { return 0.5; }
|
|
||||||
virtual auto output(const double samples[]) -> void {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual auto pending() -> bool;
|
|
||||||
virtual auto outputDynamic(const double samples[]) -> void;
|
|
||||||
|
|
||||||
bool _exclusive = false;
|
|
||||||
uintptr _context = 0;
|
|
||||||
string _device = "Default";
|
|
||||||
bool _blocking = false;
|
|
||||||
bool _dynamic = false;
|
|
||||||
uint _channels = 2;
|
|
||||||
double _frequency = 48000.0;
|
|
||||||
uint _latency = 0;
|
|
||||||
|
|
||||||
vector<nall::DSP::Resampler::Cubic> _resamplers;
|
|
||||||
};
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <nall/windows/registry.hpp>
|
||||||
#include "asio.hpp"
|
#include "asio.hpp"
|
||||||
|
|
||||||
struct AudioASIO : Audio {
|
struct AudioASIO : Audio {
|
||||||
|
|
|
@ -41,126 +41,190 @@
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Audio::setExclusive(bool exclusive) -> bool {
|
auto Audio::setExclusive(bool exclusive) -> bool {
|
||||||
_exclusive = exclusive;
|
if(driver->exclusive == exclusive) return true;
|
||||||
|
if(!driver->hasExclusive()) return false;
|
||||||
|
if(!driver->setExclusive(driver->exclusive = exclusive)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setContext(uintptr context) -> bool {
|
auto Audio::setContext(uintptr context) -> bool {
|
||||||
_context = context;
|
if(driver->context == context) return true;
|
||||||
|
if(!driver->hasContext()) return false;
|
||||||
|
if(!driver->setContext(driver->context = context)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setDevice(string device) -> bool {
|
auto Audio::setDevice(string device) -> bool {
|
||||||
_device = device;
|
if(driver->device == device) return true;
|
||||||
|
if(!driver->hasDevice(device)) return false;
|
||||||
|
if(!driver->setDevice(driver->device = device)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setBlocking(bool blocking) -> bool {
|
auto Audio::setBlocking(bool blocking) -> bool {
|
||||||
_blocking = blocking;
|
if(driver->blocking == blocking) return true;
|
||||||
Audio::setFrequency(frequency());
|
if(!driver->hasBlocking()) return false;
|
||||||
|
if(!driver->setBlocking(driver->blocking = blocking)) return false;
|
||||||
|
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setDynamic(bool dynamic) -> bool {
|
auto Audio::setDynamic(bool dynamic) -> bool {
|
||||||
_dynamic = dynamic;
|
if(driver->dynamic == dynamic) return true;
|
||||||
|
if(!driver->hasDynamic()) return false;
|
||||||
|
if(!driver->setDynamic(driver->dynamic = dynamic)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setChannels(uint channels) -> bool {
|
auto Audio::setChannels(uint channels) -> bool {
|
||||||
_channels = channels;
|
if(driver->channels == channels) return true;
|
||||||
_resamplers.reset();
|
if(!driver->hasChannels(channels)) return false;
|
||||||
_resamplers.resize(channels);
|
if(!driver->setChannels(driver->channels = channels)) return false;
|
||||||
Audio::setFrequency(frequency());
|
resamplers.reset();
|
||||||
|
resamplers.resize(channels);
|
||||||
|
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setFrequency(double frequency) -> bool {
|
auto Audio::setFrequency(uint frequency) -> bool {
|
||||||
_frequency = frequency;
|
if(driver->frequency == frequency) return true;
|
||||||
for(auto& resampler : _resamplers) {
|
if(!driver->hasFrequency(frequency)) return false;
|
||||||
resampler.reset(frequency, frequency);
|
if(!driver->setFrequency(driver->frequency = frequency)) return false;
|
||||||
}
|
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setLatency(uint latency) -> bool {
|
auto Audio::setLatency(uint latency) -> bool {
|
||||||
_latency = latency;
|
if(driver->latency == latency) return true;
|
||||||
|
if(!driver->hasLatency(latency)) return false;
|
||||||
|
if(!driver->setLatency(driver->latency = latency)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//protected functions
|
//
|
||||||
|
|
||||||
auto Audio::pending() -> bool {
|
auto Audio::clear() -> void {
|
||||||
return _resamplers && _resamplers[0].pending();
|
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
|
||||||
|
return driver->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::outputDynamic(const double samples[]) -> void {
|
auto Audio::level() -> double {
|
||||||
|
return driver->level();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Audio::output(const double samples[]) -> void {
|
||||||
|
if(!driver->dynamic) return driver->output(samples);
|
||||||
|
|
||||||
auto maxDelta = 0.005;
|
auto maxDelta = 0.005;
|
||||||
double fillLevel = level();
|
double fillLevel = driver->level();
|
||||||
double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * frequency();
|
double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * driver->frequency;
|
||||||
for(auto& resampler : _resamplers) {
|
for(auto& resampler : resamplers) {
|
||||||
resampler.setInputFrequency(dynamicFrequency);
|
resampler.setInputFrequency(dynamicFrequency);
|
||||||
resampler.write(*samples++);
|
resampler.write(*samples++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(resamplers.first().pending()) {
|
||||||
|
double samples[driver->channels];
|
||||||
|
for(uint n : range(driver->channels)) samples[n] = resamplers[n].read();
|
||||||
|
driver->output(samples);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//static functions
|
//
|
||||||
|
|
||||||
auto Audio::create(string driver) -> Audio* {
|
auto Audio::create(string driver) -> bool {
|
||||||
Audio* audio = nullptr;
|
reset();
|
||||||
if(!driver) driver = optimalDriver();
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(AUDIO_ALSA)
|
#if defined(AUDIO_ALSA)
|
||||||
if(driver == "ALSA") audio = new AudioALSA;
|
if(driver == "ALSA") self.driver = new AudioALSA(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_AO)
|
#if defined(AUDIO_AO)
|
||||||
if(driver == "libao") audio = new AudioAO;
|
if(driver == "libao") self.driver = new AudioAO(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_ASIO)
|
#if defined(AUDIO_ASIO)
|
||||||
if(driver == "ASIO") audio = new AudioASIO;
|
if(driver == "ASIO") self.driver = new AudioASIO(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_DIRECTSOUND)
|
#if defined(AUDIO_DIRECTSOUND)
|
||||||
if(driver == "DirectSound") audio = new AudioDirectSound;
|
if(driver == "DirectSound") self.driver = new AudioDirectSound(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_OPENAL)
|
#if defined(AUDIO_OPENAL)
|
||||||
if(driver == "OpenAL") audio = new AudioOpenAL;
|
if(driver == "OpenAL") self.driver = new AudioOpenAL(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_OSS)
|
#if defined(AUDIO_OSS)
|
||||||
if(driver == "OSS") audio = new AudioOSS;
|
if(driver == "OSS") self.driver = new AudioOSS(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIO)
|
#if defined(AUDIO_PULSEAUDIO)
|
||||||
if(driver == "PulseAudio") audio = new AudioPulseAudio;
|
if(driver == "PulseAudio") self.driver = new AudioPulseAudio(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
||||||
if(driver == "PulseAudioSimple") audio = new AudioPulseAudioSimple;
|
if(driver == "PulseAudioSimple") self.driver = new AudioPulseAudioSimple(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_WASAPI)
|
#if defined(AUDIO_WASAPI)
|
||||||
if(driver == "WASAPI") audio = new AudioWASAPI;
|
if(driver == "WASAPI") self.driver = new AudioWASAPI(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_XAUDIO2)
|
#if defined(AUDIO_XAUDIO2)
|
||||||
if(driver == "XAudio2") audio = new AudioXAudio2;
|
if(driver == "XAudio2") self.driver = new AudioXAudio2(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!audio) audio = new Audio;
|
if(!self.driver) self.driver = new AudioDriver(*this);
|
||||||
|
|
||||||
audio->_exclusive = audio->exclusive();
|
return self.driver->create();
|
||||||
audio->_context = audio->context();
|
}
|
||||||
audio->_device = audio->defaultDevice();
|
|
||||||
audio->_blocking = audio->blocking();
|
|
||||||
audio->_dynamic = audio->dynamic();
|
|
||||||
audio->_channels = audio->defaultChannels();
|
|
||||||
audio->_frequency = audio->defaultFrequency();
|
|
||||||
audio->_latency = audio->defaultLatency();
|
|
||||||
|
|
||||||
return audio;
|
auto Audio::hasDrivers() -> vector<string> {
|
||||||
|
return {
|
||||||
|
|
||||||
|
#if defined(AUDIO_ASIO)
|
||||||
|
"ASIO",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_WASAPI)
|
||||||
|
"WASAPI",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_XAUDIO2)
|
||||||
|
"XAudio2",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_DIRECTSOUND)
|
||||||
|
"DirectSound",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_ALSA)
|
||||||
|
"ALSA",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_OSS)
|
||||||
|
"OSS",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_OPENAL)
|
||||||
|
"OpenAL",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_PULSEAUDIO)
|
||||||
|
"PulseAudio",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
||||||
|
"PulseAudioSimple",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AUDIO_AO)
|
||||||
|
"libao",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"None"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::optimalDriver() -> string {
|
auto Audio::optimalDriver() -> string {
|
||||||
|
@ -215,50 +279,4 @@ auto Audio::safestDriver() -> string {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::availableDrivers() -> vector<string> {
|
|
||||||
return {
|
|
||||||
|
|
||||||
#if defined(AUDIO_ASIO)
|
|
||||||
"ASIO",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_WASAPI)
|
|
||||||
"WASAPI",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_XAUDIO2)
|
|
||||||
"XAudio2",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_DIRECTSOUND)
|
|
||||||
"DirectSound",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_ALSA)
|
|
||||||
"ALSA",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_OSS)
|
|
||||||
"OSS",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_OPENAL)
|
|
||||||
"OpenAL",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIO)
|
|
||||||
"PulseAudio",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
|
||||||
"PulseAudioSimple",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(AUDIO_AO)
|
|
||||||
"libao",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
"None"};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
struct Audio;
|
||||||
|
|
||||||
|
struct AudioDriver {
|
||||||
|
AudioDriver(Audio& super) : super(super) {}
|
||||||
|
virtual ~AudioDriver() = default;
|
||||||
|
|
||||||
|
virtual auto create() -> bool { return true; }
|
||||||
|
virtual auto driverName() -> string { return "None"; }
|
||||||
|
virtual auto ready() -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto hasExclusive() -> bool { return false; }
|
||||||
|
virtual auto hasContext() -> bool { return false; }
|
||||||
|
virtual auto hasDevices() -> vector<string> { return {"Default"}; }
|
||||||
|
virtual auto hasBlocking() -> bool { return false; }
|
||||||
|
virtual auto hasDynamic() -> bool { return false; }
|
||||||
|
virtual auto hasChannels() -> vector<uint> { return {0}; }
|
||||||
|
virtual auto hasFrequencies() -> vector<uint> { return {0}; }
|
||||||
|
virtual auto hasLatencies() -> vector<uint> { return {0}; }
|
||||||
|
|
||||||
|
auto hasDevice(string device) -> bool { return (bool)hasDevices().find(device); }
|
||||||
|
auto hasChannels(uint channels) -> bool { return (bool)hasChannels().find(channels); }
|
||||||
|
auto hasFrequency(uint frequency) -> bool { return (bool)hasFrequencies().find(frequency); }
|
||||||
|
auto hasLatency(uint latency) -> bool { return (bool)hasLatencies().find(latency); }
|
||||||
|
|
||||||
|
virtual auto setExclusive(bool exclusive) -> bool { return true; }
|
||||||
|
virtual auto setContext(uintptr context) -> bool { return true; }
|
||||||
|
virtual auto setDevice(string device) -> bool { return true; }
|
||||||
|
virtual auto setBlocking(bool blocking) -> bool { return true; }
|
||||||
|
virtual auto setDynamic(bool dynamic) -> bool { return true; }
|
||||||
|
virtual auto setChannels(uint channels) -> bool { return true; }
|
||||||
|
virtual auto setFrequency(uint frequency) -> bool { return true; }
|
||||||
|
virtual auto setLatency(uint latency) -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto clear() -> void {}
|
||||||
|
virtual auto level() -> double { return 0.5; }
|
||||||
|
virtual auto output(const double samples[]) -> void {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Audio& super;
|
||||||
|
friend class Audio;
|
||||||
|
|
||||||
|
bool exclusive = false;
|
||||||
|
uintptr context = 0;
|
||||||
|
string device = "Default";
|
||||||
|
bool blocking = false;
|
||||||
|
bool dynamic = false;
|
||||||
|
uint channels = 0;
|
||||||
|
uint frequency = 0;
|
||||||
|
uint latency = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Audio {
|
||||||
|
static auto hasDrivers() -> vector<string>;
|
||||||
|
static auto hasDriver(string driver) -> bool { return (bool)hasDrivers().find(driver); }
|
||||||
|
static auto optimalDriver() -> string;
|
||||||
|
static auto safestDriver() -> string;
|
||||||
|
|
||||||
|
Audio() : self(*this) {}
|
||||||
|
explicit operator bool() const { return (bool)driver; }
|
||||||
|
auto reset() -> void { driver.reset(); }
|
||||||
|
auto create(string driver = "") -> bool;
|
||||||
|
auto driverName() -> string { return driver->driverName(); }
|
||||||
|
auto ready() -> bool { return driver->ready(); }
|
||||||
|
|
||||||
|
auto hasExclusive() -> bool { return driver->hasExclusive(); }
|
||||||
|
auto hasContext() -> bool { return driver->hasContext(); }
|
||||||
|
auto hasDevices() -> vector<string> { return driver->hasDevices(); }
|
||||||
|
auto hasBlocking() -> bool { return driver->hasBlocking(); }
|
||||||
|
auto hasDynamic() -> bool { return driver->hasDynamic(); }
|
||||||
|
auto hasChannels() -> vector<uint> { return driver->hasChannels(); }
|
||||||
|
auto hasFrequencies() -> vector<uint> { return driver->hasFrequencies(); }
|
||||||
|
auto hasLatencies() -> vector<uint> { return driver->hasLatencies(); }
|
||||||
|
|
||||||
|
auto hasDevice(string device) -> bool { return driver->hasDevice(device); }
|
||||||
|
auto hasChannels(uint channels) -> bool { return driver->hasChannels(channels); }
|
||||||
|
auto hasFrequency(uint frequency) -> bool { return driver->hasFrequency(frequency); }
|
||||||
|
auto hasLatency(uint latency) -> bool { return driver->hasLatency(latency); }
|
||||||
|
|
||||||
|
auto exclusive() -> bool { return driver->exclusive; }
|
||||||
|
auto context() -> uintptr { return driver->context; }
|
||||||
|
auto device() -> string { return driver->device; }
|
||||||
|
auto blocking() -> bool { return driver->blocking; }
|
||||||
|
auto dynamic() -> bool { return driver->dynamic; }
|
||||||
|
auto channels() -> uint { return driver->channels; }
|
||||||
|
auto frequency() -> uint { return driver->frequency; }
|
||||||
|
auto latency() -> uint { return driver->latency; }
|
||||||
|
|
||||||
|
auto setExclusive(bool exclusive) -> bool;
|
||||||
|
auto setContext(uintptr context) -> bool;
|
||||||
|
auto setDevice(string device) -> bool;
|
||||||
|
auto setBlocking(bool blocking) -> bool;
|
||||||
|
auto setDynamic(bool dynamic) -> bool;
|
||||||
|
auto setChannels(uint channels) -> bool;
|
||||||
|
auto setFrequency(uint frequency) -> bool;
|
||||||
|
auto setLatency(uint latency) -> bool;
|
||||||
|
|
||||||
|
auto clear() -> void;
|
||||||
|
auto level() -> double;
|
||||||
|
auto output(const double samples[]) -> void;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Audio& self;
|
||||||
|
unique_pointer<AudioDriver> driver;
|
||||||
|
vector<nall::DSP::Resampler::Cubic> resamplers;
|
||||||
|
};
|
|
@ -1,8 +1,15 @@
|
||||||
#include <dsound.h>
|
#include <dsound.h>
|
||||||
|
|
||||||
struct AudioDirectSound : Audio {
|
struct AudioDirectSound : Audio {
|
||||||
AudioDirectSound() { initialize(); }
|
AudioDirectSound() {
|
||||||
~AudioDirectSound() { terminate(); }
|
Audio::setFrequency(48000.0);
|
||||||
|
Audio::setLatency(40);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
~AudioDirectSound() {
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
auto driver() -> string override { return "DirectSound"; }
|
auto driver() -> string override { return "DirectSound"; }
|
||||||
auto ready() -> bool override { return _ready; }
|
auto ready() -> bool override { return _ready; }
|
||||||
|
@ -19,6 +26,9 @@ struct AudioDirectSound : Audio {
|
||||||
return {40, 60, 80, 100};
|
return {40, 60, 80, 100};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto defaultFrequency() -> double override { return 48000.0; }
|
||||||
|
auto defaultLatency() -> uint override { return 40; }
|
||||||
|
|
||||||
auto setBlocking(bool blocking) -> bool override {
|
auto setBlocking(bool blocking) -> bool override {
|
||||||
if(blocking == Audio::blocking()) return true;
|
if(blocking == Audio::blocking()) return true;
|
||||||
if(!Audio::setBlocking(blocking)) return false;
|
if(!Audio::setBlocking(blocking)) return false;
|
||||||
|
|
|
@ -7,8 +7,17 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct AudioOpenAL : Audio {
|
struct AudioOpenAL : Audio {
|
||||||
AudioOpenAL() { initialize(); }
|
AudioOpenAL() {
|
||||||
~AudioOpenAL() { terminate(); }
|
Audio::setDevice(availableDevices().first());
|
||||||
|
Audio::setChannels(2);
|
||||||
|
Audio::setFrequency(48000.0);
|
||||||
|
Audio::setLatency(20);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
~AudioOpenAL() {
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
auto driver() -> string override { return "OpenAL"; }
|
auto driver() -> string override { return "OpenAL"; }
|
||||||
auto ready() -> bool override { return _ready; }
|
auto ready() -> bool override { return _ready; }
|
||||||
|
@ -21,7 +30,12 @@ struct AudioOpenAL : Audio {
|
||||||
|
|
||||||
auto availableDevices() -> vector<string> override {
|
auto availableDevices() -> vector<string> override {
|
||||||
vector<string> devices;
|
vector<string> devices;
|
||||||
for(auto& device : queryDevices()) devices.append(device);
|
if(const char* list = alcGetString(nullptr, ALC_DEVICE_SPECIFIER)) {
|
||||||
|
while(list && *list) {
|
||||||
|
result.append(list);
|
||||||
|
list += strlen(list) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,38 +51,35 @@ struct AudioOpenAL : Audio {
|
||||||
return {20, 40, 60, 80, 100};
|
return {20, 40, 60, 80, 100};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto context() -> uintptr override { return 0; }
|
||||||
|
auto dynamic() -> bool override { return false; }
|
||||||
|
|
||||||
auto setDevice(string device) -> bool override {
|
auto setDevice(string device) -> bool override {
|
||||||
if(device == this->device()) return true;
|
if(device == Audio::device()) return true;
|
||||||
if(!Audio::setDevice(device)) return false;
|
if(!Audio::setDevice(device)) return false;
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setBlocking(bool blocking) -> bool override {
|
auto setBlocking(bool blocking) -> bool override {
|
||||||
if(blocking == this->blocking()) return true;
|
if(blocking == Audio::blocking()) return true;
|
||||||
if(!Audio::setBlocking(blocking)) return false;
|
if(!Audio::setBlocking(blocking)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setChannels(uint channels) -> bool override {
|
|
||||||
if(channels == this->channels()) return true;
|
|
||||||
if(!Audio::setChannels(channels)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setFrequency(double frequency) -> bool override {
|
auto setFrequency(double frequency) -> bool override {
|
||||||
if(frequency == this->frequency()) return true;
|
if(frequency == Audio::frequency()) return true;
|
||||||
if(!Audio::setFrequency(frequency)) return false;
|
if(!Audio::setFrequency(frequency)) return false;
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setLatency(uint latency) -> bool override {
|
auto setLatency(uint latency) -> bool override {
|
||||||
if(latency == this->latency()) return true;
|
if(latency == Audio::latency()) return true;
|
||||||
if(!Audio::setLatency(latency)) return false;
|
if(!Audio::setLatency(latency)) return false;
|
||||||
if(ready()) updateLatency();
|
if(ready()) updateLatency();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output(const double samples[]) -> void override {
|
auto write(const double samples[]) -> void override {
|
||||||
_buffer[_bufferLength] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
_buffer[_bufferLength] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
_buffer[_bufferLength] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
_buffer[_bufferLength] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
if(++_bufferLength < _bufferSize) return;
|
if(++_bufferLength < _bufferSize) return;
|
||||||
|
@ -171,20 +182,6 @@ private:
|
||||||
_buffer = nullptr;
|
_buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto queryDevices() -> vector<string> {
|
|
||||||
vector<string> result;
|
|
||||||
|
|
||||||
const char* list = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
|
||||||
if(!list) return result;
|
|
||||||
|
|
||||||
while(list && *list) {
|
|
||||||
result.append(list);
|
|
||||||
list += strlen(list) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto updateLatency() -> void {
|
auto updateLatency() -> void {
|
||||||
delete[] _buffer;
|
delete[] _buffer;
|
||||||
_bufferSize = _frequency * _latency / 1000.0 + 0.5;
|
_bufferSize = _frequency * _latency / 1000.0 + 0.5;
|
||||||
|
|
|
@ -13,77 +13,54 @@
|
||||||
#define SNDCTL_DSP_POLICY _IOW('P', 45, int)
|
#define SNDCTL_DSP_POLICY _IOW('P', 45, int)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct AudioOSS : Audio {
|
struct AudioOSS : AudioDriver {
|
||||||
AudioOSS() { initialize(); }
|
AudioOSS& self;
|
||||||
|
|
||||||
|
AudioOSS(Audio& super) : AudioDriver(super), self(*this) {}
|
||||||
~AudioOSS() { terminate(); }
|
~AudioOSS() { terminate(); }
|
||||||
|
|
||||||
auto driver() -> string override { return "OSS"; }
|
auto create() -> bool {
|
||||||
|
super.setDevice("/dev/dsp");
|
||||||
|
super.setChannels(2);
|
||||||
|
super.setFrequency(48000);
|
||||||
|
super.setLatency(3);
|
||||||
|
buffer.resize(64);
|
||||||
|
return initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto driverName() -> string override { return "OSS"; }
|
||||||
auto ready() -> bool override { return _fd >= 0; }
|
auto ready() -> bool override { return _fd >= 0; }
|
||||||
|
|
||||||
auto hasDevice() -> bool override { return true; }
|
|
||||||
auto hasDynamic() -> bool override { return true; }
|
|
||||||
auto hasBlocking() -> bool override { return true; }
|
auto hasBlocking() -> bool override { return true; }
|
||||||
auto hasChannels() -> bool override { return true; }
|
auto hasDynamic() -> bool override { return true; }
|
||||||
auto hasFrequency() -> bool override { return true; }
|
|
||||||
auto hasLatency() -> bool override { return true; }
|
|
||||||
|
|
||||||
auto availableDevices() -> vector<string> override {
|
auto hasDevices() -> vector<string> override {
|
||||||
vector<string> devices;
|
vector<string> devices;
|
||||||
devices.append("/dev/dsp");
|
devices.append("/dev/dsp");
|
||||||
for(auto& device : directory::files("/dev/", "dsp?*")) devices.append(string{"/dev/", device});
|
for(auto& device : directory::files("/dev/", "dsp?*")) devices.append(string{"/dev/", device});
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto defaultChannels() -> uint override { return 2; }
|
auto hasChannels() -> vector<uint> override {
|
||||||
auto defaultFrequency() -> double override { return 48000.0; }
|
|
||||||
auto defaultLatency() -> uint override { return 3; }
|
|
||||||
|
|
||||||
auto availableChannels() -> vector<uint> override {
|
|
||||||
return {1, 2};
|
return {1, 2};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto availableFrequencies() -> vector<double> override {
|
auto hasFrequencies() -> vector<uint> override {
|
||||||
return {44100.0, 48000.0, 96000.0};
|
return {44100, 48000, 96000};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto availableLatencies() -> vector<uint> override {
|
auto hasLatencies() -> vector<uint> override {
|
||||||
return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
return {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setDevice(string device) -> bool override {
|
auto setDevice(string device) -> bool override { return initialize(); }
|
||||||
if(device == Audio::device()) return true;
|
auto setBlocking(bool blocking) -> bool override { return updateBlocking(); }
|
||||||
if(!Audio::setDevice(device)) return false;
|
auto setChannels(uint channels) -> bool override { return initialize(); }
|
||||||
return initialize();
|
auto setFrequency(uint frequency) -> bool override { return initialize(); }
|
||||||
}
|
auto setLatency(uint latency) -> bool override { return initialize(); }
|
||||||
|
|
||||||
auto setBlocking(bool blocking) -> bool override {
|
auto clear() -> void override {
|
||||||
if(blocking == Audio::blocking()) return true;
|
buffer.resize(64);
|
||||||
if(!Audio::setBlocking(blocking)) return false;
|
|
||||||
return updateBlocking();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setDynamic(bool dynamic) -> bool override {
|
|
||||||
if(dynamic == Audio::dynamic()) return true;
|
|
||||||
if(!Audio::setDynamic(dynamic)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setChannels(uint channels) -> bool override {
|
|
||||||
if(channels == Audio::channels()) return true;
|
|
||||||
if(!Audio::setChannels(channels)) return false;
|
|
||||||
return initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setFrequency(double frequency) -> bool override {
|
|
||||||
if(frequency == Audio::frequency()) return true;
|
|
||||||
if(!Audio::setFrequency(frequency)) return false;
|
|
||||||
return initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setLatency(uint latency) -> bool override {
|
|
||||||
if(latency == Audio::latency()) return true;
|
|
||||||
if(!Audio::setLatency(latency)) return false;
|
|
||||||
return initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto level() -> double override {
|
auto level() -> double override {
|
||||||
|
@ -95,18 +72,9 @@ struct AudioOSS : Audio {
|
||||||
auto output(const double samples[]) -> void override {
|
auto output(const double samples[]) -> void override {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
|
|
||||||
if(!_dynamic) {
|
for(uint n : range(self.channels)) {
|
||||||
for(uint n : range(channels())) {
|
buffer.write(sclamp<16>(samples[n] * 32767.0));
|
||||||
sample(sclamp<16>(samples[n] * 32767.0));
|
if(buffer.full()) write(_fd, buffer.data(), buffer.size<uint8_t>());
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Audio::outputDynamic(samples);
|
|
||||||
while(pending()) {
|
|
||||||
for(auto& resampler : _resamplers) {
|
|
||||||
auto sample = (uint16_t)sclamp<16>(resampler.read() * 32767.0);
|
|
||||||
auto unused = write(_fd, &sample, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,23 +82,20 @@ private:
|
||||||
auto initialize() -> bool {
|
auto initialize() -> bool {
|
||||||
terminate();
|
terminate();
|
||||||
|
|
||||||
if(!availableDevices().find(_device)) {
|
if(!hasDevices().find(self.device)) self.device = hasDevices().first();
|
||||||
Audio::setDevice(availableDevices().left());
|
|
||||||
}
|
|
||||||
Audio::setChannels(channels());
|
|
||||||
|
|
||||||
_fd = open(_device, O_WRONLY, O_NONBLOCK);
|
_fd = open(self.device, O_WRONLY, O_NONBLOCK);
|
||||||
if(_fd < 0) return false;
|
if(_fd < 0) return false;
|
||||||
|
|
||||||
int cooked = 1;
|
int cooked = 1;
|
||||||
ioctl(_fd, SNDCTL_DSP_COOKEDMODE, &cooked);
|
ioctl(_fd, SNDCTL_DSP_COOKEDMODE, &cooked);
|
||||||
//policy: 0 = minimum latency (higher CPU usage); 10 = maximum latency (lower CPU usage)
|
//policy: 0 = minimum latency (higher CPU usage); 10 = maximum latency (lower CPU usage)
|
||||||
int policy = min(10, _latency);
|
int policy = min(10, self.latency);
|
||||||
ioctl(_fd, SNDCTL_DSP_POLICY, &policy);
|
ioctl(_fd, SNDCTL_DSP_POLICY, &policy);
|
||||||
int channels = _channels;
|
int channels = self.channels;
|
||||||
ioctl(_fd, SNDCTL_DSP_CHANNELS, &channels);
|
ioctl(_fd, SNDCTL_DSP_CHANNELS, &channels);
|
||||||
ioctl(_fd, SNDCTL_DSP_SETFMT, &_format);
|
ioctl(_fd, SNDCTL_DSP_SETFMT, &_format);
|
||||||
int frequency = _frequency;
|
int frequency = self.frequency;
|
||||||
ioctl(_fd, SNDCTL_DSP_SPEED, &frequency);
|
ioctl(_fd, SNDCTL_DSP_SPEED, &frequency);
|
||||||
updateBlocking();
|
updateBlocking();
|
||||||
audio_buf_info info;
|
audio_buf_info info;
|
||||||
|
@ -150,23 +115,14 @@ private:
|
||||||
if(!ready()) return false;
|
if(!ready()) return false;
|
||||||
auto flags = fcntl(_fd, F_GETFL);
|
auto flags = fcntl(_fd, F_GETFL);
|
||||||
if(flags < 0) return false;
|
if(flags < 0) return false;
|
||||||
_blocking ? flags &=~ O_NONBLOCK : flags |= O_NONBLOCK;
|
self.blocking ? flags &=~ O_NONBLOCK : flags |= O_NONBLOCK;
|
||||||
fcntl(_fd, F_SETFL, flags);
|
fcntl(_fd, F_SETFL, flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sample(uint16_t sample) -> void {
|
|
||||||
_outputBuffer[_outputOffset++] = sample;
|
|
||||||
if(_outputOffset >= sizeof(_outputBuffer) / sizeof(uint16_t)) {
|
|
||||||
write(_fd, &_outputBuffer, sizeof(_outputBuffer));
|
|
||||||
_outputOffset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _fd = -1;
|
int _fd = -1;
|
||||||
int _format = AFMT_S16_LE;
|
int _format = AFMT_S16_LE;
|
||||||
int _bufferSize = 1;
|
int _bufferSize = 1;
|
||||||
|
|
||||||
uint _outputOffset = 0;
|
queue<int16_t> buffer;
|
||||||
uint16_t _outputBuffer[64];
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
struct Input {
|
|
||||||
static auto create(string driver = "") -> Input*;
|
|
||||||
static auto optimalDriver() -> string;
|
|
||||||
static auto safestDriver() -> string;
|
|
||||||
static auto availableDrivers() -> vector<string>;
|
|
||||||
|
|
||||||
virtual ~Input() = default;
|
|
||||||
|
|
||||||
virtual auto driver() -> string { return "None"; }
|
|
||||||
virtual auto ready() -> bool { return true; }
|
|
||||||
|
|
||||||
virtual auto hasContext() -> bool { return false; }
|
|
||||||
|
|
||||||
virtual auto context() -> uintptr { return _context; }
|
|
||||||
|
|
||||||
virtual auto setContext(uintptr context) -> bool;
|
|
||||||
|
|
||||||
virtual auto acquired() -> bool { return false; }
|
|
||||||
virtual auto acquire() -> bool { return false; }
|
|
||||||
virtual auto release() -> bool { return false; }
|
|
||||||
virtual auto poll() -> vector<shared_pointer<nall::HID::Device>> { return {}; }
|
|
||||||
virtual auto rumble(uint64_t id, bool enable) -> bool { return false; }
|
|
||||||
|
|
||||||
auto onChange(const function<void (shared_pointer<nall::HID::Device>, uint, uint, int16_t, int16_t)>&) -> void;
|
|
||||||
auto doChange(shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uintptr _context = 0;
|
|
||||||
|
|
||||||
function<void (shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> _onChange;
|
|
||||||
};
|
|
|
@ -25,55 +25,107 @@
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Input::setContext(uintptr context) -> bool {
|
auto Input::setContext(uintptr context) -> bool {
|
||||||
_context = context;
|
if(driver->context == context) return true;
|
||||||
|
if(!driver->hasContext()) return false;
|
||||||
|
if(!driver->setContext(driver->context = context)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
auto Input::acquired() -> bool {
|
||||||
|
return driver->acquired();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Input::acquire() -> bool {
|
||||||
|
return driver->acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Input::release() -> bool {
|
||||||
|
return driver->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Input::poll() -> vector<shared_pointer<nall::HID::Device>> {
|
||||||
|
return driver->poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Input::rumble(uint64_t id, bool enable) -> bool {
|
||||||
|
return driver->rumble(id, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
auto Input::onChange(const function<void (shared_pointer<HID::Device>, uint, uint, int16_t, int16_t)>& onChange) -> void {
|
auto Input::onChange(const function<void (shared_pointer<HID::Device>, uint, uint, int16_t, int16_t)>& onChange) -> void {
|
||||||
_onChange = onChange;
|
change = onChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::doChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
|
auto Input::doChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
|
||||||
if(_onChange) _onChange(device, group, input, oldValue, newValue);
|
if(change) change(device, group, input, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//protected functions
|
//
|
||||||
|
|
||||||
//static functions
|
auto Input::create(string driver) -> bool {
|
||||||
|
reset();
|
||||||
auto Input::create(string driver) -> Input* {
|
|
||||||
Input* input = nullptr;
|
|
||||||
if(!driver) driver = optimalDriver();
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(INPUT_WINDOWS)
|
#if defined(INPUT_WINDOWS)
|
||||||
if(driver == "Windows") input = new InputWindows;
|
if(driver == "Windows") self.driver = new InputWindows(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_QUARTZ)
|
#if defined(INPUT_QUARTZ)
|
||||||
if(driver == "Quartz") input = new InputQuartz;
|
if(driver == "Quartz") self.driver = new InputQuartz(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_CARBON)
|
#if defined(INPUT_CARBON)
|
||||||
if(driver == "Carbon") input = new InputCarbon;
|
if(driver == "Carbon") self.driver = new InputCarbon(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_UDEV)
|
#if defined(INPUT_UDEV)
|
||||||
if(driver == "udev") input = new InputUdev;
|
if(driver == "udev") self.driver = new InputUdev(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_SDL)
|
#if defined(INPUT_SDL)
|
||||||
if(driver == "SDL") input = new InputSDL;
|
if(driver == "SDL") self.driver = new InputSDL(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_XLIB)
|
#if defined(INPUT_XLIB)
|
||||||
if(driver == "Xlib") input = new InputXlib;
|
if(driver == "Xlib") self.driver = new InputXlib(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!input) input = new Input;
|
if(!self.driver) self.driver = new InputDriver(*this);
|
||||||
|
|
||||||
input->_context = input->context();
|
return self.driver->create();
|
||||||
|
}
|
||||||
|
|
||||||
return input;
|
auto Input::hasDrivers() -> vector<string> {
|
||||||
|
return {
|
||||||
|
|
||||||
|
#if defined(INPUT_WINDOWS)
|
||||||
|
"Windows",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INPUT_QUARTZ)
|
||||||
|
"Quartz",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INPUT_CARBON)
|
||||||
|
"Carbon",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INPUT_UDEV)
|
||||||
|
"udev",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INPUT_SDL)
|
||||||
|
"SDL",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(INPUT_XLIB)
|
||||||
|
"Xlib",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"None"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::optimalDriver() -> string {
|
auto Input::optimalDriver() -> string {
|
||||||
|
@ -112,34 +164,4 @@ auto Input::safestDriver() -> string {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::availableDrivers() -> vector<string> {
|
|
||||||
return {
|
|
||||||
|
|
||||||
#if defined(INPUT_WINDOWS)
|
|
||||||
"Windows",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(INPUT_QUARTZ)
|
|
||||||
"Quartz",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(INPUT_CARBON)
|
|
||||||
"Carbon",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(INPUT_UDEV)
|
|
||||||
"udev",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(INPUT_SDL)
|
|
||||||
"SDL",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(INPUT_XLIB)
|
|
||||||
"Xlib",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
"None"};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
struct Input;
|
||||||
|
|
||||||
|
struct InputDriver {
|
||||||
|
InputDriver(Input& super) : super(super) {}
|
||||||
|
virtual ~InputDriver() = default;
|
||||||
|
|
||||||
|
virtual auto create() -> bool { return true; }
|
||||||
|
virtual auto driverName() -> string { return "None"; }
|
||||||
|
virtual auto ready() -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto hasContext() -> bool { return false; }
|
||||||
|
|
||||||
|
virtual auto setContext(uintptr context) -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto acquired() -> bool { return false; }
|
||||||
|
virtual auto acquire() -> bool { return false; }
|
||||||
|
virtual auto release() -> bool { return false; }
|
||||||
|
virtual auto poll() -> vector<shared_pointer<nall::HID::Device>> { return {}; }
|
||||||
|
virtual auto rumble(uint64_t id, bool enable) -> bool { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Input& super;
|
||||||
|
friend class Input;
|
||||||
|
|
||||||
|
uintptr context = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
static auto hasDrivers() -> vector<string>;
|
||||||
|
static auto hasDriver(string driver) -> bool { return (bool)hasDrivers().find(driver); }
|
||||||
|
static auto optimalDriver() -> string;
|
||||||
|
static auto safestDriver() -> string;
|
||||||
|
|
||||||
|
Input() : self(*this) {}
|
||||||
|
explicit operator bool() const { return (bool)driver; }
|
||||||
|
auto reset() -> void { driver.reset(); }
|
||||||
|
auto create(string driver = "") -> bool;
|
||||||
|
auto driverName() -> string { return driver->driverName(); }
|
||||||
|
auto ready() -> bool { return driver->ready(); }
|
||||||
|
|
||||||
|
auto hasContext() -> bool { return driver->hasContext(); }
|
||||||
|
|
||||||
|
auto context() -> uintptr { return driver->context; }
|
||||||
|
|
||||||
|
auto setContext(uintptr context) -> bool;
|
||||||
|
|
||||||
|
auto acquired() -> bool;
|
||||||
|
auto acquire() -> bool;
|
||||||
|
auto release() -> bool;
|
||||||
|
auto poll() -> vector<shared_pointer<nall::HID::Device>>;
|
||||||
|
auto rumble(uint64_t id, bool enable) -> bool;
|
||||||
|
|
||||||
|
auto onChange(const function<void (shared_pointer<nall::HID::Device>, uint, uint, int16_t, int16_t)>&) -> void;
|
||||||
|
auto doChange(shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Input& self;
|
||||||
|
unique_pointer<InputDriver> driver;
|
||||||
|
function<void (shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> change;
|
||||||
|
};
|
|
@ -6,38 +6,32 @@
|
||||||
#include "mouse/xlib.cpp"
|
#include "mouse/xlib.cpp"
|
||||||
#include "joypad/sdl.cpp"
|
#include "joypad/sdl.cpp"
|
||||||
|
|
||||||
struct InputSDL : Input {
|
struct InputSDL : InputDriver {
|
||||||
InputSDL() : _keyboard(*this), _mouse(*this), _joypad(*this) { initialize(); }
|
InputSDL& self;
|
||||||
|
|
||||||
|
InputSDL(Input& super) : InputDriver(super), self(*this), keyboard(super), mouse(super), joypad(super) {}
|
||||||
~InputSDL() { terminate(); }
|
~InputSDL() { terminate(); }
|
||||||
|
|
||||||
auto driver() -> string override { return "SDL"; }
|
auto create() -> bool {
|
||||||
auto ready() -> bool override { return _ready; }
|
|
||||||
|
|
||||||
auto hasContext() -> bool override { return true; }
|
|
||||||
|
|
||||||
auto setContext(uintptr context) -> bool override {
|
|
||||||
if(context == Input::context()) return true;
|
|
||||||
if(!Input::setContext(context)) return false;
|
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acquired() -> bool override {
|
auto driverName() -> string override { return "SDL"; }
|
||||||
return _mouse.acquired();
|
auto ready() -> bool override { return isReady; }
|
||||||
}
|
|
||||||
|
|
||||||
auto acquire() -> bool override {
|
auto hasContext() -> bool override { return true; }
|
||||||
return _mouse.acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto release() -> bool override {
|
auto setContext(uintptr context) -> bool override { return initialize(); }
|
||||||
return _mouse.release();
|
|
||||||
}
|
auto acquired() -> bool override { return mouse.acquired(); }
|
||||||
|
auto acquire() -> bool override { return mouse.acquire(); }
|
||||||
|
auto release() -> bool override { return mouse.release(); }
|
||||||
|
|
||||||
auto poll() -> vector<shared_pointer<HID::Device>> override {
|
auto poll() -> vector<shared_pointer<HID::Device>> override {
|
||||||
vector<shared_pointer<HID::Device>> devices;
|
vector<shared_pointer<HID::Device>> devices;
|
||||||
_keyboard.poll(devices);
|
keyboard.poll(devices);
|
||||||
_mouse.poll(devices);
|
mouse.poll(devices);
|
||||||
_joypad.poll(devices);
|
joypad.poll(devices);
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,23 +42,23 @@ struct InputSDL : Input {
|
||||||
private:
|
private:
|
||||||
auto initialize() -> bool {
|
auto initialize() -> bool {
|
||||||
terminate();
|
terminate();
|
||||||
if(!_context) return false;
|
if(!self.context) return false;
|
||||||
if(!_keyboard.initialize()) return false;
|
if(!keyboard.initialize()) return false;
|
||||||
if(!_mouse.initialize(_context)) return false;
|
if(!mouse.initialize(self.context)) return false;
|
||||||
if(!_joypad.initialize()) return false;
|
if(!joypad.initialize()) return false;
|
||||||
return _ready = true;
|
return isReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto terminate() -> void {
|
auto terminate() -> void {
|
||||||
_ready = false;
|
isReady = false;
|
||||||
_keyboard.terminate();
|
keyboard.terminate();
|
||||||
_mouse.terminate();
|
mouse.terminate();
|
||||||
_joypad.terminate();
|
joypad.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _ready = false;
|
bool isReady = false;
|
||||||
|
|
||||||
InputKeyboardXlib _keyboard;
|
InputKeyboardXlib keyboard;
|
||||||
InputMouseXlib _mouse;
|
InputMouseXlib mouse;
|
||||||
InputJoypadSDL _joypad;
|
InputJoypadSDL joypad;
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,6 @@ using namespace ruby;
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "video.cpp"
|
#include <ruby/video/video.cpp>
|
||||||
#include "audio.cpp"
|
#include <ruby/audio/audio.cpp>
|
||||||
#include "input.cpp"
|
#include <ruby/input/input.cpp>
|
||||||
|
|
|
@ -7,23 +7,27 @@
|
||||||
#include <nall/hid.hpp>
|
#include <nall/hid.hpp>
|
||||||
#include <nall/image.hpp>
|
#include <nall/image.hpp>
|
||||||
#include <nall/matrix.hpp>
|
#include <nall/matrix.hpp>
|
||||||
|
#include <nall/queue.hpp>
|
||||||
#include <nall/range.hpp>
|
#include <nall/range.hpp>
|
||||||
#include <nall/set.hpp>
|
#include <nall/set.hpp>
|
||||||
#include <nall/shared-pointer.hpp>
|
#include <nall/shared-pointer.hpp>
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
|
#include <nall/unique-pointer.hpp>
|
||||||
#include <nall/vector.hpp>
|
#include <nall/vector.hpp>
|
||||||
#include <nall/dsp/resampler/cubic.hpp>
|
#include <nall/dsp/resampler/cubic.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
|
|
||||||
using nall::function;
|
using nall::function;
|
||||||
|
using nall::queue;
|
||||||
using nall::shared_pointer;
|
using nall::shared_pointer;
|
||||||
using nall::string;
|
using nall::string;
|
||||||
|
using nall::unique_pointer;
|
||||||
using nall::vector;
|
using nall::vector;
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
#include "video.hpp"
|
#include <ruby/video/video.hpp>
|
||||||
#include "audio.hpp"
|
#include <ruby/audio/audio.hpp>
|
||||||
#include "input.hpp"
|
#include <ruby/input/input.hpp>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
struct Video {
|
|
||||||
static auto create(string driver = "") -> Video*;
|
|
||||||
static auto optimalDriver() -> string;
|
|
||||||
static auto safestDriver() -> string;
|
|
||||||
static auto availableDrivers() -> vector<string>;
|
|
||||||
|
|
||||||
virtual ~Video() = default;
|
|
||||||
|
|
||||||
virtual auto driver() -> string { return "None"; }
|
|
||||||
virtual auto ready() -> bool { return true; }
|
|
||||||
|
|
||||||
virtual auto hasExclusive() -> bool { return false; }
|
|
||||||
virtual auto hasContext() -> bool { return false; }
|
|
||||||
virtual auto hasBlocking() -> bool { return false; }
|
|
||||||
virtual auto hasFlush() -> bool { return false; }
|
|
||||||
virtual auto hasFormat() -> bool { return false; }
|
|
||||||
virtual auto hasSmooth() -> bool { return false; }
|
|
||||||
virtual auto hasShader() -> bool { return false; }
|
|
||||||
|
|
||||||
virtual auto availableFormats() -> vector<string> { return {"Default"}; }
|
|
||||||
|
|
||||||
virtual auto defaultFormat() -> string { return availableFormats().first(); }
|
|
||||||
|
|
||||||
virtual auto exclusive() -> bool { return _exclusive; }
|
|
||||||
virtual auto context() -> uintptr { return _context; }
|
|
||||||
virtual auto blocking() -> bool { return _blocking; }
|
|
||||||
virtual auto flush() -> bool { return _flush; }
|
|
||||||
virtual auto format() -> string { return _format; }
|
|
||||||
virtual auto smooth() -> bool { return _smooth; }
|
|
||||||
virtual auto shader() -> string { return _shader; }
|
|
||||||
|
|
||||||
virtual auto setExclusive(bool exclusive) -> bool;
|
|
||||||
virtual auto setContext(uintptr context) -> bool;
|
|
||||||
virtual auto setBlocking(bool blocking) -> bool;
|
|
||||||
virtual auto setFlush(bool flush) -> bool;
|
|
||||||
virtual auto setFormat(string format) -> bool;
|
|
||||||
virtual auto setSmooth(bool smooth) -> bool;
|
|
||||||
virtual auto setShader(string shader) -> bool;
|
|
||||||
|
|
||||||
virtual auto clear() -> void {}
|
|
||||||
virtual auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
|
||||||
virtual auto release() -> void {}
|
|
||||||
virtual auto output() -> void {}
|
|
||||||
virtual auto poll() -> void {}
|
|
||||||
|
|
||||||
auto onUpdate(const function<void (uint, uint)>&) -> void;
|
|
||||||
auto doUpdate(uint width, uint height) -> void;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool _exclusive = false;
|
|
||||||
uintptr _context = 0;
|
|
||||||
bool _blocking = false;
|
|
||||||
bool _flush = false;
|
|
||||||
string _format = "Default";
|
|
||||||
bool _smooth = false;
|
|
||||||
string _shader = "";
|
|
||||||
|
|
||||||
function<void (uint, uint)> _onUpdate;
|
|
||||||
};
|
|
|
@ -21,46 +21,36 @@
|
||||||
#error "ruby::OpenGL2: unsupported platform"
|
#error "ruby::OpenGL2: unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct VideoGLX2 : Video {
|
struct VideoGLX2 : VideoDriver {
|
||||||
VideoGLX2() { initialize(); }
|
VideoGLX2& self;
|
||||||
|
|
||||||
|
VideoGLX2(Video& super) : VideoDriver(super), self(*this) {}
|
||||||
~VideoGLX2() { terminate(); }
|
~VideoGLX2() { terminate(); }
|
||||||
|
|
||||||
auto driver() -> string override { return "OpenGL2"; }
|
auto create() -> bool {
|
||||||
|
super.setFormat("RGB24");
|
||||||
|
return initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto driverName() -> string override { return "OpenGL2"; }
|
||||||
auto ready() -> bool override { return _ready; }
|
auto ready() -> bool override { return _ready; }
|
||||||
|
|
||||||
auto hasContext() -> bool override { return true; }
|
auto hasContext() -> bool override { return true; }
|
||||||
auto hasBlocking() -> bool override { return true; }
|
auto hasBlocking() -> bool override { return true; }
|
||||||
auto hasFlush() -> bool override { return true; }
|
auto hasFlush() -> bool override { return true; }
|
||||||
auto hasFormat() -> bool override { return true; }
|
auto hasFormats() -> vector<string> override { return {"RGB24"}; }
|
||||||
auto hasSmooth() -> bool override { return true; }
|
auto hasSmooth() -> bool override { return true; }
|
||||||
|
|
||||||
auto availableFormats() -> vector<string> override {
|
|
||||||
return {"RGB24", "RGB30"};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setContext(uintptr context) -> bool override {
|
auto setContext(uintptr context) -> bool override {
|
||||||
if(context == Video::context()) return true;
|
|
||||||
if(!Video::setContext(context)) return false;
|
|
||||||
return initialize();
|
return initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setBlocking(bool blocking) -> bool override {
|
auto setBlocking(bool blocking) -> bool override {
|
||||||
if(blocking == Video::blocking()) return true;
|
|
||||||
if(!Video::setBlocking(blocking)) return false;
|
|
||||||
if(glXSwapInterval) glXSwapInterval(blocking);
|
if(glXSwapInterval) glXSwapInterval(blocking);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setFlush(bool flush) -> bool override {
|
|
||||||
if(flush == Video::flush()) return true;
|
|
||||||
if(!Video::setFlush(flush)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setFormat(string format) -> bool override {
|
auto setFormat(string format) -> bool override {
|
||||||
if(format == Video::format()) return true;
|
|
||||||
if(!Video::setFormat(format)) return false;
|
|
||||||
|
|
||||||
if(format == "RGB24") {
|
if(format == "RGB24") {
|
||||||
_glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
|
_glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||||
return initialize();
|
return initialize();
|
||||||
|
@ -74,12 +64,6 @@ struct VideoGLX2 : Video {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto setSmooth(bool smooth) -> bool override {
|
|
||||||
if(smooth == Video::smooth()) return true;
|
|
||||||
if(!Video::setSmooth(smooth)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto clear() -> void override {
|
auto clear() -> void override {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
memory::fill<uint32_t>(_glBuffer, _glWidth * _glHeight);
|
memory::fill<uint32_t>(_glBuffer, _glWidth * _glHeight);
|
||||||
|
@ -90,21 +74,17 @@ struct VideoGLX2 : Video {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||||
if(!ready()) return false;
|
|
||||||
if(width != _width || height != _height) resize(width, height);
|
if(width != _width || height != _height) resize(width, height);
|
||||||
pitch = _glWidth * sizeof(uint32_t);
|
pitch = _glWidth * sizeof(uint32_t);
|
||||||
return data = _glBuffer;
|
return data = _glBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto release() -> void override {
|
auto release() -> void override {
|
||||||
if(!ready()) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output() -> void override {
|
auto output() -> void override {
|
||||||
if(!ready()) return;
|
|
||||||
|
|
||||||
XWindowAttributes parent, child;
|
XWindowAttributes parent, child;
|
||||||
XGetWindowAttributes(_display, (Window)_context, &parent);
|
XGetWindowAttributes(_display, (Window)self.context, &parent);
|
||||||
XGetWindowAttributes(_display, _window, &child);
|
XGetWindowAttributes(_display, _window, &child);
|
||||||
if(child.width != parent.width || child.height != parent.height) {
|
if(child.width != parent.width || child.height != parent.height) {
|
||||||
XResizeWindow(_display, _window, parent.width, parent.height);
|
XResizeWindow(_display, _window, parent.width, parent.height);
|
||||||
|
@ -112,8 +92,8 @@ struct VideoGLX2 : Video {
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _smooth ? GL_LINEAR : GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, self.smooth ? GL_LINEAR : GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _smooth ? GL_LINEAR : GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, self.smooth ? GL_LINEAR : GL_NEAREST);
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
@ -139,7 +119,7 @@ struct VideoGLX2 : Video {
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
|
if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
|
||||||
if(flush()) glFinish();
|
if(self.flush) glFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto poll() -> void override {
|
auto poll() -> void override {
|
||||||
|
@ -149,7 +129,7 @@ struct VideoGLX2 : Video {
|
||||||
if(event.type == Expose) {
|
if(event.type == Expose) {
|
||||||
XWindowAttributes attributes;
|
XWindowAttributes attributes;
|
||||||
XGetWindowAttributes(_display, _window, &attributes);
|
XGetWindowAttributes(_display, _window, &attributes);
|
||||||
doUpdate(attributes.width, attributes.height);
|
super.doUpdate(attributes.width, attributes.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,9 +137,9 @@ struct VideoGLX2 : Video {
|
||||||
private:
|
private:
|
||||||
auto initialize() -> bool {
|
auto initialize() -> bool {
|
||||||
terminate();
|
terminate();
|
||||||
if(!_context) return false;
|
if(!self.context) return false;
|
||||||
|
|
||||||
_display = XOpenDisplay(0);
|
_display = XOpenDisplay(nullptr);
|
||||||
_screen = DefaultScreen(_display);
|
_screen = DefaultScreen(_display);
|
||||||
|
|
||||||
int versionMajor = 0, versionMinor = 0;
|
int versionMajor = 0, versionMinor = 0;
|
||||||
|
@ -167,11 +147,11 @@ private:
|
||||||
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
||||||
|
|
||||||
XWindowAttributes windowAttributes;
|
XWindowAttributes windowAttributes;
|
||||||
XGetWindowAttributes(_display, (Window)_context, &windowAttributes);
|
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
|
||||||
|
|
||||||
int redDepth = Video::format() == "RGB30" ? 10 : 8;
|
int redDepth = self.format == "RGB30" ? 10 : 8;
|
||||||
int greenDepth = Video::format() == "RGB30" ? 10 : 8;
|
int greenDepth = self.format == "RGB30" ? 10 : 8;
|
||||||
int blueDepth = Video::format() == "RGB30" ? 10 : 8;
|
int blueDepth = self.format == "RGB30" ? 10 : 8;
|
||||||
|
|
||||||
int attributeList[] = {
|
int attributeList[] = {
|
||||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
|
@ -192,7 +172,7 @@ private:
|
||||||
XSetWindowAttributes attributes = {};
|
XSetWindowAttributes attributes = {};
|
||||||
attributes.colormap = _colormap;
|
attributes.colormap = _colormap;
|
||||||
attributes.border_pixel = 0;
|
attributes.border_pixel = 0;
|
||||||
_window = XCreateWindow(_display, (Window)_context, 0, 0, windowAttributes.width, windowAttributes.height,
|
_window = XCreateWindow(_display, (Window)self.context, 0, 0, windowAttributes.width, windowAttributes.height,
|
||||||
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
|
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
|
||||||
XSelectInput(_display, _window, ExposureMask);
|
XSelectInput(_display, _window, ExposureMask);
|
||||||
XSetWindowBackground(_display, _window, 0);
|
XSetWindowBackground(_display, _window, 0);
|
||||||
|
@ -210,7 +190,7 @@ private:
|
||||||
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
||||||
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
|
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
|
||||||
|
|
||||||
if(glXSwapInterval) glXSwapInterval(_blocking);
|
if(glXSwapInterval) glXSwapInterval(self.blocking);
|
||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
glXGetConfig(_display, vi, GLX_DOUBLEBUFFER, &value);
|
glXGetConfig(_display, vi, GLX_DOUBLEBUFFER, &value);
|
||||||
|
|
|
@ -37,103 +37,173 @@
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Video::setExclusive(bool exclusive) -> bool {
|
auto Video::setExclusive(bool exclusive) -> bool {
|
||||||
_exclusive = exclusive;
|
if(driver->exclusive == exclusive) return true;
|
||||||
|
if(!driver->hasExclusive()) return false;
|
||||||
|
if(!driver->setExclusive(driver->exclusive = exclusive)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setContext(uintptr context) -> bool {
|
auto Video::setContext(uintptr context) -> bool {
|
||||||
_context = context;
|
if(driver->context == context) return true;
|
||||||
|
if(!driver->hasContext()) return false;
|
||||||
|
if(!driver->setContext(driver->context = context)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setBlocking(bool blocking) -> bool {
|
auto Video::setBlocking(bool blocking) -> bool {
|
||||||
_blocking = blocking;
|
if(driver->blocking == blocking) return true;
|
||||||
|
if(!driver->hasBlocking()) return false;
|
||||||
|
if(!driver->setBlocking(driver->blocking = blocking)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setFlush(bool flush) -> bool {
|
auto Video::setFlush(bool flush) -> bool {
|
||||||
_flush = flush;
|
if(driver->flush == flush) return true;
|
||||||
|
if(!driver->hasFlush()) return false;
|
||||||
|
if(!driver->setFlush(driver->flush = flush)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setFormat(string format) -> bool {
|
auto Video::setFormat(string format) -> bool {
|
||||||
_format = format;
|
if(driver->format == format) return true;
|
||||||
|
if(!driver->hasFormat(format)) return false;
|
||||||
|
if(!driver->setFormat(driver->format = format)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setSmooth(bool smooth) -> bool {
|
auto Video::setSmooth(bool smooth) -> bool {
|
||||||
_smooth = smooth;
|
if(driver->smooth == smooth) return true;
|
||||||
|
if(!driver->hasSmooth()) return false;
|
||||||
|
if(!driver->setSmooth(driver->smooth = smooth)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setShader(string shader) -> bool {
|
auto Video::setShader(string shader) -> bool {
|
||||||
_shader = shader;
|
if(driver->shader == shader) return true;
|
||||||
|
if(!driver->hasShader()) return false;
|
||||||
|
if(!driver->setShader(driver->shader = shader)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
auto Video::clear() -> void {
|
||||||
|
return driver->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Video::acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
|
return driver->acquire(data, pitch, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Video::release() -> void {
|
||||||
|
return driver->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Video::output() -> void {
|
||||||
|
return driver->output();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Video::poll() -> void {
|
||||||
|
return driver->poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
auto Video::onUpdate(const function<void (uint, uint)>& onUpdate) -> void {
|
auto Video::onUpdate(const function<void (uint, uint)>& onUpdate) -> void {
|
||||||
_onUpdate = onUpdate;
|
update = onUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::doUpdate(uint width, uint height) -> void {
|
auto Video::doUpdate(uint width, uint height) -> void {
|
||||||
if(_onUpdate) return _onUpdate(width, height);
|
if(update) return update(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
//protected functions
|
//
|
||||||
|
|
||||||
//static functions
|
auto Video::create(string driver) -> bool {
|
||||||
|
reset();
|
||||||
auto Video::create(string driver) -> Video* {
|
|
||||||
Video* video = nullptr;
|
|
||||||
if(!driver) driver = optimalDriver();
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(VIDEO_CGL)
|
#if defined(VIDEO_CGL)
|
||||||
if(driver == "OpenGL") video = new VideoCGL;
|
if(driver == "OpenGL") self.driver = new VideoCGL(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECT3D)
|
#if defined(VIDEO_DIRECT3D)
|
||||||
if(driver == "Direct3D") video = new VideoDirect3D;
|
if(driver == "Direct3D") self.driver = new VideoDirect3D(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECTDRAW)
|
#if defined(VIDEO_DIRECTDRAW)
|
||||||
if(driver == "DirectDraw") video = new VideoDirectDraw;
|
if(driver == "DirectDraw") self.driver = new VideoDirectDraw(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GDI)
|
#if defined(VIDEO_GDI)
|
||||||
if(driver == "GDI") video = new VideoGDI;
|
if(driver == "GDI") self.driver = new VideoGDI(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GLX)
|
#if defined(VIDEO_GLX)
|
||||||
if(driver == "OpenGL") video = new VideoGLX;
|
if(driver == "OpenGL") self.driver = new VideoGLX(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GLX2)
|
#if defined(VIDEO_GLX2)
|
||||||
if(driver == "OpenGL2") video = new VideoGLX2;
|
if(driver == "OpenGL2") self.driver = new VideoGLX2(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_WGL)
|
#if defined(VIDEO_WGL)
|
||||||
if(driver == "OpenGL") video = new VideoWGL;
|
if(driver == "OpenGL") self.driver = new VideoWGL(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_XSHM)
|
#if defined(VIDEO_XSHM)
|
||||||
if(driver == "XShm") video = new VideoXShm;
|
if(driver == "XShm") self.driver = new VideoXShm(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_XVIDEO)
|
#if defined(VIDEO_XVIDEO)
|
||||||
if(driver == "XVideo") video = new VideoXVideo;
|
if(driver == "XVideo") self.driver = new VideoXVideo(*this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!video) video = new Video;
|
if(!self.driver) self.driver = new VideoDriver(*this);
|
||||||
|
|
||||||
video->_exclusive = video->exclusive();
|
return self.driver->create();
|
||||||
video->_context = video->context();
|
}
|
||||||
video->_blocking = video->blocking();
|
|
||||||
video->_flush = video->flush();
|
|
||||||
video->_format = video->defaultFormat();
|
|
||||||
video->_smooth = video->smooth();
|
|
||||||
video->_shader = video->shader();
|
|
||||||
|
|
||||||
return video;
|
auto Video::hasDrivers() -> vector<string> {
|
||||||
|
return {
|
||||||
|
|
||||||
|
#if defined(VIDEO_WGL)
|
||||||
|
"OpenGL",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_DIRECT3D)
|
||||||
|
"Direct3D",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_DIRECTDRAW)
|
||||||
|
"DirectDraw",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GDI)
|
||||||
|
"GDI",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_CGL)
|
||||||
|
"OpenGL",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GLX)
|
||||||
|
"OpenGL",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GLX2)
|
||||||
|
"OpenGL2",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_XVIDEO)
|
||||||
|
"XVideo",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_XSHM)
|
||||||
|
"XShm",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"None"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::optimalDriver() -> string {
|
auto Video::optimalDriver() -> string {
|
||||||
|
@ -184,46 +254,4 @@ auto Video::safestDriver() -> string {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::availableDrivers() -> vector<string> {
|
|
||||||
return {
|
|
||||||
|
|
||||||
#if defined(VIDEO_WGL)
|
|
||||||
"OpenGL",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECT3D)
|
|
||||||
"Direct3D",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECTDRAW)
|
|
||||||
"DirectDraw",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_GDI)
|
|
||||||
"GDI",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_CGL)
|
|
||||||
"OpenGL",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_GLX)
|
|
||||||
"OpenGL",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_GLX2)
|
|
||||||
"OpenGL2",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_XVIDEO)
|
|
||||||
"XVideo",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VIDEO_XSHM)
|
|
||||||
"XShm",
|
|
||||||
#endif
|
|
||||||
|
|
||||||
"None"};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
struct Video;
|
||||||
|
|
||||||
|
struct VideoDriver {
|
||||||
|
VideoDriver(Video& super) : super(super) {}
|
||||||
|
virtual ~VideoDriver() = default;
|
||||||
|
|
||||||
|
virtual auto create() -> bool { return true; }
|
||||||
|
virtual auto driverName() -> string { return "None"; }
|
||||||
|
virtual auto ready() -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto hasExclusive() -> bool { return false; }
|
||||||
|
virtual auto hasContext() -> bool { return false; }
|
||||||
|
virtual auto hasBlocking() -> bool { return false; }
|
||||||
|
virtual auto hasFlush() -> bool { return false; }
|
||||||
|
virtual auto hasFormats() -> vector<string> { return {"RGB24"}; }
|
||||||
|
virtual auto hasSmooth() -> bool { return false; }
|
||||||
|
virtual auto hasShader() -> bool { return false; }
|
||||||
|
|
||||||
|
auto hasFormat(string format) -> bool { return (bool)hasFormats().find(format); }
|
||||||
|
|
||||||
|
virtual auto setExclusive(bool exclusive) -> bool { return true; }
|
||||||
|
virtual auto setContext(uintptr context) -> bool { return true; }
|
||||||
|
virtual auto setBlocking(bool blocking) -> bool { return true; }
|
||||||
|
virtual auto setFlush(bool flush) -> bool { return true; }
|
||||||
|
virtual auto setFormat(string format) -> bool { return true; }
|
||||||
|
virtual auto setSmooth(bool smooth) -> bool { return true; }
|
||||||
|
virtual auto setShader(string shader) -> bool { return true; }
|
||||||
|
|
||||||
|
virtual auto clear() -> void {}
|
||||||
|
virtual auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
||||||
|
virtual auto release() -> void {}
|
||||||
|
virtual auto output() -> void {}
|
||||||
|
virtual auto poll() -> void {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Video& super;
|
||||||
|
friend class Video;
|
||||||
|
|
||||||
|
bool exclusive = false;
|
||||||
|
uintptr context = 0;
|
||||||
|
bool blocking = false;
|
||||||
|
bool flush = false;
|
||||||
|
string format = "RGB24";
|
||||||
|
bool smooth = false;
|
||||||
|
string shader = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Video {
|
||||||
|
static auto hasDrivers() -> vector<string>;
|
||||||
|
static auto hasDriver(string driver) -> bool { return (bool)hasDrivers().find(driver); }
|
||||||
|
static auto optimalDriver() -> string;
|
||||||
|
static auto safestDriver() -> string;
|
||||||
|
|
||||||
|
Video() : self(*this) {}
|
||||||
|
explicit operator bool() const { return (bool)driver; }
|
||||||
|
auto reset() -> void { driver.reset(); }
|
||||||
|
auto create(string driver = "") -> bool;
|
||||||
|
auto driverName() -> string { return driver->driverName(); }
|
||||||
|
auto ready() -> bool { return driver->ready(); }
|
||||||
|
|
||||||
|
auto hasExclusive() -> bool { return driver->hasExclusive(); }
|
||||||
|
auto hasContext() -> bool { return driver->hasContext(); }
|
||||||
|
auto hasBlocking() -> bool { return driver->hasBlocking(); }
|
||||||
|
auto hasFlush() -> bool { return driver->hasFlush(); }
|
||||||
|
auto hasFormats() -> vector<string> { return driver->hasFormats(); }
|
||||||
|
auto hasSmooth() -> bool { return driver->hasSmooth(); }
|
||||||
|
auto hasShader() -> bool { return driver->hasShader(); }
|
||||||
|
|
||||||
|
auto hasFormat(string format) -> bool { return driver->hasFormat(format); }
|
||||||
|
|
||||||
|
auto exclusive() -> bool { return driver->exclusive; }
|
||||||
|
auto context() -> uintptr { return driver->context; }
|
||||||
|
auto blocking() -> bool { return driver->blocking; }
|
||||||
|
auto flush() -> bool { return driver->flush; }
|
||||||
|
auto format() -> string { return driver->format; }
|
||||||
|
auto smooth() -> bool { return driver->smooth; }
|
||||||
|
auto shader() -> string { return driver->shader; }
|
||||||
|
|
||||||
|
auto setExclusive(bool exclusive) -> bool;
|
||||||
|
auto setContext(uintptr context) -> bool;
|
||||||
|
auto setBlocking(bool blocking) -> bool;
|
||||||
|
auto setFlush(bool flush) -> bool;
|
||||||
|
auto setFormat(string format) -> bool;
|
||||||
|
auto setSmooth(bool smooth) -> bool;
|
||||||
|
auto setShader(string shader) -> bool;
|
||||||
|
|
||||||
|
auto clear() -> void;
|
||||||
|
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool;
|
||||||
|
auto release() -> void;
|
||||||
|
auto output() -> void;
|
||||||
|
auto poll() -> void;
|
||||||
|
|
||||||
|
auto onUpdate(const function<void (uint, uint)>&) -> void;
|
||||||
|
auto doUpdate(uint width, uint height) -> void;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Video& self;
|
||||||
|
unique_pointer<VideoDriver> driver;
|
||||||
|
function<void (uint, uint)> update;
|
||||||
|
};
|
|
@ -8,38 +8,28 @@
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
#include <X11/extensions/XShm.h>
|
#include <X11/extensions/XShm.h>
|
||||||
|
|
||||||
struct VideoXShm : Video {
|
struct VideoXShm : VideoDriver {
|
||||||
VideoXShm() { initialize(); }
|
VideoXShm& self;
|
||||||
|
|
||||||
|
VideoXShm(Video& super) : VideoDriver(super), self(*this) {}
|
||||||
~VideoXShm() { terminate(); }
|
~VideoXShm() { terminate(); }
|
||||||
|
|
||||||
auto driver() -> string override { return "XShm"; }
|
auto create() -> bool {
|
||||||
|
return initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto driverName() -> string override { return "XShm"; }
|
||||||
auto ready() -> bool override { return _ready; }
|
auto ready() -> bool override { return _ready; }
|
||||||
|
|
||||||
auto hasContext() -> bool override { return true; }
|
auto hasContext() -> bool override { return true; }
|
||||||
auto hasSmooth() -> bool override { return true; }
|
auto hasSmooth() -> bool override { return true; }
|
||||||
|
|
||||||
auto availableFormats() -> vector<string> { return {"RGB24"}; }
|
auto hasFormats() -> vector<string> override { return {"RGB24"}; }
|
||||||
|
|
||||||
auto exclusive() -> bool override { return false; }
|
auto setContext(uintptr context) -> bool override { return initialize(); }
|
||||||
auto blocking() -> bool override { return false; }
|
auto setSmooth(bool smooth) -> bool override { return true; }
|
||||||
auto flush() -> bool override { return false; }
|
|
||||||
auto format() -> string override { return "RGB24"; }
|
|
||||||
auto shader() -> string override { return ""; }
|
|
||||||
|
|
||||||
auto setContext(uintptr context) -> bool override {
|
|
||||||
if(context == this->context()) return true;
|
|
||||||
if(!Video::setContext(context)) return false;
|
|
||||||
return initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto setSmooth(bool smooth) -> bool override {
|
|
||||||
if(smooth == this->smooth()) return true;
|
|
||||||
if(!Video::setSmooth(smooth)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto clear() -> void override {
|
auto clear() -> void override {
|
||||||
if(!ready()) return;
|
|
||||||
auto dp = _inputBuffer;
|
auto dp = _inputBuffer;
|
||||||
uint length = _inputWidth * _inputHeight;
|
uint length = _inputWidth * _inputHeight;
|
||||||
while(length--) *dp++ = 255u << 24;
|
while(length--) *dp++ = 255u << 24;
|
||||||
|
@ -47,7 +37,6 @@ struct VideoXShm : Video {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
|
||||||
if(!ready()) return false;
|
|
||||||
if(!_inputBuffer || _inputWidth != width || _inputHeight != height) {
|
if(!_inputBuffer || _inputWidth != width || _inputHeight != height) {
|
||||||
if(_inputBuffer) delete[] _inputBuffer;
|
if(_inputBuffer) delete[] _inputBuffer;
|
||||||
_inputWidth = width;
|
_inputWidth = width;
|
||||||
|
@ -61,11 +50,9 @@ struct VideoXShm : Video {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto release() -> void override {
|
auto release() -> void override {
|
||||||
if(!ready()) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output() -> void override {
|
auto output() -> void override {
|
||||||
if(!ready()) return;
|
|
||||||
size();
|
size();
|
||||||
|
|
||||||
float xratio = (float)_inputWidth / (float)_outputWidth;
|
float xratio = (float)_inputWidth / (float)_outputWidth;
|
||||||
|
@ -79,7 +66,7 @@ struct VideoXShm : Video {
|
||||||
uint32_t* sp = _inputBuffer + (uint)ystep * _inputWidth;
|
uint32_t* sp = _inputBuffer + (uint)ystep * _inputWidth;
|
||||||
uint32_t* dp = _outputBuffer + y * _outputWidth;
|
uint32_t* dp = _outputBuffer + y * _outputWidth;
|
||||||
|
|
||||||
if(!_smooth) {
|
if(!self.smooth) {
|
||||||
for(uint x = 0; x < _outputWidth; x++) {
|
for(uint x = 0; x < _outputWidth; x++) {
|
||||||
*dp++ = 255u << 24 | sp[(uint)xstep];
|
*dp++ = 255u << 24 | sp[(uint)xstep];
|
||||||
xstep += xratio;
|
xstep += xratio;
|
||||||
|
@ -105,7 +92,7 @@ struct VideoXShm : Video {
|
||||||
if(event.type == Expose) {
|
if(event.type == Expose) {
|
||||||
XWindowAttributes attributes;
|
XWindowAttributes attributes;
|
||||||
XGetWindowAttributes(_display, _window, &attributes);
|
XGetWindowAttributes(_display, _window, &attributes);
|
||||||
doUpdate(attributes.width, attributes.height);
|
super.doUpdate(attributes.width, attributes.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,13 +100,13 @@ struct VideoXShm : Video {
|
||||||
private:
|
private:
|
||||||
auto initialize() -> bool {
|
auto initialize() -> bool {
|
||||||
terminate();
|
terminate();
|
||||||
if(!_context) return false;
|
if(!self.context) return false;
|
||||||
|
|
||||||
_display = XOpenDisplay(nullptr);
|
_display = XOpenDisplay(nullptr);
|
||||||
_screen = DefaultScreen(_display);
|
_screen = DefaultScreen(_display);
|
||||||
|
|
||||||
XWindowAttributes getAttributes;
|
XWindowAttributes getAttributes;
|
||||||
XGetWindowAttributes(_display, (Window)_context, &getAttributes);
|
XGetWindowAttributes(_display, (Window)self.context, &getAttributes);
|
||||||
_depth = getAttributes.depth;
|
_depth = getAttributes.depth;
|
||||||
_visual = getAttributes.visual;
|
_visual = getAttributes.visual;
|
||||||
//driver only supports 32-bit pixels
|
//driver only supports 32-bit pixels
|
||||||
|
@ -131,7 +118,7 @@ private:
|
||||||
|
|
||||||
XSetWindowAttributes setAttributes = {};
|
XSetWindowAttributes setAttributes = {};
|
||||||
setAttributes.border_pixel = 0;
|
setAttributes.border_pixel = 0;
|
||||||
_window = XCreateWindow(_display, (Window)_context,
|
_window = XCreateWindow(_display, (Window)self.context,
|
||||||
0, 0, 256, 256, 0,
|
0, 0, 256, 256, 0,
|
||||||
getAttributes.depth, InputOutput, getAttributes.visual,
|
getAttributes.depth, InputOutput, getAttributes.visual,
|
||||||
CWBorderPixel, &setAttributes
|
CWBorderPixel, &setAttributes
|
||||||
|
@ -160,7 +147,7 @@ private:
|
||||||
|
|
||||||
auto size() -> bool {
|
auto size() -> bool {
|
||||||
XWindowAttributes windowAttributes;
|
XWindowAttributes windowAttributes;
|
||||||
XGetWindowAttributes(_display, (Window)_context, &windowAttributes);
|
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
|
||||||
|
|
||||||
if(_outputBuffer && _outputWidth == windowAttributes.width && _outputHeight == windowAttributes.height) return true;
|
if(_outputBuffer && _outputWidth == windowAttributes.width && _outputHeight == windowAttributes.height) return true;
|
||||||
_outputWidth = windowAttributes.width;
|
_outputWidth = windowAttributes.width;
|
||||||
|
|
Loading…
Reference in New Issue