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:
Tim Allen
2018-07-31 12:23:12 +10:00
parent 5deba5cbc1
commit 212da0a966
39 changed files with 868 additions and 762 deletions

View File

@@ -12,9 +12,10 @@ ifeq ($(ruby),)
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.xlib input.udev
else ifeq ($(platform),bsd)
ruby += video.glx video.glx2 video.xvideo video.xshm
ruby += audio.oss audio.openal
ruby += input.sdl input.xlib
# ruby += video.glx video.glx2 video.xvideo video.xshm
ruby += video.glx2 video.xshm
ruby += audio.oss #audio.openal
ruby += input.sdl #input.xlib
endif
endif

View File

@@ -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;
};

View File

@@ -1,3 +1,4 @@
#include <nall/windows/registry.hpp>
#include "asio.hpp"
struct AudioASIO : Audio {

View File

@@ -41,126 +41,190 @@
namespace ruby {
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;
}
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;
}
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;
}
auto Audio::setBlocking(bool blocking) -> bool {
_blocking = blocking;
Audio::setFrequency(frequency());
if(driver->blocking == blocking) return true;
if(!driver->hasBlocking()) return false;
if(!driver->setBlocking(driver->blocking = blocking)) return false;
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
return true;
}
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;
}
auto Audio::setChannels(uint channels) -> bool {
_channels = channels;
_resamplers.reset();
_resamplers.resize(channels);
Audio::setFrequency(frequency());
if(driver->channels == channels) return true;
if(!driver->hasChannels(channels)) return false;
if(!driver->setChannels(driver->channels = channels)) return false;
resamplers.reset();
resamplers.resize(channels);
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
return true;
}
auto Audio::setFrequency(double frequency) -> bool {
_frequency = frequency;
for(auto& resampler : _resamplers) {
resampler.reset(frequency, frequency);
}
auto Audio::setFrequency(uint frequency) -> bool {
if(driver->frequency == frequency) return true;
if(!driver->hasFrequency(frequency)) return false;
if(!driver->setFrequency(driver->frequency = frequency)) return false;
for(auto& resampler : resamplers) resampler.reset(driver->frequency);
return true;
}
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;
}
//protected functions
//
auto Audio::pending() -> bool {
return _resamplers && _resamplers[0].pending();
auto Audio::clear() -> void {
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;
double fillLevel = level();
double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * frequency();
for(auto& resampler : _resamplers) {
double fillLevel = driver->level();
double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * driver->frequency;
for(auto& resampler : resamplers) {
resampler.setInputFrequency(dynamicFrequency);
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* {
Audio* audio = nullptr;
auto Audio::create(string driver) -> bool {
reset();
if(!driver) driver = optimalDriver();
#if defined(AUDIO_ALSA)
if(driver == "ALSA") audio = new AudioALSA;
if(driver == "ALSA") self.driver = new AudioALSA(*this);
#endif
#if defined(AUDIO_AO)
if(driver == "libao") audio = new AudioAO;
if(driver == "libao") self.driver = new AudioAO(*this);
#endif
#if defined(AUDIO_ASIO)
if(driver == "ASIO") audio = new AudioASIO;
if(driver == "ASIO") self.driver = new AudioASIO(*this);
#endif
#if defined(AUDIO_DIRECTSOUND)
if(driver == "DirectSound") audio = new AudioDirectSound;
if(driver == "DirectSound") self.driver = new AudioDirectSound(*this);
#endif
#if defined(AUDIO_OPENAL)
if(driver == "OpenAL") audio = new AudioOpenAL;
if(driver == "OpenAL") self.driver = new AudioOpenAL(*this);
#endif
#if defined(AUDIO_OSS)
if(driver == "OSS") audio = new AudioOSS;
if(driver == "OSS") self.driver = new AudioOSS(*this);
#endif
#if defined(AUDIO_PULSEAUDIO)
if(driver == "PulseAudio") audio = new AudioPulseAudio;
if(driver == "PulseAudio") self.driver = new AudioPulseAudio(*this);
#endif
#if defined(AUDIO_PULSEAUDIOSIMPLE)
if(driver == "PulseAudioSimple") audio = new AudioPulseAudioSimple;
if(driver == "PulseAudioSimple") self.driver = new AudioPulseAudioSimple(*this);
#endif
#if defined(AUDIO_WASAPI)
if(driver == "WASAPI") audio = new AudioWASAPI;
if(driver == "WASAPI") self.driver = new AudioWASAPI(*this);
#endif
#if defined(AUDIO_XAUDIO2)
if(driver == "XAudio2") audio = new AudioXAudio2;
if(driver == "XAudio2") self.driver = new AudioXAudio2(*this);
#endif
if(!audio) audio = new Audio;
if(!self.driver) self.driver = new AudioDriver(*this);
audio->_exclusive = audio->exclusive();
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 self.driver->create();
}
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 {
@@ -215,50 +279,4 @@ auto Audio::safestDriver() -> string {
#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"};
}
}

105
ruby/audio/audio.hpp Normal file
View File

@@ -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;
};

View File

@@ -1,8 +1,15 @@
#include <dsound.h>
struct AudioDirectSound : Audio {
AudioDirectSound() { initialize(); }
~AudioDirectSound() { terminate(); }
AudioDirectSound() {
Audio::setFrequency(48000.0);
Audio::setLatency(40);
initialize();
}
~AudioDirectSound() {
terminate();
}
auto driver() -> string override { return "DirectSound"; }
auto ready() -> bool override { return _ready; }
@@ -19,6 +26,9 @@ struct AudioDirectSound : Audio {
return {40, 60, 80, 100};
}
auto defaultFrequency() -> double override { return 48000.0; }
auto defaultLatency() -> uint override { return 40; }
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;

View File

@@ -7,8 +7,17 @@
#endif
struct AudioOpenAL : Audio {
AudioOpenAL() { initialize(); }
~AudioOpenAL() { terminate(); }
AudioOpenAL() {
Audio::setDevice(availableDevices().first());
Audio::setChannels(2);
Audio::setFrequency(48000.0);
Audio::setLatency(20);
initialize();
}
~AudioOpenAL() {
terminate();
}
auto driver() -> string override { return "OpenAL"; }
auto ready() -> bool override { return _ready; }
@@ -21,7 +30,12 @@ struct AudioOpenAL : Audio {
auto availableDevices() -> vector<string> override {
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;
}
@@ -37,38 +51,35 @@ struct AudioOpenAL : Audio {
return {20, 40, 60, 80, 100};
}
auto context() -> uintptr override { return 0; }
auto dynamic() -> bool override { return false; }
auto setDevice(string device) -> bool override {
if(device == this->device()) return true;
if(device == Audio::device()) return true;
if(!Audio::setDevice(device)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == this->blocking()) return true;
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
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 {
if(frequency == this->frequency()) return true;
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
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(ready()) updateLatency();
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[1] * 32767.0) << 16;
if(++_bufferLength < _bufferSize) return;
@@ -171,20 +182,6 @@ private:
_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 {
delete[] _buffer;
_bufferSize = _frequency * _latency / 1000.0 + 0.5;

View File

@@ -13,77 +13,54 @@
#define SNDCTL_DSP_POLICY _IOW('P', 45, int)
#endif
struct AudioOSS : Audio {
AudioOSS() { initialize(); }
struct AudioOSS : AudioDriver {
AudioOSS& self;
AudioOSS(Audio& super) : AudioDriver(super), self(*this) {}
~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 hasDevice() -> bool override { return true; }
auto hasDynamic() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasChannels() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto hasDynamic() -> bool override { return true; }
auto availableDevices() -> vector<string> override {
auto hasDevices() -> vector<string> override {
vector<string> devices;
devices.append("/dev/dsp");
for(auto& device : directory::files("/dev/", "dsp?*")) devices.append(string{"/dev/", device});
return devices;
}
auto defaultChannels() -> uint override { return 2; }
auto defaultFrequency() -> double override { return 48000.0; }
auto defaultLatency() -> uint override { return 3; }
auto availableChannels() -> vector<uint> override {
auto hasChannels() -> vector<uint> override {
return {1, 2};
}
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
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};
}
auto setDevice(string device) -> bool override {
if(device == Audio::device()) return true;
if(!Audio::setDevice(device)) return false;
return initialize();
}
auto setDevice(string device) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { return updateBlocking(); }
auto setChannels(uint channels) -> bool override { return initialize(); }
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
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 clear() -> void override {
buffer.resize(64);
}
auto level() -> double override {
@@ -95,18 +72,9 @@ struct AudioOSS : Audio {
auto output(const double samples[]) -> void override {
if(!ready()) return;
if(!_dynamic) {
for(uint n : range(channels())) {
sample(sclamp<16>(samples[n] * 32767.0));
}
} 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);
}
}
for(uint n : range(self.channels)) {
buffer.write(sclamp<16>(samples[n] * 32767.0));
if(buffer.full()) write(_fd, buffer.data(), buffer.size<uint8_t>());
}
}
@@ -114,23 +82,20 @@ private:
auto initialize() -> bool {
terminate();
if(!availableDevices().find(_device)) {
Audio::setDevice(availableDevices().left());
}
Audio::setChannels(channels());
if(!hasDevices().find(self.device)) self.device = hasDevices().first();
_fd = open(_device, O_WRONLY, O_NONBLOCK);
_fd = open(self.device, O_WRONLY, O_NONBLOCK);
if(_fd < 0) return false;
int cooked = 1;
ioctl(_fd, SNDCTL_DSP_COOKEDMODE, &cooked);
//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);
int channels = _channels;
int channels = self.channels;
ioctl(_fd, SNDCTL_DSP_CHANNELS, &channels);
ioctl(_fd, SNDCTL_DSP_SETFMT, &_format);
int frequency = _frequency;
int frequency = self.frequency;
ioctl(_fd, SNDCTL_DSP_SPEED, &frequency);
updateBlocking();
audio_buf_info info;
@@ -150,23 +115,14 @@ private:
if(!ready()) return false;
auto flags = fcntl(_fd, F_GETFL);
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);
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 _format = AFMT_S16_LE;
int _bufferSize = 1;
uint _outputOffset = 0;
uint16_t _outputBuffer[64];
queue<int16_t> buffer;
};

View File

@@ -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;
};

View File

@@ -25,55 +25,107 @@
namespace ruby {
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;
}
//
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 {
_onChange = onChange;
change = onChange;
}
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) -> Input* {
Input* input = nullptr;
auto Input::create(string driver) -> bool {
reset();
if(!driver) driver = optimalDriver();
#if defined(INPUT_WINDOWS)
if(driver == "Windows") input = new InputWindows;
if(driver == "Windows") self.driver = new InputWindows(*this);
#endif
#if defined(INPUT_QUARTZ)
if(driver == "Quartz") input = new InputQuartz;
if(driver == "Quartz") self.driver = new InputQuartz(*this);
#endif
#if defined(INPUT_CARBON)
if(driver == "Carbon") input = new InputCarbon;
if(driver == "Carbon") self.driver = new InputCarbon(*this);
#endif
#if defined(INPUT_UDEV)
if(driver == "udev") input = new InputUdev;
if(driver == "udev") self.driver = new InputUdev(*this);
#endif
#if defined(INPUT_SDL)
if(driver == "SDL") input = new InputSDL;
if(driver == "SDL") self.driver = new InputSDL(*this);
#endif
#if defined(INPUT_XLIB)
if(driver == "Xlib") input = new InputXlib;
if(driver == "Xlib") self.driver = new InputXlib(*this);
#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 {
@@ -112,34 +164,4 @@ auto Input::safestDriver() -> string {
#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"};
}
}

60
ruby/input/input.hpp Normal file
View File

@@ -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;
};

View File

@@ -6,38 +6,32 @@
#include "mouse/xlib.cpp"
#include "joypad/sdl.cpp"
struct InputSDL : Input {
InputSDL() : _keyboard(*this), _mouse(*this), _joypad(*this) { initialize(); }
struct InputSDL : InputDriver {
InputSDL& self;
InputSDL(Input& super) : InputDriver(super), self(*this), keyboard(super), mouse(super), joypad(super) {}
~InputSDL() { terminate(); }
auto driver() -> string override { return "SDL"; }
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;
auto create() -> bool {
return initialize();
}
auto acquired() -> bool override {
return _mouse.acquired();
}
auto driverName() -> string override { return "SDL"; }
auto ready() -> bool override { return isReady; }
auto acquire() -> bool override {
return _mouse.acquire();
}
auto hasContext() -> bool override { return true; }
auto release() -> bool override {
return _mouse.release();
}
auto setContext(uintptr context) -> bool override { return initialize(); }
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 {
vector<shared_pointer<HID::Device>> devices;
_keyboard.poll(devices);
_mouse.poll(devices);
_joypad.poll(devices);
keyboard.poll(devices);
mouse.poll(devices);
joypad.poll(devices);
return devices;
}
@@ -48,23 +42,23 @@ struct InputSDL : Input {
private:
auto initialize() -> bool {
terminate();
if(!_context) return false;
if(!_keyboard.initialize()) return false;
if(!_mouse.initialize(_context)) return false;
if(!_joypad.initialize()) return false;
return _ready = true;
if(!self.context) return false;
if(!keyboard.initialize()) return false;
if(!mouse.initialize(self.context)) return false;
if(!joypad.initialize()) return false;
return isReady = true;
}
auto terminate() -> void {
_ready = false;
_keyboard.terminate();
_mouse.terminate();
_joypad.terminate();
isReady = false;
keyboard.terminate();
mouse.terminate();
joypad.terminate();
}
bool _ready = false;
bool isReady = false;
InputKeyboardXlib _keyboard;
InputMouseXlib _mouse;
InputJoypadSDL _joypad;
InputKeyboardXlib keyboard;
InputMouseXlib mouse;
InputJoypadSDL joypad;
};

View File

@@ -24,6 +24,6 @@ using namespace ruby;
#include <windows.h>
#endif
#include "video.cpp"
#include "audio.cpp"
#include "input.cpp"
#include <ruby/video/video.cpp>
#include <ruby/audio/audio.cpp>
#include <ruby/input/input.cpp>

View File

@@ -7,23 +7,27 @@
#include <nall/hid.hpp>
#include <nall/image.hpp>
#include <nall/matrix.hpp>
#include <nall/queue.hpp>
#include <nall/range.hpp>
#include <nall/set.hpp>
#include <nall/shared-pointer.hpp>
#include <nall/string.hpp>
#include <nall/unique-pointer.hpp>
#include <nall/vector.hpp>
#include <nall/dsp/resampler/cubic.hpp>
#include <nall/hash/crc32.hpp>
using nall::function;
using nall::queue;
using nall::shared_pointer;
using nall::string;
using nall::unique_pointer;
using nall::vector;
namespace ruby {
#include "video.hpp"
#include "audio.hpp"
#include "input.hpp"
#include <ruby/video/video.hpp>
#include <ruby/audio/audio.hpp>
#include <ruby/input/input.hpp>
}

View File

@@ -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;
};

View File

@@ -21,46 +21,36 @@
#error "ruby::OpenGL2: unsupported platform"
#endif
struct VideoGLX2 : Video {
VideoGLX2() { initialize(); }
struct VideoGLX2 : VideoDriver {
VideoGLX2& self;
VideoGLX2(Video& super) : VideoDriver(super), self(*this) {}
~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 hasContext() -> bool override { return true; }
auto hasBlocking() -> 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 availableFormats() -> vector<string> override {
return {"RGB24", "RGB30"};
}
auto setContext(uintptr context) -> bool override {
if(context == Video::context()) return true;
if(!Video::setContext(context)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Video::blocking()) return true;
if(!Video::setBlocking(blocking)) return false;
if(glXSwapInterval) glXSwapInterval(blocking);
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 {
if(format == Video::format()) return true;
if(!Video::setFormat(format)) return false;
if(format == "RGB24") {
_glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
return initialize();
@@ -74,12 +64,6 @@ struct VideoGLX2 : Video {
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 {
if(!ready()) return;
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 {
if(!ready()) return false;
if(width != _width || height != _height) resize(width, height);
pitch = _glWidth * sizeof(uint32_t);
return data = _glBuffer;
}
auto release() -> void override {
if(!ready()) return;
}
auto output() -> void override {
if(!ready()) return;
XWindowAttributes parent, child;
XGetWindowAttributes(_display, (Window)_context, &parent);
XGetWindowAttributes(_display, (Window)self.context, &parent);
XGetWindowAttributes(_display, _window, &child);
if(child.width != parent.width || child.height != 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_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _smooth ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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, self.smooth ? GL_LINEAR : GL_NEAREST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -139,7 +119,7 @@ struct VideoGLX2 : Video {
glFlush();
if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
if(flush()) glFinish();
if(self.flush) glFinish();
}
auto poll() -> void override {
@@ -149,7 +129,7 @@ struct VideoGLX2 : Video {
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
super.doUpdate(attributes.width, attributes.height);
}
}
}
@@ -157,9 +137,9 @@ struct VideoGLX2 : Video {
private:
auto initialize() -> bool {
terminate();
if(!_context) return false;
if(!self.context) return false;
_display = XOpenDisplay(0);
_display = XOpenDisplay(nullptr);
_screen = DefaultScreen(_display);
int versionMajor = 0, versionMinor = 0;
@@ -167,11 +147,11 @@ private:
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
XWindowAttributes windowAttributes;
XGetWindowAttributes(_display, (Window)_context, &windowAttributes);
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
int redDepth = Video::format() == "RGB30" ? 10 : 8;
int greenDepth = Video::format() == "RGB30" ? 10 : 8;
int blueDepth = Video::format() == "RGB30" ? 10 : 8;
int redDepth = self.format == "RGB30" ? 10 : 8;
int greenDepth = self.format == "RGB30" ? 10 : 8;
int blueDepth = self.format == "RGB30" ? 10 : 8;
int attributeList[] = {
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
@@ -192,7 +172,7 @@ private:
XSetWindowAttributes attributes = {};
attributes.colormap = _colormap;
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);
XSelectInput(_display, _window, ExposureMask);
XSetWindowBackground(_display, _window, 0);
@@ -210,7 +190,7 @@ private:
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
if(glXSwapInterval) glXSwapInterval(_blocking);
if(glXSwapInterval) glXSwapInterval(self.blocking);
int value = 0;
glXGetConfig(_display, vi, GLX_DOUBLEBUFFER, &value);

View File

@@ -37,103 +37,173 @@
namespace ruby {
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
//
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 {
_onUpdate = onUpdate;
update = onUpdate;
}
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) -> Video* {
Video* video = nullptr;
auto Video::create(string driver) -> bool {
reset();
if(!driver) driver = optimalDriver();
#if defined(VIDEO_CGL)
if(driver == "OpenGL") video = new VideoCGL;
if(driver == "OpenGL") self.driver = new VideoCGL(*this);
#endif
#if defined(VIDEO_DIRECT3D)
if(driver == "Direct3D") video = new VideoDirect3D;
if(driver == "Direct3D") self.driver = new VideoDirect3D(*this);
#endif
#if defined(VIDEO_DIRECTDRAW)
if(driver == "DirectDraw") video = new VideoDirectDraw;
if(driver == "DirectDraw") self.driver = new VideoDirectDraw(*this);
#endif
#if defined(VIDEO_GDI)
if(driver == "GDI") video = new VideoGDI;
if(driver == "GDI") self.driver = new VideoGDI(*this);
#endif
#if defined(VIDEO_GLX)
if(driver == "OpenGL") video = new VideoGLX;
if(driver == "OpenGL") self.driver = new VideoGLX(*this);
#endif
#if defined(VIDEO_GLX2)
if(driver == "OpenGL2") video = new VideoGLX2;
if(driver == "OpenGL2") self.driver = new VideoGLX2(*this);
#endif
#if defined(VIDEO_WGL)
if(driver == "OpenGL") video = new VideoWGL;
if(driver == "OpenGL") self.driver = new VideoWGL(*this);
#endif
#if defined(VIDEO_XSHM)
if(driver == "XShm") video = new VideoXShm;
if(driver == "XShm") self.driver = new VideoXShm(*this);
#endif
#if defined(VIDEO_XVIDEO)
if(driver == "XVideo") video = new VideoXVideo;
if(driver == "XVideo") self.driver = new VideoXVideo(*this);
#endif
if(!video) video = new Video;
if(!self.driver) self.driver = new VideoDriver(*this);
video->_exclusive = video->exclusive();
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 self.driver->create();
}
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 {
@@ -184,46 +254,4 @@ auto Video::safestDriver() -> string {
#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"};
}
}

100
ruby/video/video.hpp Normal file
View File

@@ -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;
};

View File

@@ -8,38 +8,28 @@
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
struct VideoXShm : Video {
VideoXShm() { initialize(); }
struct VideoXShm : VideoDriver {
VideoXShm& self;
VideoXShm(Video& super) : VideoDriver(super), self(*this) {}
~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 hasContext() -> 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 blocking() -> bool override { return false; }
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 setContext(uintptr context) -> bool override { return initialize(); }
auto setSmooth(bool smooth) -> bool override { return true; }
auto clear() -> void override {
if(!ready()) return;
auto dp = _inputBuffer;
uint length = _inputWidth * _inputHeight;
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 {
if(!ready()) return false;
if(!_inputBuffer || _inputWidth != width || _inputHeight != height) {
if(_inputBuffer) delete[] _inputBuffer;
_inputWidth = width;
@@ -61,11 +50,9 @@ struct VideoXShm : Video {
}
auto release() -> void override {
if(!ready()) return;
}
auto output() -> void override {
if(!ready()) return;
size();
float xratio = (float)_inputWidth / (float)_outputWidth;
@@ -79,7 +66,7 @@ struct VideoXShm : Video {
uint32_t* sp = _inputBuffer + (uint)ystep * _inputWidth;
uint32_t* dp = _outputBuffer + y * _outputWidth;
if(!_smooth) {
if(!self.smooth) {
for(uint x = 0; x < _outputWidth; x++) {
*dp++ = 255u << 24 | sp[(uint)xstep];
xstep += xratio;
@@ -105,7 +92,7 @@ struct VideoXShm : Video {
if(event.type == Expose) {
XWindowAttributes attributes;
XGetWindowAttributes(_display, _window, &attributes);
doUpdate(attributes.width, attributes.height);
super.doUpdate(attributes.width, attributes.height);
}
}
}
@@ -113,13 +100,13 @@ struct VideoXShm : Video {
private:
auto initialize() -> bool {
terminate();
if(!_context) return false;
if(!self.context) return false;
_display = XOpenDisplay(nullptr);
_screen = DefaultScreen(_display);
XWindowAttributes getAttributes;
XGetWindowAttributes(_display, (Window)_context, &getAttributes);
XGetWindowAttributes(_display, (Window)self.context, &getAttributes);
_depth = getAttributes.depth;
_visual = getAttributes.visual;
//driver only supports 32-bit pixels
@@ -131,7 +118,7 @@ private:
XSetWindowAttributes setAttributes = {};
setAttributes.border_pixel = 0;
_window = XCreateWindow(_display, (Window)_context,
_window = XCreateWindow(_display, (Window)self.context,
0, 0, 256, 256, 0,
getAttributes.depth, InputOutput, getAttributes.visual,
CWBorderPixel, &setAttributes
@@ -160,7 +147,7 @@ private:
auto size() -> bool {
XWindowAttributes windowAttributes;
XGetWindowAttributes(_display, (Window)_context, &windowAttributes);
XGetWindowAttributes(_display, (Window)self.context, &windowAttributes);
if(_outputBuffer && _outputWidth == windowAttributes.width && _outputHeight == windowAttributes.height) return true;
_outputWidth = windowAttributes.width;