* multi-monitor support
* improved pause/frame advance support
* added option to disable video dimming when idle
This commit is contained in:
byuu 2019-08-16 19:44:16 +09:00
parent 252f479b22
commit 0b088b6b55
68 changed files with 2167 additions and 1365 deletions

View file

@ -3,7 +3,6 @@
#include <nall/platform.hpp>
#include <nall/adaptive-array.hpp>
#include <nall/any.hpp>
#include <nall/bit-field.hpp>
#include <nall/chrono.hpp>
#include <nall/dl.hpp>
#include <nall/endian.hpp>
@ -30,7 +29,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "108.8";
static const string Version = "108.9";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org";

View file

@ -24,14 +24,14 @@ struct Readable {
memory::fill<T>(self.data, self.mask + 1, fill);
}
inline auto load(vfs::shared::file fp) -> void {
inline auto load(shared_pointer<vfs::file> fp) -> void {
fp->read(self.data, min(fp->size(), self.size * sizeof(T)));
for(uint address = self.size; address <= self.mask; address++) {
self.data[address] = self.data[mirror(address, self.size)];
}
}
inline auto save(vfs::shared::file fp) -> void {
inline auto save(shared_pointer<vfs::file> fp) -> void {
fp->write(self.data, self.size * sizeof(T));
}

View file

@ -24,14 +24,14 @@ struct Writable {
memory::fill<T>(self.data, self.mask + 1, fill);
}
inline auto load(vfs::shared::file fp) -> void {
inline auto load(shared_pointer<vfs::file> fp) -> void {
fp->read(self.data, min(fp->size(), self.size * sizeof(T)));
for(uint address = self.size; address <= self.mask; address++) {
self.data[address] = self.data[mirror(address, self.size)];
}
}
inline auto save(vfs::shared::file fp) -> void {
inline auto save(shared_pointer<vfs::file> fp) -> void {
fp->write(self.data, self.size * sizeof(T));
}

View file

@ -14,7 +14,7 @@ struct Platform {
};
virtual auto path(uint id) -> string { return ""; }
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; }
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> shared_pointer<vfs::file> { return {}; }
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
virtual auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void {}
virtual auto audioFrame(const float* samples, uint channels) -> void {}

View file

@ -34,22 +34,22 @@ struct Register {
};
struct SFR {
union {
uint16_t data = 0;
BooleanBitField<uint16_t, 15> irq; //interrupt flag
BooleanBitField<uint16_t, 12> b; //with flag
BooleanBitField<uint16_t, 11> ih; //immediate higher 8-bit flag
BooleanBitField<uint16_t, 10> il; //immediate lower 8-bit flag
BooleanBitField<uint16_t, 9> alt2; //alt2 instruction mode
BooleanBitField<uint16_t, 8> alt1; //alt1 instruction mode
BooleanBitField<uint16_t, 6> r; //ROM r14 read flag
BooleanBitField<uint16_t, 5> g; //go flag
BooleanBitField<uint16_t, 4> ov; //overflow flag
BooleanBitField<uint16_t, 3> s; //sign flag
BooleanBitField<uint16_t, 2> cy; //carry flag
BooleanBitField<uint16_t, 1> z; //zero flag
NaturalBitField<uint16_t, 9, 8> alt; //instruction mode (composite flag)
};
uint16_t data = 0;
BitField<16, 1> z {&data}; //zero flag
BitField<16, 2> cy {&data}; //carry flag
BitField<16, 3> s {&data}; //sign flag
BitField<16, 4> ov {&data}; //overflow flag
BitField<16, 5> g {&data}; //go flag
BitField<16, 6> r {&data}; //ROM r14 flag
BitField<16, 8> alt1{&data}; //alt1 instruction mode
BitField<16, 9> alt2{&data}; //alt2 instruction mode
BitField<16,10> il {&data}; //immediate lower 8-bit flag
BitField<16,11> ih {&data}; //immediate upper 8-bit flag
BitField<16,12> b {&data}; //with flag
BitField<16,15> irq {&data}; //interrupt flag
BitRange<16,8,9> alt{&data}; //composite instruction mode
inline operator uint() const { return data & 0x9f7e; }
inline auto& operator=(const uint value) { return data = value, *this; }

View file

@ -31,10 +31,10 @@ auto WDC65816::disassemble(uint24 address, bool e, bool m, bool x) -> string {
return data | readWord(address + 1) << 8;
};
auto opcode = read(address); address(0,15)++;
auto operand0 = read(address); address(0,15)++;
auto operand1 = read(address); address(0,15)++;
auto operand2 = read(address); address(0,15)++;
auto opcode = read(address); address.bit(0,15)++;
auto operand0 = read(address); address.bit(0,15)++;
auto operand1 = read(address); address.bit(0,15)++;
auto operand2 = read(address); address.bit(0,15)++;
uint8 operandByte = operand0 << 0;
uint16 operandWord = operand0 << 0 | operand1 << 8;

View file

@ -17,8 +17,8 @@ struct MSU1 : Thread {
auto serialize(serializer&) -> void;
private:
vfs::shared::file dataFile;
vfs::shared::file audioFile;
shared_pointer<vfs::file> dataFile;
shared_pointer<vfs::file> audioFile;
enum Flag : uint {
Revision = 0x02, //max: 0x07

View file

@ -12,7 +12,7 @@ auto InputManager::bindHotkeys() -> void {
static bool rewinding = false;
hotkeys.append(InputHotkey("Toggle Fullscreen Mode").onPress([] {
presentation.toggleFullscreenMode();
program.toggleVideoFullScreen();
}));
hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] {
@ -107,11 +107,22 @@ auto InputManager::bindHotkeys() -> void {
}));
hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
presentation.pauseEmulation.setChecked(!presentation.pauseEmulation.checked());
if(presentation.runEmulation.checked()) {
presentation.pauseEmulation.setChecked().doActivate();
} else {
//unpausing can also cancel frame advance mode
presentation.runEmulation.setChecked().doActivate();
}
}));
hotkeys.append(InputHotkey("Frame Advance").onPress([] {
presentation.frameAdvance.doActivate();
if(!presentation.frameAdvance.checked()) {
//start frame advance if not currently frame advancing
presentation.frameAdvance.setChecked().doActivate();
} else {
//advance to the next video frame otherwise
program.frameAdvanceLock = false;
}
}));
hotkeys.append(InputHotkey("Reset Emulation").onPress([] {

View file

@ -111,7 +111,7 @@ auto Presentation::create() -> void {
driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow.show(7); });
toolsMenu.setText(tr("Tools")).setVisible(false);
saveState.setIcon(Icon::Action::Save).setText("Save State");
saveState.setIcon(Icon::Media::Record).setText("Save State");
for(uint index : range(QuickStates)) {
MenuItem item{&saveState};
item.setProperty("name", {"Quick/Slot ", 1 + index});
@ -119,7 +119,7 @@ auto Presentation::create() -> void {
item.setText({"Slot ", 1 + index});
item.onActivate([=] { program.saveState({"Quick/Slot ", 1 + index}); });
}
loadState.setIcon(Icon::Media::Play).setText("Load State");
loadState.setIcon(Icon::Media::Rewind).setText("Load State");
for(uint index : range(QuickStates)) {
MenuItem item{&loadState};
item.setProperty("name", {"Quick/Slot ", 1 + index});
@ -153,18 +153,21 @@ auto Presentation::create() -> void {
speedNormal.setText("100% (Normal)").setProperty("multiplier", "1.0").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(); });
pauseEmulation.setText("Pause Emulation").onToggle([&] {
if(pauseEmulation.checked()) audio.clear();
runMenu.setIcon(Icon::Media::Play).setText("Run Mode");
runEmulation.setText("Normal").onActivate([&] {
});
pauseEmulation.setText("Pause Emulation").onActivate([&] {
audio.clear();
});
frameAdvance.setText("Frame Advance").onActivate([&] {
audio.clear();
program.frameAdvanceLock = true;
});
movieMenu.setIcon(Icon::Emblem::Video).setText("Movie");
moviePlay.setIcon(Icon::Media::Play).setText("Play").onActivate([&] { program.moviePlay(); });
movieRecord.setIcon(Icon::Media::Record).setText("Record").onActivate([&] { program.movieRecord(false); });
movieRecordFromBeginning.setIcon(Icon::Media::Record).setText("Reset & Record").onActivate([&] { program.movieRecord(true); });
movieRecordFromBeginning.setIcon(Icon::Media::Record).setText("Reset and Record").onActivate([&] { program.movieRecord(true); });
movieStop.setIcon(Icon::Media::Stop).setText("Stop").onActivate([&] { program.movieStop(); });
frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] {
pauseEmulation.setChecked(false);
program.frameAdvance = true;
});
captureScreenshot.setIcon(Icon::Emblem::Image).setText("Capture Screenshot").onActivate([&] {
program.captureScreenshot();
});
@ -309,17 +312,6 @@ auto Presentation::resizeWindow() -> void {
setSize({width * multiplier, height * multiplier + statusHeight});
}
auto Presentation::toggleFullscreenMode() -> void {
if(!video.exclusive()) {
video.setExclusive(true);
if(!input.acquired()) input.acquire();
} else {
if(input.acquired()) input.release();
video.setExclusive(false);
viewport.setFocused();
}
}
auto Presentation::updateDeviceMenu() -> void {
controllerPort1.reset();
controllerPort2.reset();

View file

@ -9,7 +9,6 @@ struct Presentation : Window {
auto updateStatusIcon() -> void;
auto resizeWindow() -> void;
auto updateStatus() -> void;
auto toggleFullscreenMode() -> void;
auto updateDeviceMenu() -> void;
auto updateDeviceSelections() -> void;
auto updateSizeMenu() -> void;
@ -100,14 +99,16 @@ struct Presentation : Window {
MenuRadioItem speedFast{&speedMenu};
MenuRadioItem speedFastest{&speedMenu};
Group speedGroup{&speedSlowest, &speedSlow, &speedNormal, &speedFast, &speedFastest};
MenuSeparator speedSeparator{&speedMenu};
MenuCheckItem pauseEmulation{&speedMenu};
Menu runMenu{&toolsMenu};
MenuRadioItem runEmulation{&runMenu};
MenuRadioItem pauseEmulation{&runMenu};
MenuRadioItem frameAdvance{&runMenu};
Group runGroup{&runEmulation, &pauseEmulation, &frameAdvance};
Menu movieMenu{&toolsMenu};
MenuItem moviePlay{&movieMenu};
MenuItem movieRecord{&movieMenu};
MenuItem movieRecordFromBeginning{&movieMenu};
MenuItem movieStop{&movieMenu};
MenuItem frameAdvance{&toolsMenu};
MenuItem captureScreenshot{&toolsMenu};
MenuSeparator toolsSeparatorC{&toolsMenu};
MenuItem cheatFinder{&toolsMenu};

View file

@ -1,19 +1,19 @@
auto Program::openPakSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openPakSuperFamicom(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
return vfs::fs::file::open({superFamicom.location, name}, mode);
}
auto Program::openPakGameBoy(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openPakGameBoy(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
return vfs::fs::file::open({gameBoy.location, name}, mode);
}
auto Program::openPakBSMemory(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openPakBSMemory(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
return vfs::fs::file::open({bsMemory.location, name}, mode);
}
auto Program::openPakSufamiTurboA(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openPakSufamiTurboA(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
return vfs::fs::file::open({sufamiTurboA.location, name}, mode);
}
auto Program::openPakSufamiTurboB(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openPakSufamiTurboB(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
return vfs::fs::file::open({sufamiTurboB.location, name}, mode);
}

View file

@ -1,4 +1,4 @@
auto Program::openRomSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openRomSuperFamicom(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
if(name == "program.rom" && mode == vfs::file::mode::read) {
return vfs::memory::file::open(superFamicom.program.data(), superFamicom.program.size());
}
@ -131,7 +131,7 @@ auto Program::openRomSuperFamicom(string name, vfs::file::mode mode) -> vfs::sha
return {};
}
auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
if(name == "program.rom" && mode == vfs::file::mode::read) {
return vfs::memory::file::open(gameBoy.program.data(), gameBoy.program.size());
}
@ -147,7 +147,7 @@ auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> vfs::shared::
return {};
}
auto Program::openRomBSMemory(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openRomBSMemory(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
if(name == "program.rom" && mode == vfs::file::mode::read) {
return vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size());
}
@ -160,7 +160,7 @@ auto Program::openRomBSMemory(string name, vfs::file::mode mode) -> vfs::shared:
return {};
}
auto Program::openRomSufamiTurboA(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openRomSufamiTurboA(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
if(name == "program.rom" && mode == vfs::file::mode::read) {
return vfs::memory::file::open(sufamiTurboA.program.data(), sufamiTurboA.program.size());
}
@ -172,7 +172,7 @@ auto Program::openRomSufamiTurboA(string name, vfs::file::mode mode) -> vfs::sha
return {};
}
auto Program::openRomSufamiTurboB(string name, vfs::file::mode mode) -> vfs::shared::file {
auto Program::openRomSufamiTurboB(string name, vfs::file::mode mode) -> shared_pointer<vfs::file> {
if(name == "program.rom" && mode == vfs::file::mode::read) {
return vfs::memory::file::open(sufamiTurboB.program.data(), sufamiTurboB.program.size());
}

View file

@ -18,7 +18,6 @@ auto Program::load() -> void {
gameQueue = {};
screenshot = {};
frameAdvance = false;
if(!verified() && emulatorSettings.warnOnUnverifiedGames.checked()) {
//Emulator::loaded() is true at this point:
//prevent Program::main() from calling Emulator::run() during this dialog window
@ -52,7 +51,7 @@ auto Program::load() -> void {
presentation.toolsMenu.setVisible(true);
presentation.updateStateMenus();
presentation.speedNormal.setChecked();
presentation.pauseEmulation.setChecked(false);
presentation.runEmulation.setChecked().doActivate();
presentation.updateProgramIcon();
presentation.updateStatusIcon();
rewindReset(); //starts rewind state recording

View file

@ -7,8 +7,8 @@
#include <heuristics/sufami-turbo.cpp>
//ROM data is held in memory to support compressed archives, soft-patching, and game hacks
auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file {
vfs::shared::file result;
auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> shared_pointer<vfs::file> {
shared_pointer<vfs::file> result;
if(id == 0) { //System
if(name == "boards.bml" && mode == vfs::file::mode::read) {
@ -237,9 +237,8 @@ auto Program::videoFrame(const uint16* data, uint pitch, uint width, uint height
inputManager.frame();
if(frameAdvance) {
frameAdvance = false;
presentation.pauseEmulation.setChecked();
if(presentation.frameAdvance.checked()) {
frameAdvanceLock = true;
}
static uint frameCounter = 0;

View file

@ -67,7 +67,7 @@ auto Program::create() -> void {
if(gameQueue) load();
if(startFullScreen && emulator->loaded()) {
presentation.toggleFullscreenMode();
toggleVideoFullScreen();
}
Application::onMain({&Program::main, this});
}

View file

@ -7,7 +7,7 @@ struct Program : Lock, Emulator::Platform {
auto quit() -> void;
//platform.cpp
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
auto open(uint id, string name, vfs::file::mode mode, bool required) -> shared_pointer<vfs::file> override;
auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override;
auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void override;
auto audioFrame(const float* samples, uint channels) -> void override;
@ -28,18 +28,18 @@ struct Program : Lock, Emulator::Platform {
auto verified() const -> bool;
//game-pak.cpp
auto openPakSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openPakGameBoy(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openPakBSMemory(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openPakSufamiTurboA(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openPakSufamiTurboB(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openPakSuperFamicom(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openPakGameBoy(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openPakBSMemory(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openPakSufamiTurboA(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openPakSufamiTurboB(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
//game-rom.cpp
auto openRomSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openRomGameBoy(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openRomBSMemory(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openRomSufamiTurboA(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openRomSufamiTurboB(string name, vfs::file::mode mode) -> vfs::shared::file;
auto openRomSuperFamicom(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openRomGameBoy(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openRomBSMemory(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openRomSufamiTurboA(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
auto openRomSufamiTurboB(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
//paths.cpp
auto path(string type, string location, string extension = "") -> string;
@ -92,10 +92,12 @@ struct Program : Lock, Emulator::Platform {
auto updateVideoExclusive() -> void;
auto updateVideoBlocking() -> void;
auto updateVideoFlush() -> void;
auto updateVideoMonitor() -> void;
auto updateVideoFormat() -> void;
auto updateVideoShader() -> void;
auto updateVideoPalette() -> void;
auto updateVideoEffects() -> void;
auto toggleVideoFullScreen() -> void;
//audio.cpp
auto updateAudioDriver(Window parent) -> void;
@ -169,7 +171,7 @@ public:
vector<string> gameQueue;
uint32_t palette[32768];
uint32_t palettePaused[32768];
uint32_t paletteDimmed[32768];
struct Screenshot {
const uint16* data = nullptr;
@ -179,7 +181,7 @@ public:
uint scale = 0;
} screenshot;
bool frameAdvance = false;
bool frameAdvanceLock = false;
uint64 autoSaveTime;

View file

@ -19,6 +19,8 @@ auto Program::updateStatus() -> void {
string frameRate;
if(!emulator->loaded()) {
frameRate = tr("Unloaded");
} else if(presentation.frameAdvance.checked() && frameAdvanceLock) {
frameRate = tr("Frame Advance");
} else if(presentation.pauseEmulation.checked()) {
frameRate = tr("Paused");
} else if(!focused() && inputSettings.pauseEmulation.checked()) {
@ -66,6 +68,7 @@ auto Program::inactive() -> bool {
if(locked()) return true;
if(!emulator->loaded()) return true;
if(presentation.pauseEmulation.checked()) return true;
if(presentation.frameAdvance.checked() && frameAdvanceLock) return true;
if(!focused() && inputSettings.pauseEmulation.checked()) return true;
return false;
}

View file

@ -8,6 +8,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
updateVideoExclusive();
updateVideoBlocking();
updateVideoFlush();
updateVideoMonitor();
updateVideoFormat();
updateVideoShader();
@ -32,8 +33,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
}
auto Program::updateVideoExclusive() -> void {
//only enabled in fullscreen mode via Presentation::toggleFullScreen()
video.setExclusive(false);
video.setExclusive(settings.video.exclusive);
}
auto Program::updateVideoBlocking() -> void {
@ -44,6 +44,13 @@ auto Program::updateVideoFlush() -> void {
video.setFlush(settings.video.flush);
}
auto Program::updateVideoMonitor() -> void {
if(!video.hasMonitor(settings.video.monitor)) {
settings.video.monitor = video.monitor();
}
video.setMonitor(settings.video.monitor);
}
auto Program::updateVideoFormat() -> void {
if(!video.hasFormat(settings.video.format)) {
settings.video.format = video.format();
@ -103,8 +110,8 @@ auto Program::updateVideoPalette() -> void {
b >>= 1;
switch(depth) {
case 24: palettePaused[color] = r >> 8 << 16 | g >> 8 << 8 | b >> 8 << 0; break;
case 30: palettePaused[color] = r >> 6 << 20 | g >> 6 << 10 | b >> 6 << 0; break;
case 24: paletteDimmed[color] = r >> 8 << 16 | g >> 8 << 8 | b >> 8 << 0; break;
case 30: paletteDimmed[color] = r >> 6 << 20 | g >> 6 << 10 | b >> 6 << 0; break;
}
}
@ -114,3 +121,18 @@ auto Program::updateVideoPalette() -> void {
auto Program::updateVideoEffects() -> void {
emulator->configure("Video/BlurEmulation", settings.video.blur);
}
auto Program::toggleVideoFullScreen() -> void {
if(!video.hasFullScreen()) return;
video.clear();
if(!video.fullScreen()) {
video.setFullScreen(true);
if(!input.acquired() && video.exclusive()) input.acquire();
} else {
if(input.acquired()) input.release();
video.setFullScreen(false);
presentation.viewport.setFocused();
}
}

View file

@ -68,7 +68,8 @@ auto Program::viewportRefresh() -> void {
auto filterRender = filterSelect(filterWidth, filterHeight, scale);
if(auto [output, length] = video.acquire(filterWidth, filterHeight); output) {
filterRender(palettePaused, output, length, (const uint16_t*)data, pitch, width, height);
bool dimmed = settings.video.dimming && !presentation.frameAdvance.checked();
filterRender(dimmed ? paletteDimmed : palette, output, length, (const uint16_t*)data, pitch, width, height);
length >>= 2;
if(settings.video.snow) {

View file

@ -3,14 +3,26 @@ auto DriverSettings::create() -> void {
setVisible(false);
videoLabel.setText("Video").setFont(Font().setBold());
videoLayout.setSize({2, 2});
videoDriverLabel.setText("Driver:");
videoDriverOption.onChange([&] {
videoDriverUpdate.setText(videoDriverOption.selected().text() != video.driver() ? "Change" : "Reload");
});
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
videoMonitorLabel.setText("Fullscreen Monitor:").setToolTip(
"Sets which monitor video is sent to in fullscreen mode."
);
videoMonitorOption.onChange([&] { videoMonitorChange(); });
videoFormatLabel.setText("Format:");
videoFormatOption.onChange([&] { videoFormatChange(); });
videoExclusiveToggle.setText("Exclusive").setToolTip(
"Causes fullscreen mode to take over all monitors.\n"
"This allows adaptive sync to work better and reduces input latency.\n"
"However, multi-monitor users should turn this option off.\n"
"Note: Direct3D exclusive mode also does not honor the requested monitor."
).onToggle([&] {
settings.video.exclusive = videoExclusiveToggle.checked();
program.updateVideoExclusive();
});
videoBlockingToggle.setText("Synchronize").setToolTip(
"Waits for the video card to be ready before rendering frames.\n"
"Eliminates dropped or duplicated frames; but can distort audio.\n\n"
@ -90,11 +102,6 @@ auto DriverSettings::create() -> void {
"This is useful for APIs that lack auto-hotplug support,\n"
"such as DirectInput and SDL."
).onActivate([&] { inputDriverChange(); });
//this will hide the video format setting for simplicity, as it's not very useful just yet ...
//videoLayout.setSize({2, 1});
//videoLayout.remove(videoFormatLabel);
//videoLayout.remove(videoPropertyLayout);
}
//
@ -108,7 +115,9 @@ auto DriverSettings::videoDriverChanged() -> void {
}
videoDriverActive.setText({"Active driver: ", video.driver()});
videoDriverOption.doChange();
videoMonitorChanged();
videoFormatChanged();
videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive());
videoBlockingToggle.setChecked(video.blocking()).setEnabled(video.hasBlocking());
videoFlushToggle.setChecked(video.flush()).setEnabled(video.hasFlush());
setGeometry(geometry());
@ -133,6 +142,24 @@ auto DriverSettings::videoDriverChange() -> void {
}
}
auto DriverSettings::videoMonitorChanged() -> void {
videoMonitorOption.reset();
for(auto& monitor : Video::hasMonitors()) {
ComboButtonItem item{&videoMonitorOption};
item.setText(monitor.name);
if(monitor.name == video.monitor()) item.setSelected();
}
videoMonitorOption.setEnabled(videoMonitorOption.itemCount() > 1);
setGeometry(geometry());
videoMonitorChange();
}
auto DriverSettings::videoMonitorChange() -> void {
auto item = videoMonitorOption.selected();
settings.video.monitor = item.text();
program.updateVideoMonitor();
}
auto DriverSettings::videoFormatChanged() -> void {
videoFormatOption.reset();
for(auto& format : video.hasFormats()) {

View file

@ -46,14 +46,17 @@ auto Settings::process(bool load) -> void {
} \
bind(text, "Video/Driver", video.driver);
bind(boolean, "Video/Exclusive", video.exclusive);
bind(boolean, "Video/Blocking", video.blocking);
bind(boolean, "Video/Flush", video.flush);
bind(text, "Video/Monitor", video.monitor);
bind(text, "Video/Format", video.format);
bind(text, "Video/Shader", video.shader);
bind(natural, "Video/Luminance", video.luminance);
bind(natural, "Video/Saturation", video.saturation);
bind(natural, "Video/Gamma", video.gamma);
bind(boolean, "Video/Dimming", video.dimming);
bind(boolean, "Video/Snow", video.snow);
bind(text, "Video/Output", video.output);

View file

@ -9,14 +9,17 @@ struct Settings : Markup::Node {
struct Video {
string driver;
bool exclusive = false;
bool blocking = false;
bool flush = false;
string monitor = "Primary";
string format = "Default";
string shader = "Blur";
uint luminance = 100;
uint saturation = 100;
uint gamma = 150;
bool dimming = true;
bool snow = false;
string output = "Scale";
@ -153,6 +156,7 @@ private:
Label gammaValue{&colorLayout, Size{50_sx, 0}};
HorizontalSlider gammaSlider{&colorLayout, Size{~0, 0}};
//
CheckLabel dimmingOption{this, Size{~0, 0}};
CheckLabel snowOption{this, Size{~0, 0}};
};
@ -354,6 +358,8 @@ struct DriverSettings : VerticalLayout {
auto create() -> void;
auto videoDriverChanged() -> void;
auto videoDriverChange() -> void;
auto videoMonitorChanged() -> void;
auto videoMonitorChange() -> void;
auto videoFormatChanged() -> void;
auto videoFormatChange() -> void;
auto audioDriverChanged() -> void;
@ -369,16 +375,19 @@ struct DriverSettings : VerticalLayout {
public:
Label videoLabel{this, Size{~0, 0}, 2};
TableLayout videoLayout{this, Size{~0, 0}};
Label videoDriverLabel{&videoLayout, Size{0, 0}};
VerticalLayout videoLayout{this, Size{~0, 0}};
HorizontalLayout videoDriverLayout{&videoLayout, Size{~0, 0}};
Label videoDriverLabel{&videoDriverLayout, Size{0, 0}};
ComboButton videoDriverOption{&videoDriverLayout, Size{0, 0}};
Button videoDriverUpdate{&videoDriverLayout, Size{0, 0}};
Label videoDriverActive{&videoDriverLayout, Size{0, 0}};
Label videoFormatLabel{&videoLayout, Size{0, 0}};
HorizontalLayout videoPropertyLayout{&videoLayout, Size{~0, 0}};
Label videoMonitorLabel{&videoPropertyLayout, Size{0, 0}};
ComboButton videoMonitorOption{&videoPropertyLayout, Size{0, 0}};
Label videoFormatLabel{&videoPropertyLayout, Size{0, 0}};
ComboButton videoFormatOption{&videoPropertyLayout, Size{0, 0}};
HorizontalLayout videoToggleLayout{this, Size{~0, 0}};
CheckLabel videoExclusiveToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
Canvas videoSpacer{this, Size{~0, 1}};

View file

@ -30,6 +30,12 @@ auto VideoSettings::create() -> void {
program.updateVideoPalette();
}).doChange();
dimmingOption.setText("Dim video when idle").setToolTip(
"Darkens the video to indicate that the emulation is not running."
).setChecked(settings.video.dimming).onToggle([&] {
settings.video.dimming = dimmingOption.checked();
});
snowOption.setText("Draw snow effect when idle").setChecked(settings.video.snow).onToggle([&] {
settings.video.snow = snowOption.checked();
presentation.updateProgramIcon();

View file

@ -188,10 +188,10 @@ auto mWindow::resizable() const -> bool {
}
auto mWindow::setAlignment(Alignment alignment) -> type& {
auto workspace = Desktop::workspace();
auto workspace = Monitor::workspace();
auto geometry = frameGeometry();
auto x = alignment.horizontal() * (workspace.width() - geometry.width());
auto y = alignment.vertical() * (workspace.height() - geometry.height());
auto x = workspace.x() + alignment.horizontal() * (workspace.width() - geometry.width());
auto y = workspace.y() + alignment.vertical() * (workspace.height() - geometry.height());
setFramePosition({(int)x, (int)y});
return *this;
}
@ -206,10 +206,10 @@ auto mWindow::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
//-1 .. -0 => beyond parent window
//... I know, relying on -0 IEE754 here is ... less than ideal
if(signbit(alignment.horizontal())) {
x = (parent.x() - window.width()) + (parent.width() + window.width()) * abs(alignment.horizontal());
x = (parent.x() - window.width()) + abs(alignment.horizontal()) * (parent.width() + window.width());
}
if(signbit(alignment.vertical())) {
y = (parent.y() - window.height()) + (parent.height() + window.height()) * abs(alignment.vertical());
y = (parent.y() - window.height()) + abs(alignment.vertical()) * (parent.height() + window.height());
}
setFramePosition({(int)x, (int)y});
return *this;

View file

@ -48,8 +48,12 @@ auto pMonitor::primary() -> uint {
auto pMonitor::workspace(uint monitor) -> Geometry {
#if HIRO_GTK==2 || 1
//todo: can this be done on a per-monitor basis with raw Xlib / Win32 APIs?
return pDesktop::workspace();
if(Monitor::count() == 1) {
return Desktop::workspace();
} else {
//it is currently unknown how to get per-monitor workspace areas, use geometry instead
return Monitor::geometry(monitor);
}
#elif HIRO_GTK==3
auto gdkMonitor = gdk_display_get_monitor(gdk_display_get_default(), monitor);
GdkRectangle rectangle = {};

View file

@ -3,13 +3,57 @@
namespace hiro {
auto pDesktop::size() -> Size {
#if defined(DISPLAY_WINDOWS)
return {GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)};
#elif defined(DISPLAY_XORG)
auto display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display);
XWindowAttributes attributes;
XGetWindowAttributes(display, RootWindow(display, screen), &attributes);
XCloseDisplay(display);
return {attributes.width, attributes.height};
#else
//this only returns the geometry of the primary monitor rather than the entire desktop
QRect rect = QApplication::desktop()->screenGeometry();
return {rect.width(), rect.height()};
#endif
}
auto pDesktop::workspace() -> Geometry {
#if defined(DISPLAY_WINDOWS)
RECT rc;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
#elif defined(DISPLAY_XORG)
auto display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display);
int format;
unsigned char* data = nullptr;
unsigned long items, after;
XlibAtom returnAtom;
XlibAtom netWorkarea = XInternAtom(display, "_NET_WORKAREA", XlibTrue);
int result = XGetWindowProperty(
display, RootWindow(display, screen), netWorkarea, 0, 4, XlibFalse,
XInternAtom(display, "CARDINAL", XlibTrue), &returnAtom, &format, &items, &after, &data
);
XlibAtom cardinal = XInternAtom(display, "CARDINAL", XlibTrue);
if(result == Success && returnAtom == cardinal && format == 32 && items == 4) {
unsigned long* workarea = (unsigned long*)data;
XCloseDisplay(display);
return {(int)workarea[0], (int)workarea[1], (int)workarea[2], (int)workarea[3]};
}
XCloseDisplay(display);
auto size = Desktop::size();
return {0, 0, size.width(), size.height()};
#else
//this only returns the workspace of the primary monitor rather than the entire desktop
QRect rect = QApplication::desktop()->availableGeometry();
return {rect.x(), rect.y(), rect.width(), rect.height()};
#endif
}
}

View file

@ -24,8 +24,11 @@ auto pMonitor::primary() -> uint {
}
auto pMonitor::workspace(uint monitor) -> Geometry {
//TODO: per-monitor?
return pDesktop::workspace();
if(Monitor::count() == 1) {
return Desktop::workspace();
} else {
return Monitor::geometry(monitor);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -83,8 +83,9 @@ auto pWindow::handle() const -> uintptr_t {
}
auto pWindow::monitor() const -> uint {
//TODO
return 0;
int monitor = QDesktopWidget().screenNumber(qtWindow);
if(monitor < 0) monitor = Monitor::primary();
return monitor;
}
auto pWindow::remove(sMenuBar menuBar) -> void {
@ -130,7 +131,8 @@ auto pWindow::setFullScreen(bool fullScreen) -> void {
if(fullScreen) {
windowedGeometry = state().geometry;
qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
qtContainer->setFixedSize(Desktop::size().width() - frameMargin().width(), Desktop::size().height() - frameMargin().height());
auto monitorGeometry = Monitor::geometry(monitor());
qtContainer->setFixedSize(monitorGeometry.width() - frameMargin().width(), monitorGeometry.height() - frameMargin().height());
qtWindow->showFullScreen();
state().geometry = Monitor::geometry(Monitor::primary());
} else {

View file

@ -1,142 +0,0 @@
#pragma once
#include <nall/primitives.hpp>
namespace nall {
template<typename Type, uint Bit> struct BooleanBitField {
enum : uint { bit = Bit };
enum : uint { mask = 1ull << bit };
using type = Type;
using utype = typename std::make_unsigned<type>::type;
static_assert(bit < sizeof(type) * 8, "");
inline BooleanBitField() = default;
inline BooleanBitField(const BooleanBitField& value) { set(value.get()); }
template<typename T> inline BooleanBitField(const bool value) { set(value); }
inline operator bool() const { return get(); }
inline auto& operator=(const BooleanBitField& value) { return set(value.get()); }
inline auto& operator=(const bool value) { return set(value); }
inline auto& operator&=(const bool value) { return set(get() & value); }
inline auto& operator|=(const bool value) { return set(get() | value); }
inline auto& operator^=(const bool value) { return set(get() ^ value); }
inline auto raise() { return get() == 0 ? set(1), true : false; }
inline auto lower() { return get() == 1 ? set(0), true : false; }
inline auto& invert() { return set(get() ^ 1); }
private:
utype data;
inline auto get() const -> bool {
return data & mask;
}
inline auto set(bool value) -> BooleanBitField& {
return data = (data & ~mask) | (value << bit), *this;
}
};
template<typename Type, uint Lo, uint Hi> struct NaturalBitField {
enum : uint { lo = Lo <= Hi ? Lo : Hi };
enum : uint { hi = Hi >= Lo ? Hi : Lo };
enum : uint { bits = hi - lo + 1 };
enum : uint { mask = (~0ull >> (64 - bits)) << lo };
using type = Type;
using utype = typename std::make_unsigned<type>::type;
static_assert(hi < sizeof(type) * 8, "");
inline NaturalBitField() = default;
inline NaturalBitField(const NaturalBitField& value) { set(value.data); }
template<typename T> inline NaturalBitField(const T& value) { set(value << lo); }
inline explicit operator bool() const { return data & mask; }
inline operator utype() const { return get(); }
inline auto& operator=(const NaturalBitField& value) { return set(value.data); }
template<typename T> inline auto& operator=(T value) { return set(value << lo); }
inline auto operator++(int) { utype value = get(); set(data + (1 << lo)); return value; }
inline auto operator--(int) { utype value = get(); set(data - (1 << lo)); return value; }
inline auto& operator++() { return set(data + (1 << lo)); }
inline auto& operator--() { return set(data - (1 << lo)); }
inline auto& operator &=(const utype value) { return set(data & (value << lo)); }
inline auto& operator |=(const utype value) { return set(data | (value << lo)); }
inline auto& operator ^=(const utype value) { return set(data ^ (value << lo)); }
inline auto& operator<<=(const utype value) { return set((data & mask) << value); }
inline auto& operator>>=(const utype value) { return set((data & mask) >> value); }
inline auto& operator +=(const utype value) { return set(data + (value << lo)); }
inline auto& operator -=(const utype value) { return set(data - (value << lo)); }
inline auto& operator *=(const utype value) { return set((get() * value) << lo); }
inline auto& operator /=(const utype value) { return set((get() / value) << lo); }
inline auto& operator %=(const utype value) { return set((get() % value) << lo); }
private:
utype data;
inline auto get() const -> utype {
return (data & mask) >> lo;
}
inline auto set(utype value) -> NaturalBitField& {
return data = (data & ~mask) | (value & mask), *this;
}
};
template<typename Type, uint Lo, uint Hi> struct IntegerBitField {
enum : uint { lo = Lo <= Hi ? Lo : Hi };
enum : uint { hi = Hi >= Lo ? Hi : Lo };
enum : uint { bits = hi - lo + 1 };
enum : uint { mask = (~0ull >> (64 - bits)) << lo };
using type = Type;
using stype = typename std::make_signed<type>::type;
using utype = typename std::make_unsigned<type>::type;
static_assert(hi < sizeof(type) * 8, "");
inline IntegerBitField() = default;
inline IntegerBitField(const IntegerBitField& value) { set(value.get()); }
template<typename T> inline IntegerBitField(const T& value) { set(value); }
inline explicit operator bool() const { return data & mask; }
inline operator stype() const { return get(); }
inline auto& operator=(const IntegerBitField& value) { return set(value.get()); }
template<typename T> inline auto& operator=(const T& value) { return set(value); }
inline auto operator++(int) { stype value = get(); set(value + 1); return value; }
inline auto operator--(int) { stype value = get(); set(value - 1); return value; }
inline auto& operator++() { return set(get() + 1); }
inline auto& operator--() { return set(get() - 1); }
inline auto& operator &=(const stype value) { return set(get() & value); }
inline auto& operator |=(const stype value) { return set(get() | value); }
inline auto& operator ^=(const stype value) { return set(get() ^ value); }
inline auto& operator<<=(const stype value) { return set(get() << value); }
inline auto& operator>>=(const stype value) { return set(get() >> value); }
inline auto& operator +=(const stype value) { return set(get() + value); }
inline auto& operator -=(const stype value) { return set(get() - value); }
inline auto& operator *=(const stype value) { return set(get() * value); }
inline auto& operator /=(const stype value) { return set(get() / value); }
inline auto& operator %=(const stype value) { return set(get() % value); }
private:
utype data;
inline auto get() const -> stype {
enum : utype { b = 1ull << (bits - 1) };
enum : utype { m = b * 2 - 1 };
return ((((data & mask) >> lo) & m) ^ b) - b;
}
inline auto set(utype value) -> IntegerBitField& {
return data = (data & ~mask) | ((value << lo) & mask), *this;
}
};
}

View file

@ -1,119 +0,0 @@
#pragma once
#include <nall/memory.hpp>
namespace nall {
struct bitvector {
bitvector() = default;
bitvector(uint size) { resize(size); }
bitvector(const bitvector& source) { operator=(source); }
bitvector(bitvector&& source) { operator=(move(source)); }
~bitvector() { reset(); }
auto operator=(const bitvector& source) -> bitvector& {
bits = source.bits;
pool = memory::resize<uint8_t>(pool, bytes());
memory::copy(pool, source.pool, bytes());
return *this;
}
auto operator=(bitvector&& source) -> bitvector& {
pool = source.pool;
bits = source.bits;
source.pool = nullptr;
source.bits = 0;
return *this;
}
explicit operator bool() const { return bits > 0; }
auto size() const -> uint { return bits; }
auto bytes() const -> uint { return (bits + 7) / 8; }
auto data() -> uint8_t* { return pool; }
auto data() const -> const uint8_t* { return pool; }
auto reset() -> void {
if(pool) free(pool);
pool = nullptr;
bits = 0;
}
auto resize(uint size) -> void {
uint from = bits;
bits = size;
for(uint n = size; n < from; n++) clear(n); //on reduce
pool = memory::resize<uint8_t>(pool, bytes());
for(uint n = from; n < size; n++) clear(n); //on expand
}
auto get(uint position) const -> bool {
#ifdef DEBUG
struct out_of_bounds {};
if(position >= bits) throw out_of_bounds{};
#endif
return pool[position >> 3] & (0x80 >> (position & 7));
}
auto clear() -> void {
memory::fill<uint8_t>(pool, bytes(), 0x00);
}
auto set() -> void {
memory::fill<uint8_t>(pool, bytes(), 0xff);
for(uint n = bits; n < bytes() * 8; n++) clear(n);
}
auto clear(uint position) -> void {
pool[position >> 3] &= ~(0x80 >> (position & 7));
}
auto set(uint position) -> void {
pool[position >> 3] |= (0x80 >> (position & 7));
}
auto invert(uint position) -> void {
get(position) ? clear(position) : set(position);
}
auto set(uint position, bool value) -> void {
value ? set(position) : clear(position);
}
struct reference {
reference(bitvector& self, uint position) : self(self), position(position) {}
operator bool() const { return self.get(position); }
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
protected:
bitvector& self;
uint position;
};
auto operator[](uint position) -> reference {
return reference(*this, position);
}
auto operator[](uint position) const -> bool {
return get(position);
}
struct iterator {
iterator(bitvector& self, uint position) : self(self), position(position) {}
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
auto operator++() -> iterator& { position++; return *this; }
auto operator*() -> reference { return self.operator[](position); }
protected:
bitvector& self;
uint position;
};
auto begin() -> iterator { return iterator(*this, 0); }
auto end() -> iterator { return iterator(*this, bits); }
protected:
uint8_t* pool = nullptr;
uint bits = 0;
};
}

View file

@ -77,16 +77,16 @@ struct directory : inode {
function<void (const string&, const string&, const string&)>
recurse = [&](const string& basename, const string& pathname, const string& pattern) {
for(auto& folder : directory::ufolders(pathname)) {
contents.append(string{pathname, folder}.trimLeft(basename, 1L));
recurse(basename, {pathname, folder}, pattern);
contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L));
recurse(basename, {pathname, folder, "/"}, pattern);
}
for(auto& file : directory::ufiles(pathname, pattern)) {
contents.append(string{pathname, file}.trimLeft(basename, 1L));
}
};
for(auto& folder : directory::ufolders(pathname)) {
contents.append(folder);
recurse(pathname, {pathname, folder}, pattern);
contents.append({folder, "/"});
recurse(pathname, {pathname, folder, "/"}, pattern);
}
for(auto& file : directory::ufiles(pathname, pattern)) {
contents.append(file);
@ -100,16 +100,16 @@ struct directory : inode {
function<void (const string&, const string&, const string&)>
recurse = [&](const string& basename, const string& pathname, const string& pattern) {
for(auto& folder : directory::ufolders(pathname)) {
contents.append(string{pathname, folder}.trimLeft(basename, 1L));
recurse(basename, {pathname, folder}, pattern);
contents.append(string{pathname, folder, "/"}.trimLeft(basename, 1L));
recurse(basename, {pathname, folder, "/"}, pattern);
}
for(auto& file : directory::ufiles(pathname, pattern)) {
contents.append(string{pathname, file}.trimLeft(basename, 1L));
}
};
for(auto& folder : directory::ufolders(pathname)) {
contents.append(folder);
recurse(pathname, {pathname, folder}, pattern);
contents.append({folder, "/"});
recurse(pathname, {pathname, folder, "/"}, pattern);
}
for(auto& file : directory::ufiles(pathname, pattern)) {
contents.append(file);

View file

@ -180,6 +180,7 @@ auto Response::findContentType(const string& s) const -> string {
if(s == ".gz" ) return "application/gzip";
if(s == ".htm" ) return "text/html; charset=utf-8";
if(s == ".html") return "text/html; charset=utf-8";
if(s == ".ico" ) return "image/x-icon";
if(s == ".jpg" ) return "image/jpeg";
if(s == ".jpeg") return "image/jpeg";
if(s == ".js" ) return "application/javascript";

View file

@ -10,13 +10,13 @@ namespace nall::HTTP {
struct Role {
struct Settings {
int connectionLimit = 1 * 1024; //server
int headSizeLimit = 16 * 1024; //client, server
int bodySizeLimit = 8192 * 1024; //client, server
int chunkSize = 32 * 1024; //client, server
int threadStackSize = 128 * 1024; //server
int timeoutReceive = 15 * 1000; //server
int timeoutSend = 15 * 1000; //server
int connectionLimit = 1 * 1024; //server
int headSizeLimit = 16 * 1024; //client, server
int bodySizeLimit = 65536 * 1024; //client, server
int chunkSize = 32 * 1024; //client, server
int threadStackSize = 128 * 1024; //server
int timeoutReceive = 15 * 1000; //server
int timeoutSend = 15 * 1000; //server
} settings;
inline auto configure(const string& parameters) -> bool;

View file

@ -29,6 +29,7 @@ namespace nall {
constexpr auto compiler() -> Compiler { return Compiler::Clang; }
#pragma clang diagnostic warning "-Wreturn-type"
#pragma clang diagnostic ignored "-Wunused-result"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wempty-body"
#pragma clang diagnostic ignored "-Wparentheses"
@ -36,20 +37,20 @@ namespace nall {
#pragma clang diagnostic ignored "-Wswitch-bool"
#pragma clang diagnostic ignored "-Wtautological-compare"
#pragma clang diagnostic ignored "-Wabsolute-value"
#pragma clang diagnostic ignored "-Wunused-result"
#pragma clang diagnostic ignored "-Wshift-count-overflow"
//temporary
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
//#pragma clang diagnostic error "-Wdeprecated-declarations"
#elif defined(__GNUC__)
#define COMPILER_GCC
constexpr auto compiler() -> Compiler { return Compiler::GCC; }
#pragma GCC diagnostic warning "-Wreturn-type"
#pragma GCC diagnostic ignored "-Wunused-result"
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wswitch-bool"
#pragma GCC diagnostic ignored "-Wunused-result"
#elif defined(_MSC_VER)
#define COMPILER_MICROSOFT
constexpr auto compiler() -> Compiler { return Compiler::Microsoft; }

View file

@ -22,8 +22,6 @@
#include <nall/array-view.hpp>
#include <nall/atoi.hpp>
#include <nall/bit.hpp>
#include <nall/bit-field.hpp>
#include <nall/bit-vector.hpp>
#include <nall/chrono.hpp>
#include <nall/directory.hpp>
#include <nall/dl.hpp>

View file

@ -103,13 +103,13 @@ namespace Math {
#endif
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
#define neverinline __attribute__((noinline))
#define noinline __attribute__((noinline))
#define alwaysinline inline __attribute__((always_inline))
#elif defined(COMPILER_MICROSOFT)
#define neverinline __declspec(noinline)
#define noinline __declspec(noinline)
#define alwaysinline inline __forceinline
#else
#define neverinline
#define noinline
#define alwaysinline inline
#endif

View file

@ -11,6 +11,7 @@ namespace nall {
template<uint Precision = 64> struct Real;
}
#include <nall/primitives/bit-field.hpp>
#include <nall/primitives/bit-range.hpp>
#include <nall/primitives/boolean.hpp>
#include <nall/primitives/natural.hpp>

View file

@ -0,0 +1,124 @@
#pragma once
namespace nall {
template<int...> struct BitField;
/* static BitField */
template<int Precision, int Index> struct BitField<Precision, Index> {
static_assert(Precision >= 1 && Precision <= 64);
enum : uint { bits = Precision };
using type =
conditional_t<bits <= 8, uint8_t,
conditional_t<bits <= 16, uint16_t,
conditional_t<bits <= 32, uint32_t,
conditional_t<bits <= 64, uint64_t,
void>>>>;
enum : uint { shift = Index < 0 ? Precision + Index : Index };
enum : type { mask = 1ull << shift };
BitField(const BitField&) = delete;
inline auto& operator=(const BitField& source) {
target = target & ~mask | (bool)source << shift;
return *this;
}
template<typename T> inline BitField(T* source) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
}
inline auto bit() const {
return shift;
}
inline operator bool() const {
return target & mask;
}
inline auto& operator=(bool source) {
target = target & ~mask | source << shift;
return *this;
}
inline auto& operator&=(bool source) {
target = target & (~mask | source << shift);
return *this;
}
inline auto& operator^=(bool source) {
target = target ^ source << shift;
return *this;
}
inline auto& operator|=(bool source) {
target = target | source << shift;
return *this;
}
private:
type& target;
};
/* dynamic BitField */
template<int Precision> struct BitField<Precision> {
static_assert(Precision >= 1 && Precision <= 64);
enum : uint { bits = Precision };
using type =
conditional_t<bits <= 8, uint8_t,
conditional_t<bits <= 16, uint16_t,
conditional_t<bits <= 32, uint32_t,
conditional_t<bits <= 64, uint64_t,
void>>>>;
BitField(const BitField&) = delete;
inline auto& operator=(const BitField& source) {
target = target & ~mask | (bool)source << shift;
return *this;
}
template<typename T> inline BitField(T* source, int index) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
if(index < 0) index = Precision + index;
mask = 1ull << index;
shift = index;
}
inline auto bit() const {
return shift;
}
inline operator bool() const {
return target & mask;
}
inline auto& operator=(bool source) {
target = target & ~mask | source << shift;
return *this;
}
inline auto& operator&=(bool source) {
target = target & (~mask | source << shift);
return *this;
}
inline auto& operator^=(bool source) {
target = target ^ source << shift;
return *this;
}
inline auto& operator|=(bool source) {
target = target | source << shift;
return *this;
}
private:
type& target;
type mask;
uint shift;
};
}

View file

@ -2,66 +2,254 @@
namespace nall {
//warning: so that BitRange can modify the underlying number directly, it must bind a reference.
//as a result, auto value = number.bits() will capture by-reference, rather than by-value.
template<int...> struct BitRange;
template<int Precision> struct BitRange {
/* static BitRange */
template<int Precision, int Lo, int Hi> struct BitRange<Precision, Lo, Hi> {
static_assert(Precision >= 1 && Precision <= 64);
static inline constexpr auto bits() -> uint { return Precision; }
using utype =
conditional_t<bits() <= 8, uint8_t,
conditional_t<bits() <= 16, uint16_t,
conditional_t<bits() <= 32, uint32_t,
conditional_t<bits() <= 64, uint64_t,
enum : uint { bits = Precision };
using type =
conditional_t<bits <= 8, uint8_t,
conditional_t<bits <= 16, uint16_t,
conditional_t<bits <= 32, uint32_t,
conditional_t<bits <= 64, uint64_t,
void>>>>;
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
enum : uint { lo = Lo < 0 ? Precision + Lo : Lo };
enum : uint { hi = Hi < 0 ? Precision + Hi : Hi };
enum : type { mask = ~0ull >> 64 - (hi - lo + 1) << lo };
enum : uint { shift = lo };
inline BitRange(utype& source, int lo, int hi) : source(source) {
if(lo < 0) lo = Precision + lo;
if(hi < 0) hi = Precision + hi;
if(lo > hi) swap(lo, hi);
this->lo = lo;
this->hi = hi;
}
inline auto& operator=(BitRange& source) { return set(source.get()); }
BitRange(const BitRange& source) = delete;
inline operator utype() const { return get(); }
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
inline auto& operator++() { return set(get() + 1); }
inline auto& operator--() { return set(get() - 1); }
template<typename T> inline auto& operator =(const T& value) { return set( value); }
template<typename T> inline auto& operator *=(const T& value) { return set(get() * value); }
template<typename T> inline auto& operator /=(const T& value) { return set(get() / value); }
template<typename T> inline auto& operator %=(const T& value) { return set(get() % value); }
template<typename T> inline auto& operator +=(const T& value) { return set(get() + value); }
template<typename T> inline auto& operator -=(const T& value) { return set(get() - value); }
template<typename T> inline auto& operator<<=(const T& value) { return set(get() << value); }
template<typename T> inline auto& operator>>=(const T& value) { return set(get() >> value); }
template<typename T> inline auto& operator &=(const T& value) { return set(get() & value); }
template<typename T> inline auto& operator ^=(const T& value) { return set(get() ^ value); }
template<typename T> inline auto& operator |=(const T& value) { return set(get() | value); }
private:
inline auto get() const -> utype {
const utype rangeBits = hi - lo + 1;
const utype rangeMask = (1ull << rangeBits) - 1 << lo & mask();
return (source & rangeMask) >> lo;
}
inline auto& set(const utype& value) {
const utype rangeBits = hi - lo + 1;
const utype rangeMask = (1ull << rangeBits) - 1 << lo & mask();
source = source & ~rangeMask | value << lo & rangeMask;
inline auto& operator=(const BitRange& source) {
target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
return *this;
}
utype& source;
uint lo;
uint hi;
template<typename T> inline BitRange(T* source) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
}
inline operator type() const {
return (target & mask) >> shift;
}
inline auto operator++(int) {
auto value = (target & mask) >> shift;
target = target & ~mask | target + (1 << shift) & mask;
return value;
}
inline auto operator--(int) {
auto value = (target & mask) >> shift;
target = target & ~mask | target - (1 << shift) & mask;
return value;
}
inline auto& operator++() {
target = target & ~mask | target + (1 << shift) & mask;
return *this;
}
inline auto& operator--() {
target = target & ~mask | target - (1 << shift) & mask;
return *this;
}
template<typename T> inline auto& operator=(const T& source) {
target = target & ~mask | source << shift & mask;
return *this;
}
template<typename T> inline auto& operator*=(const T& source) {
auto value = ((target & mask) >> shift) * source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator/=(const T& source) {
auto value = ((target & mask) >> shift) / source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator%=(const T& source) {
auto value = ((target & mask) >> shift) % source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator+=(const T& source) {
auto value = ((target & mask) >> shift) + source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator-=(const T& source) {
auto value = ((target & mask) >> shift) - source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator<<=(const T& source) {
auto value = ((target & mask) >> shift) << source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator>>=(const T& source) {
auto value = ((target & mask) >> shift) >> source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator&=(const T& source) {
target = target & (~mask | source << shift & mask);
return *this;
}
template<typename T> inline auto& operator^=(const T& source) {
target = target ^ source << shift & mask;
return *this;
}
template<typename T> inline auto& operator|=(const T& source) {
target = target | source << shift & mask;
return *this;
}
private:
type& target;
};
/* dynamic BitRange */
template<int Precision> struct BitRange<Precision> {
static_assert(Precision >= 1 && Precision <= 64);
enum : uint { bits = Precision };
using type =
conditional_t<bits <= 8, uint8_t,
conditional_t<bits <= 16, uint16_t,
conditional_t<bits <= 32, uint32_t,
conditional_t<bits <= 64, uint64_t,
void>>>>;
BitRange(const BitRange& source) = delete;
inline auto& operator=(const BitRange& source) {
target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
return *this;
}
template<typename T> inline BitRange(T* source, int index) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
if(index < 0) index = Precision + index;
mask = 1ull << index;
shift = index;
}
template<typename T> inline BitRange(T* source, int lo, int hi) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
if(lo < 0) lo = Precision + lo;
if(hi < 0) hi = Precision + hi;
if(lo > hi) swap(lo, hi);
mask = ~0ull >> 64 - (hi - lo + 1) << lo;
shift = lo;
}
inline operator type() const {
return (target & mask) >> shift;
}
inline auto operator++(int) {
auto value = (target & mask) >> shift;
target = target & ~mask | target + (1 << shift) & mask;
return value;
}
inline auto operator--(int) {
auto value = (target & mask) >> shift;
target = target & ~mask | target - (1 << shift) & mask;
return value;
}
inline auto& operator++() {
target = target & ~mask | target + (1 << shift) & mask;
return *this;
}
inline auto& operator--() {
target = target & ~mask | target - (1 << shift) & mask;
return *this;
}
template<typename T> inline auto& operator=(const T& source) {
target = target & ~mask | source << shift & mask;
return *this;
}
template<typename T> inline auto& operator*=(const T& source) {
auto value = ((target & mask) >> shift) * source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator/=(const T& source) {
auto value = ((target & mask) >> shift) / source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator%=(const T& source) {
auto value = ((target & mask) >> shift) % source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator+=(const T& source) {
auto value = ((target & mask) >> shift) + source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator-=(const T& source) {
auto value = ((target & mask) >> shift) - source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator<<=(const T& source) {
auto value = ((target & mask) >> shift) << source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator>>=(const T& source) {
auto value = ((target & mask) >> shift) >> source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> inline auto& operator&=(const T& source) {
target = target & (~mask | source << shift & mask);
return *this;
}
template<typename T> inline auto& operator^=(const T& source) {
target = target ^ source << shift & mask;
return *this;
}
template<typename T> inline auto& operator|=(const T& source) {
target = target | source << shift & mask;
return *this;
}
private:
type& target;
type mask;
uint shift;
};
}

View file

@ -12,59 +12,62 @@ template<uint Precision> struct Integer {
conditional_t<bits() <= 64, int64_t,
void>>>>;
using utype = typename Natural<Precision>::utype;
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - Precision; }
static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; }
inline Integer() : data(0) {}
template<uint Bits> inline Integer(Integer<Bits> value) { data = mask(value); }
template<typename T> inline Integer(const T& value) { data = mask(value); }
explicit inline Integer(const char* value) { data = mask(toInteger(value)); }
template<uint Bits> inline Integer(Integer<Bits> value) { data = cast(value); }
template<typename T> inline Integer(const T& value) { data = cast(value); }
explicit inline Integer(const char* value) { data = cast(toInteger(value)); }
inline operator stype() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
inline auto operator++(int) { auto value = *this; data = cast(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = cast(data - 1); return value; }
inline auto& operator++() { data = mask(data + 1); return *this; }
inline auto& operator--() { data = mask(data - 1); return *this; }
inline auto& operator++() { data = cast(data + 1); return *this; }
inline auto& operator--() { data = cast(data - 1); return *this; }
template<typename T> inline auto& operator =(const T& value) { data = mask( value); return *this; }
template<typename T> inline auto& operator *=(const T& value) { data = mask(data * value); return *this; }
template<typename T> inline auto& operator /=(const T& value) { data = mask(data / value); return *this; }
template<typename T> inline auto& operator %=(const T& value) { data = mask(data % value); return *this; }
template<typename T> inline auto& operator +=(const T& value) { data = mask(data + value); return *this; }
template<typename T> inline auto& operator -=(const T& value) { data = mask(data - value); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { data = mask(data << value); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { data = mask(data >> value); return *this; }
template<typename T> inline auto& operator &=(const T& value) { data = mask(data & value); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { data = mask(data ^ value); return *this; }
template<typename T> inline auto& operator |=(const T& value) { data = mask(data | value); return *this; }
template<typename T> inline auto& operator =(const T& value) { data = cast( value); return *this; }
template<typename T> inline auto& operator *=(const T& value) { data = cast(data * value); return *this; }
template<typename T> inline auto& operator /=(const T& value) { data = cast(data / value); return *this; }
template<typename T> inline auto& operator %=(const T& value) { data = cast(data % value); return *this; }
template<typename T> inline auto& operator +=(const T& value) { data = cast(data + value); return *this; }
template<typename T> inline auto& operator -=(const T& value) { data = cast(data - value); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { data = cast(data << value); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { data = cast(data >> value); return *this; }
template<typename T> inline auto& operator &=(const T& value) { data = cast(data & value); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { data = cast(data ^ value); return *this; }
template<typename T> inline auto& operator |=(const T& value) { data = cast(data | value); return *this; }
inline auto operator()(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto operator()(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Precision> { return {&data, index}; }
inline auto bit(int index) const -> const BitRange<Precision> { return {&data, index}; }
inline auto operator()(int index) const -> const BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto operator()(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int lo, int hi) -> BitRange<Precision> { return {&data, lo, hi}; }
inline auto bit(int lo, int hi) const -> const BitRange<Precision> { return {&data, lo, hi}; }
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto byte(int index) -> BitRange<Precision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto byte(int index) -> BitRange<Precision> { return {&data, index * 8 + 0, index * 8 + 7}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {&data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)*this, lo, hi}; }
inline auto bit(int index) const -> const BitRange<Precision> { return {(utype&)*this, index, index}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto mask(int index) const -> utype {
return data & 1 << index;
}
inline auto mask(int lo, int hi) const -> utype {
return data & (~0ull >> 64 - (hi - lo + 1) << lo);
}
inline auto slice(int index) const { return Natural<>{bit(index)}; }
inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; }
inline auto clamp(uint bits) -> stype {
const int64_t b = 1ull << (bits - 1);
const int64_t b = 1ull << bits - 1;
const int64_t m = b - 1;
return data > m ? m : data < -b ? -b : data;
}
inline auto clip(uint bits) -> stype {
const uint64_t b = 1ull << (bits - 1);
const uint64_t b = 1ull << bits - 1;
const uint64_t m = b * 2 - 1;
return (data & m ^ b) - b;
}
@ -73,7 +76,7 @@ template<uint Precision> struct Integer {
inline auto natural() const -> Natural<Precision>;
private:
inline auto mask(stype value) const -> stype {
inline auto cast(stype value) const -> stype {
return (value & mask() ^ sign()) - sign();
}

View file

@ -11,58 +11,61 @@ template<uint Precision> struct Natural {
conditional_t<bits() <= 32, uint32_t,
conditional_t<bits() <= 64, uint64_t,
void>>>>;
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - Precision; }
inline Natural() : data(0) {}
template<uint Bits> inline Natural(Natural<Bits> value) { data = mask(value); }
template<typename T> inline Natural(const T& value) { data = mask(value); }
explicit inline Natural(const char* value) { data = mask(toNatural(value)); }
template<uint Bits> inline Natural(Natural<Bits> value) { data = cast(value); }
template<typename T> inline Natural(const T& value) { data = cast(value); }
explicit inline Natural(const char* value) { data = cast(toNatural(value)); }
inline operator utype() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
inline auto operator++(int) { auto value = *this; data = cast(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = cast(data - 1); return value; }
inline auto& operator++() { data = mask(data + 1); return *this; }
inline auto& operator--() { data = mask(data - 1); return *this; }
inline auto& operator++() { data = cast(data + 1); return *this; }
inline auto& operator--() { data = cast(data - 1); return *this; }
template<typename T> inline auto& operator =(const T& value) { data = mask( value); return *this; }
template<typename T> inline auto& operator *=(const T& value) { data = mask(data * value); return *this; }
template<typename T> inline auto& operator /=(const T& value) { data = mask(data / value); return *this; }
template<typename T> inline auto& operator %=(const T& value) { data = mask(data % value); return *this; }
template<typename T> inline auto& operator +=(const T& value) { data = mask(data + value); return *this; }
template<typename T> inline auto& operator -=(const T& value) { data = mask(data - value); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { data = mask(data << value); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { data = mask(data >> value); return *this; }
template<typename T> inline auto& operator &=(const T& value) { data = mask(data & value); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { data = mask(data ^ value); return *this; }
template<typename T> inline auto& operator |=(const T& value) { data = mask(data | value); return *this; }
template<typename T> inline auto& operator =(const T& value) { data = cast( value); return *this; }
template<typename T> inline auto& operator *=(const T& value) { data = cast(data * value); return *this; }
template<typename T> inline auto& operator /=(const T& value) { data = cast(data / value); return *this; }
template<typename T> inline auto& operator %=(const T& value) { data = cast(data % value); return *this; }
template<typename T> inline auto& operator +=(const T& value) { data = cast(data + value); return *this; }
template<typename T> inline auto& operator -=(const T& value) { data = cast(data - value); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { data = cast(data << value); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { data = cast(data >> value); return *this; }
template<typename T> inline auto& operator &=(const T& value) { data = cast(data & value); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { data = cast(data ^ value); return *this; }
template<typename T> inline auto& operator |=(const T& value) { data = cast(data | value); return *this; }
inline auto operator()(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto operator()(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Precision> { return {&data, index}; }
inline auto bit(int index) const -> const BitRange<Precision> { return {&data, index}; }
inline auto operator()(int index) const -> const BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto operator()(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int lo, int hi) -> BitRange<Precision> { return {&data, lo, hi}; }
inline auto bit(int lo, int hi) const -> const BitRange<Precision> { return {&data, lo, hi}; }
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto byte(int index) -> BitRange<Precision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto byte(int index) -> BitRange<Precision> { return {&data, index * 8 + 0, index * 8 + 7}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {&data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)data, lo, hi}; }
inline auto bit(int index) const -> const BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto mask(int index) const -> utype {
return data & 1 << index;
}
inline auto mask(int lo, int hi) const -> utype {
return data & (~0ull >> 64 - (hi - lo + 1) << lo);
}
inline auto slice(int index) const { return Natural<>{bit(index)}; }
inline auto slice(int lo, int hi) const { return Natural<>{bits(lo, hi)}; }
inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; }
inline auto clamp(uint bits) -> utype {
const uint64_t b = 1ull << (bits - 1);
const uint64_t b = 1ull << bits - 1;
const uint64_t m = b * 2 - 1;
return data < m ? data : m;
}
inline auto clip(uint bits) -> utype {
const uint64_t b = 1ull << (bits - 1);
const uint64_t b = 1ull << bits - 1;
const uint64_t m = b * 2 - 1;
return data & m;
}
@ -71,7 +74,7 @@ template<uint Precision> struct Natural {
inline auto integer() const -> Integer<Precision>;
private:
inline auto mask(utype value) const -> utype {
inline auto cast(utype value) const -> utype {
return value & mask();
}

View file

@ -52,7 +52,7 @@ template<typename T> auto string::_prepend(const stringify<T>& source) -> string
template<typename T, typename... P> auto string::append(const T& value, P&&... p) -> string& {
_append(make_string(value));
if constexpr(sizeof...(p)) append(forward<P>(p)...);
if constexpr(sizeof...(p) > 0) append(forward<P>(p)...);
return *this;
}

View file

@ -30,6 +30,8 @@ private:
string value;
};
vector<Variable> variables;
bool inMedia = false;
bool inMediaNode = false;
auto parseDocument(const string& filedata, const string& pathname, uint depth) -> bool;
};
@ -57,7 +59,7 @@ inline auto CML::parseDocument(const string& filedata, const string& pathname, u
for(auto& block : filedata.split("\n\n")) {
auto lines = block.stripRight().split("\n");
auto name = lines.takeLeft();
auto name = lines.takeFirst();
if(name.beginsWith("include ")) {
name.trimLeft("include ", 1L);
@ -76,7 +78,16 @@ inline auto CML::parseDocument(const string& filedata, const string& pathname, u
}
state.output.append(name, " {\n");
inMedia = name.beginsWith("@media");
for(auto& line : lines) {
if(inMedia && !line.find(": ")) {
if(inMediaNode) state.output.append(" }\n");
state.output.append(line, " {\n");
inMediaNode = true;
continue;
}
auto data = line.split(":", 1L).strip();
auto name = data(0), value = data(1);
while(auto offset = value.find("var(")) {
@ -93,9 +104,13 @@ inline auto CML::parseDocument(const string& filedata, const string& pathname, u
}
if(!found) break;
}
state.output.append(" ", name, ": ", value, ";\n");
state.output.append(inMedia ? " " : " ", name, ": ", value, ";\n");
if(name == "box-sizing") vendorAppend(name, value);
}
if(inMediaNode) {
state.output.append(" }\n");
inMediaNode = false;
}
state.output.append("}\n\n");
}

View file

@ -90,12 +90,12 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) -
auto content = lines.takeLeft().trimLeft("# ", 1L).split("::", 1L).strip();
auto data = markup(content[0]);
auto name = escape(content(1, data.hash()));
state.output.append("<header id=\"", name, "\">", data);
state.output.append("<h1 id=\"", name, "\">", data);
for(auto& line : lines) {
if(!line.beginsWith("# ")) continue;
state.output.append("<span>", line.trimLeft("# ", 1L), "</span>");
}
state.output.append("</header>\n");
state.output.append("</h1>\n");
}
//header
@ -103,13 +103,13 @@ inline auto DML::parseBlock(string& block, const string& pathname, uint depth) -
auto content = slice(lines.takeLeft(), depth + 1).split("::", 1L).strip();
auto data = markup(content[0]);
auto name = escape(content(1, data.hash()));
if(depth <= 6) {
state.output.append("<h", depth, " id=\"", name, "\">", data);
if(depth <= 5) {
state.output.append("<h", depth + 1, " id=\"", name, "\">", data);
for(auto& line : lines) {
if(count(line, '=') != depth) continue;
state.output.append("<span>", slice(line, depth + 1), "</span>");
}
state.output.append("</h", depth, ">\n");
state.output.append("</h", depth + 1, ">\n");
}
}
@ -215,12 +215,13 @@ inline auto DML::markup(const string& s) -> string {
natural link, linkBase;
natural embed, embedBase;
natural iframe, iframeBase;
for(uint n = 0; n < s.size();) {
char a = s[n];
char b = s[n + 1];
if(!link && !embed) {
if(!link && !embed && !iframe) {
if(a == '*' && b == '*') { t.append(strong.flip() ? "<strong>" : "</strong>"); n += 2; continue; }
if(a == '/' && b == '/') { t.append(emphasis.flip() ? "<em>" : "</em>"); n += 2; continue; }
if(a == '_' && b == '_') { t.append(insertion.flip() ? "<ins>" : "</ins>"); n += 2; continue; }
@ -229,6 +230,9 @@ inline auto DML::markup(const string& s) -> string {
if(a =='\\' && b =='\\') { t.append("<br>"); n += 2; continue; }
}
if(iframe == 0 && a == '<' && b == '<') { t.append("<iframe width='772' height='434' src=\""); iframe = 1; iframeBase = n += 2; continue; }
if(iframe != 0 && a == '>' && b == '>') { t.append("\" frameborder='0' allowfullscreen></iframe>"); iframe = 0; n += 2; continue; }
if(!embed) {
if(link == 0 && a == '[' && b == '[') { t.append("<a href=\""); link = 1; linkBase = n += 2; continue; }
if(link == 1 && a == ':' && b == ':') { t.append("\">"); link = 2; n += 2; continue; }

View file

@ -95,19 +95,8 @@ struct vector_base {
auto removeRight(uint64_t length = 1) -> void;
auto removeLast(uint64_t length = 1) -> void { return removeRight(length); }
auto remove(uint64_t offset, uint64_t length = 1) -> void;
struct RemoveWhere {
RemoveWhere(type& source) : self(source) {}
auto operator==(const T& value) -> type&;
auto operator!=(const T& value) -> type&;
auto operator< (const T& value) -> type&;
auto operator<=(const T& value) -> type&;
auto operator> (const T& value) -> type&;
auto operator>=(const T& value) -> type&;
private:
type& self;
template<typename Compare> auto remove(const T& value) -> type&;
};
auto removeWhere() -> RemoveWhere { return RemoveWhere{*this}; }
auto removeByIndex(uint64_t offset) -> bool;
auto removeByValue(const T& value) -> bool;
auto takeLeft() -> T;
auto takeFirst() -> T { return move(takeLeft()); }
@ -135,32 +124,6 @@ struct vector_base {
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t>;
auto find(const T& value) const -> maybe<uint64_t>;
auto findSorted(const T& value) const -> maybe<uint64_t>;
struct FindWhere {
FindWhere(type& source) : self(source) {}
auto operator==(const T& value) -> vector_base<iterator<T>>;
auto operator!=(const T& value) -> vector_base<iterator<T>>;
auto operator< (const T& value) -> vector_base<iterator<T>>;
auto operator<=(const T& value) -> vector_base<iterator<T>>;
auto operator> (const T& value) -> vector_base<iterator<T>>;
auto operator>=(const T& value) -> vector_base<iterator<T>>;
private:
type& self;
template<typename Compare> auto find(const T& value) -> vector_base<iterator<T>>;
};
auto findWhere() { return FindWhere{*this}; }
struct FindWhereConst {
FindWhereConst(const type& source) : self(source) {}
auto operator==(const T& value) const -> vector_base<iterator_const<T>>;
auto operator!=(const T& value) const -> vector_base<iterator_const<T>>;
auto operator< (const T& value) const -> vector_base<iterator_const<T>>;
auto operator<=(const T& value) const -> vector_base<iterator_const<T>>;
auto operator> (const T& value) const -> vector_base<iterator_const<T>>;
auto operator>=(const T& value) const -> vector_base<iterator_const<T>>;
private:
const type& self;
template<typename Compare> auto find(const T& value) const -> vector_base<iterator_const<T>>;
};
auto findWhere() const { return FindWhereConst{*this}; }
auto foreach(const function<void (const T&)>& callback) -> void;
auto foreach(const function<void (uint, const T&)>& callback) -> void;
@ -171,10 +134,6 @@ protected:
uint64_t _right = 0; //number of allocated elements free on the right of pool
};
template<typename T> auto removeWhere(vector_base<T>& source) { return source.removeWhere(); }
template<typename T> auto findWhere(vector_base<T>& source) { return source.findWhere(); }
template<typename T> auto findWhere(const vector_base<T>& source) { return source.findWhere(); }
}
#define vector vector_base

View file

@ -101,23 +101,14 @@ template<typename T> auto vector<T>::remove(uint64_t offset, uint64_t length) ->
_size -= length;
}
template<typename T> auto vector<T>::RemoveWhere::operator==(const T& value) -> type& { return remove<std::equal_to<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator!=(const T& value) -> type& { return remove<std::not_equal_to<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator< (const T& value) -> type& { return remove<std::less<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator<=(const T& value) -> type& { return remove<std::less_equal<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator> (const T& value) -> type& { return remove<std::greater<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator>=(const T& value) -> type& { return remove<std::greater_equal<T>>(value); }
template<typename T> auto vector<T>::removeByIndex(uint64_t index) -> bool {
if(index < size()) return remove(index), true;
return false;
}
template<typename T> template<typename Compare> auto vector<T>::RemoveWhere::remove(const T& value) -> type& {
auto source = self.begin();
auto target = self.begin();
while(source != self.end()) {
if(source != target) *target = move(*source);
if(!Compare()(*target, value)) ++target;
++source;
}
self.resize(target.offset());
return self;
template<typename T> auto vector<T>::removeByValue(const T& value) -> bool {
if(auto index = find(value)) return remove(*index), true;
return false;
}
//

View file

@ -36,36 +36,6 @@ template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<u
return nothing;
}
template<typename T> auto vector<T>::FindWhere::operator==(const T& value) -> vector<iterator<T>> { return move(find<std::equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator!=(const T& value) -> vector<iterator<T>> { return move(find<std::not_equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator< (const T& value) -> vector<iterator<T>> { return move(find<std::less<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator<=(const T& value) -> vector<iterator<T>> { return move(find<std::less_equal<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator> (const T& value) -> vector<iterator<T>> { return move(find<std::greater<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator>=(const T& value) -> vector<iterator<T>> { return move(find<std::greater_equal<T>>(value)); }
template<typename T> template<typename Compare> auto vector<T>::FindWhere::find(const T& value) -> vector<iterator<T>> {
vector<iterator<T>> found;
for(auto iterator = self.begin(); iterator != self.end(); ++iterator) {
if(Compare()(*iterator, value)) found.append(iterator);
}
return move(found);
}
template<typename T> auto vector<T>::FindWhereConst::operator==(const T& value) const -> vector<iterator_const<T>> { return move(find<std::equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator!=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::not_equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator< (const T& value) const -> vector<iterator_const<T>> { return move(find<std::less<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator<=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::less_equal<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator> (const T& value) const -> vector<iterator_const<T>> { return move(find<std::greater<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator>=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::greater_equal<T>>(value)); }
template<typename T> template<typename Compare> auto vector<T>::FindWhereConst::find(const T& value) const -> vector<iterator_const<T>> {
vector<iterator_const<T>> found;
for(auto iterator = self.begin(); iterator != self.end(); ++iterator) {
if(Compare()(*iterator, value)) found.append(iterator);
}
return move(found);
}
template<typename T> auto vector<T>::foreach(const function<void (const T&)>& callback) -> void {
for(uint64_t n : range(size())) callback(_pool[n]);
}

View file

@ -5,7 +5,7 @@
namespace nall::vfs::fs {
struct file : vfs::file {
static auto open(string location_, mode mode_) -> vfs::shared::file {
static auto open(string location_, mode mode_) -> shared_pointer<vfs::file> {
auto instance = shared_pointer<file>{new file};
if(!instance->_open(location_, mode_)) return {};
return instance;

View file

@ -8,7 +8,7 @@ namespace nall::vfs::memory {
struct file : vfs::file {
~file() { delete[] _data; }
static auto open(const void* data, uintmax size) -> vfs::shared::file {
static auto open(const void* data, uintmax size) -> shared_pointer<vfs::file> {
auto instance = shared_pointer<file>{new file};
instance->_open((const uint8_t*)data, size);
return instance;

View file

@ -67,9 +67,5 @@ struct file {
}
namespace nall::vfs::shared {
using file = shared_pointer<vfs::file>;
}
#include <nall/vfs/fs/file.hpp>
#include <nall/vfs/memory/file.hpp>

View file

@ -2,23 +2,23 @@
#define NALL_XORG_GUARD_HPP
#define Atom XlibAtom
#define Bool XlibBool
#define Display XlibDisplay
#define Font XlibFont
#define Screen XlibScreen
#define Window XlibWindow
#define Above XlibAbove
#define Below XlibBelow
#else
#undef NALL_XORG_GUARD_HPP
#undef Atom
#undef Bool
#undef Display
#undef Font
#undef Screen
#undef Window
#undef Above
#undef Below
#undef Bool
#ifndef NALL_XORG_GUARD_CONSTANTS
#define NALL_XORG_GUARD_CONSTANTS

View file

@ -13,7 +13,7 @@ ifeq ($(ruby),)
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 += audio.oss #audio.openal
ruby += input.sdl input.xlib
endif
endif
@ -58,12 +58,12 @@ ifeq ($(platform),macos)
endif
ifeq ($(platform),linux)
ruby.options += -lX11 -lXext
ruby.options += -lX11 -lXext -lXrandr
ruby.options += $(if $(findstring audio.openal,$(ruby)),-lopenal)
endif
ifeq ($(platform),bsd)
ruby.options += -lX11 -lXext
ruby.options += -lX11 -lXext -lXrandr
ruby.options += $(if $(findstring audio.openal,$(ruby)),-lopenal)
endif

View file

@ -11,6 +11,7 @@ using namespace ruby;
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrandr.h>
#elif defined(DISPLAY_QUARTZ)
#include <nall/macos/guard.hpp>
#include <Cocoa/Cocoa.h>

View file

@ -84,9 +84,12 @@ struct VideoCGL : VideoDriver, OpenGL {
if([view lockFocusIfCanDraw]) {
OpenGL::absoluteWidth = width;
OpenGL::absoluteHeight = height;
OpenGL::outputX = 0;
OpenGL::outputY = 0;
OpenGL::outputWidth = windowWidth;
OpenGL::outputHeight = windowHeight;
OpenGL::output();
[[view openGLContext] flushBuffer];
if(self.flush) glFinish();
[view unlockFocus];

View file

@ -19,11 +19,15 @@ struct VideoDirect3D : VideoDriver {
auto driver() -> string override { return "Direct3D 9.0"; }
auto ready() -> bool override { return _ready; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasExclusive() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasShader() -> bool override { return true; }
auto setFullScreen(bool fullScreen) -> bool override { return initialize(); }
auto setMonitor(string monitor) -> bool override { return initialize(); }
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
auto setContext(uintptr context) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { return true; }
@ -241,19 +245,30 @@ private:
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
POINT point{0, 0};
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX information{};
information.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &information);
_monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
_monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
//Direct3D exclusive mode targets the primary monitor only
if(self.exclusive) {
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirect3D9_Window", L"", WS_VISIBLE | WS_POPUP,
information.rcMonitor.left, information.rcMonitor.top, _monitorWidth, _monitorHeight,
POINT point{0, 0}; //the primary monitor always starts at (0,0)
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX info{};
info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &info);
_monitorX = info.rcMonitor.left;
_monitorY = info.rcMonitor.top;
_monitorWidth = info.rcMonitor.right - info.rcMonitor.left;
_monitorHeight = info.rcMonitor.bottom - info.rcMonitor.top;
}
if(self.fullScreen) {
_context = _window = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirect3D9_Window", L"", WS_VISIBLE | WS_POPUP,
_monitorX, _monitorY, _monitorWidth, _monitorHeight,
nullptr, nullptr, GetModuleHandle(0), nullptr);
} else {
_context = (HWND)self.context;
@ -312,7 +327,7 @@ private:
if(_texture) { _texture->Release(); _texture = nullptr; }
if(_device) { _device->Release(); _device = nullptr; }
if(_instance) { _instance->Release(); _instance = nullptr; }
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
if(_window) { DestroyWindow(_window); _window = nullptr; }
_context = nullptr;
}
@ -323,7 +338,7 @@ private:
bool _ready = false;
HWND _exclusive = nullptr;
HWND _window = nullptr;
HWND _context = nullptr;
LPDIRECT3D9 _instance = nullptr;
LPDIRECT3DDEVICE9 _device = nullptr;
@ -338,8 +353,10 @@ private:
uint _windowHeight;
uint _textureWidth;
uint _textureHeight;
uint _monitorWidth;
uint _monitorHeight;
int _monitorX;
int _monitorY;
int _monitorWidth;
int _monitorHeight;
uint _inputWidth;
uint _inputHeight;

View file

@ -11,18 +11,23 @@ struct VideoDirectDraw : VideoDriver {
~VideoDirectDraw() { destruct(); }
auto create() -> bool override {
super.setShader("Blur");
VideoDriver::shader = "Blur";
return initialize();
}
auto driver() -> string override { return "DirectDraw 7.0"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto setExclusive(bool exclusive) -> bool override {
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setMonitor(bool monitor) -> bool override {
return initialize();
}
@ -118,19 +123,17 @@ private:
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
POINT point{0, 0};
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX information{};
information.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &information);
uint monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
uint monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
if(self.exclusive) {
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirectDraw7_Window", L"", WS_VISIBLE | WS_POPUP,
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
if(self.fullScreen) {
_context = _window = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirectDraw7_Window", L"", WS_VISIBLE | WS_POPUP,
_monitorX, _monitorY, _monitorWidth, _monitorHeight,
nullptr, nullptr, GetModuleHandle(0), nullptr);
} else {
_context = (HWND)self.context;
@ -166,7 +169,7 @@ private:
if(_raster) { _raster->Release(); _raster = nullptr; }
if(_screen) { _screen->Release(); _screen = nullptr; }
if(_interface) { _interface->Release(); _interface = nullptr; }
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
if(_window) { DestroyWindow(_window); _window = nullptr; }
_context = nullptr;
}
@ -213,11 +216,16 @@ private:
bool _ready = false;
int _monitorX = 0;
int _monitorY = 0;
int _monitorWidth = 0;
int _monitorHeight = 0;
uint _width = 0;
uint _height = 0;
HWND _context = nullptr;
HWND _exclusive = nullptr;
HWND _window = nullptr;
LPDIRECTDRAW7 _interface = nullptr;
LPDIRECTDRAWSURFACE7 _screen = nullptr;
LPDIRECTDRAWSURFACE7 _raster = nullptr;

View file

@ -8,17 +8,19 @@ struct VideoGDI : VideoDriver {
~VideoGDI() { destruct(); }
auto create() -> bool override {
super.setShader("None");
VideoDriver::shader = "None";
return initialize();
}
auto driver() -> string override { return "GDI"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
auto setFullScreen(bool fullScreen) -> bool override { return initialize(); }
auto setMonitor(string monitor) -> bool override { return initialize(); }
auto setContext(uintptr context) -> bool override { return initialize(); }
auto size(uint& width, uint& height) -> void override {
@ -96,19 +98,17 @@ private:
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
POINT point{0, 0};
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX information{};
information.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &information);
uint monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
uint monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
if(self.exclusive) {
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoGDI_Window", L"", WS_VISIBLE | WS_POPUP,
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
if(self.fullScreen) {
_context = _window = CreateWindowEx(WS_EX_TOPMOST, L"VideoGDI_Window", L"", WS_VISIBLE | WS_POPUP,
_monitorX, _monitorY, _monitorWidth, _monitorHeight,
nullptr, nullptr, GetModuleHandle(0), nullptr);
} else {
_context = (HWND)self.context;
@ -124,17 +124,22 @@ private:
if(_buffer) { delete[] _buffer; _buffer = nullptr; }
if(_bitmap) { DeleteObject(_bitmap); _bitmap = nullptr; }
if(_dc) { DeleteDC(_dc); _dc = nullptr; }
if(_exclusive) { DestroyWindow(_exclusive); _exclusive = nullptr; }
if(_window) { DestroyWindow(_window); _window = nullptr; }
_context = nullptr;
}
bool _ready = false;
int _monitorX = 0;
int _monitorY = 0;
int _monitorWidth = 0;
int _monitorHeight = 0;
uint32_t* _buffer = nullptr;
uint _width = 0;
uint _height = 0;
HWND _exclusive = nullptr;
HWND _window = nullptr;
HWND _context = nullptr;
HBITMAP _bitmap = nullptr;
HDC _dc = nullptr;

View file

@ -13,26 +13,32 @@ struct VideoGLX : VideoDriver, OpenGL {
~VideoGLX() { destruct(); }
auto create() -> bool override {
super.setFormat("RGB24");
VideoDriver::exclusive = true;
VideoDriver::format = "ARGB24";
return initialize();
}
auto driver() -> string override { return "OpenGL 3.2"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasFlush() -> bool override { return true; }
auto hasShader() -> bool override { return true; }
auto hasFormats() -> vector<string> override {
if(_depth == 30) return {"RGB30", "RGB24"};
if(_depth == 24) return {"RGB24"};
return {"RGB24"}; //fallback
if(_depth == 30) return {"ARGB30", "ARGB24"};
if(_depth == 24) return {"ARGB24"};
return {"ARGB24"}; //fallback
}
auto setExclusive(bool exclusive) -> bool override {
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setMonitor(string monitor) -> bool override {
return initialize();
}
@ -50,12 +56,12 @@ struct VideoGLX : VideoDriver, OpenGL {
}
auto setFormat(string format) -> bool override {
if(format == "RGB24") {
if(format == "ARGB24") {
OpenGL::inputFormat = GL_RGBA8;
return initialize();
}
if(format == "RGB30") {
if(format == "ARGB30") {
OpenGL::inputFormat = GL_RGB10_A2;
return initialize();
}
@ -74,18 +80,15 @@ struct VideoGLX : VideoDriver, OpenGL {
}
auto size(uint& width, uint& height) -> void override {
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
if(self.fullScreen) {
width = _monitorWidth;
height = _monitorHeight;
} else {
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
width = parent.width;
height = parent.height;
}
width = parent.width;
height = parent.height;
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
@ -97,14 +100,28 @@ struct VideoGLX : VideoDriver, OpenGL {
}
auto output(uint width, uint height) -> void override {
uint windowWidth, windowHeight;
size(windowWidth, windowHeight);
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
}
//convert (0,0) from top-left to bottom-left coordinates
auto _height = height ? height : _monitorHeight;
auto _monitorY = parent.height - (this->_monitorY + _height) - (_monitorHeight - _height);
OpenGL::absoluteWidth = width;
OpenGL::absoluteHeight = height;
OpenGL::outputWidth = windowWidth;
OpenGL::outputHeight = windowHeight;
OpenGL::outputX = self.fullScreen ? _monitorX : 0;
OpenGL::outputY = self.fullScreen ? _monitorY : 0;
OpenGL::outputWidth = self.fullScreen ? _monitorWidth : parent.width;
OpenGL::outputHeight = self.fullScreen ? _monitorHeight : parent.height;
OpenGL::output();
if(_doubleBuffer) glXSwapBuffers(_display, _glXWindow);
if(self.flush) glFinish();
}
@ -133,17 +150,12 @@ private:
auto destruct() -> void {
terminate();
if(_display) {
XCloseDisplay(_display);
_display = nullptr;
_screen = 0;
}
XCloseDisplay(_display);
}
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
//require GLX 1.2+ API
glXQueryVersion(_display, &_versionMajor, &_versionMinor);
@ -171,10 +183,16 @@ private:
auto visual = glXGetVisualFromFBConfig(_display, fbConfig[0]);
_parent = self.exclusive ? RootWindow(_display, visual->screen) : (Window)self.context;
_parent = self.fullScreen ? RootWindow(_display, visual->screen) : (Window)self.context;
XWindowAttributes windowAttributes;
XGetWindowAttributes(_display, _parent, &windowAttributes);
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
//(Window)self.context has already been realized, most likely with DefaultVisual.
//GLX requires that the GL output window has the same Visual as the GLX context.
//it is not possible to change the Visual of an already realized (created) window.
@ -183,7 +201,7 @@ private:
XSetWindowAttributes attributes{};
attributes.border_pixel = 0;
attributes.colormap = _colormap;
attributes.override_redirect = self.exclusive;
attributes.override_redirect = self.fullScreen;
_window = XCreateWindow(_display, _parent,
0, 0, windowAttributes.width, windowAttributes.height,
0, visual->depth, InputOutput, visual->visual,
@ -269,6 +287,10 @@ private:
auto (*glXSwapInterval)(int) -> int = nullptr;
Display* _display = nullptr;
uint _monitorX = 0;
uint _monitorY = 0;
uint _monitorWidth = 0;
uint _monitorHeight = 0;
int _screen = 0;
uint _depth = 24; //depth of the default root window
Window _parent = 0;

View file

@ -27,26 +27,32 @@ struct VideoGLX2 : VideoDriver {
~VideoGLX2() { destruct(); }
auto create() -> bool {
super.setFormat("RGB24");
VideoDriver::exclusive = true;
VideoDriver::format = "ARGB24";
return initialize();
}
auto driver() -> string override { return "OpenGL 2.0"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasFlush() -> bool override { return true; }
auto hasShader() -> bool override { return true; }
auto hasFormats() -> vector<string> override {
if(_depth == 30) return {"RGB30", "RGB24"};
if(_depth == 24) return {"RGB24"};
return {"RGB24"}; //fallback
if(_depth == 30) return {"ARGB30", "ARGB24"};
if(_depth == 24) return {"ARGB24"};
return {"ARGB24"}; //fallback
}
auto setExclusive(bool exclusive) -> bool override {
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setMonitor(string monitor) -> bool override {
return initialize();
}
@ -60,12 +66,12 @@ struct VideoGLX2 : VideoDriver {
}
auto setFormat(string format) -> bool override {
if(format == "RGB24") {
if(format == "ARGB24") {
_glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
return initialize();
}
if(format == "RGB30") {
if(format == "ARGB30") {
_glFormat = GL_UNSIGNED_INT_2_10_10_10_REV;
return initialize();
}
@ -86,18 +92,15 @@ struct VideoGLX2 : VideoDriver {
}
auto size(uint& width, uint& height) -> void override {
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
if(self.fullScreen) {
width = _monitorWidth;
height = _monitorHeight;
} else {
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
width = parent.width;
height = parent.height;
}
width = parent.width;
height = parent.height;
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
@ -110,13 +113,30 @@ struct VideoGLX2 : VideoDriver {
}
auto output(uint width, uint height) -> void override {
uint windowWidth, windowHeight;
size(windowWidth, windowHeight);
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
if(!width) width = windowWidth;
if(!height) height = windowHeight;
int x = ((int)windowWidth - (int)width) / 2;
int y = ((int)windowHeight - (int)height) / 2;
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
}
uint viewportX = 0;
uint viewportY = 0;
uint viewportWidth = parent.width;
uint viewportHeight = parent.height;
if(self.fullScreen) {
viewportX = _monitorX;
viewportY = _monitorY;
viewportWidth = _monitorWidth;
viewportHeight = _monitorHeight;
}
if(!width) width = viewportWidth;
if(!height) height = viewportHeight;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
@ -125,24 +145,47 @@ struct VideoGLX2 : VideoDriver {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, 0, windowHeight, -1.0, 1.0);
glViewport(x, y, width, height);
//vertex coordinates range from (0,0) to (1,1) for the entire desktop (all monitors)
glOrtho(0, 1, 0, 1, -1.0, 1.0);
//set the viewport to the entire desktop (all monitors)
glViewport(0, 0, parent.width, parent.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPixelStorei(GL_UNPACK_ROW_LENGTH, _glWidth);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_BGRA, _glFormat, _glBuffer);
//normalize texture coordinates and adjust for NPOT textures
double w = (double)_width / (double)_glWidth;
double h = (double)_height / (double)_glHeight;
int u = windowWidth;
int v = windowHeight;
//size of the active monitor
double mw = (double)viewportWidth / (double)parent.width;
double mh = (double)viewportHeight / (double)parent.height;
//offset of the active monitor
double mx = (double)viewportX / (double)parent.width;
double my = (double)viewportY / (double)parent.height;
//size of the render area
double vw = (double)width / (double)parent.width;
double vh = (double)height / (double)parent.height;
//center the render area within the active monitor
double vl = mx + (mw - vw) / 2;
double vt = my + (mh - vh) / 2;
double vr = vl + vw;
double vb = vt + vh;
//OpenGL places (0,0) at the bottom left; convert our (0,0) at the top left to this form:
vt = 1.0 - vt;
vb = 1.0 - vb;
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
glTexCoord2f(w, 0); glVertex3i(u, v, 0);
glTexCoord2f(0, h); glVertex3i(0, 0, 0);
glTexCoord2f(w, h); glVertex3i(u, 0, 0);
glTexCoord2f(0, 0); glVertex3f(vl, vt, 0);
glTexCoord2f(w, 0); glVertex3f(vr, vt, 0);
glTexCoord2f(0, h); glVertex3f(vl, vb, 0);
glTexCoord2f(w, h); glVertex3f(vr, vb, 0);
glEnd();
glFlush();
@ -174,17 +217,12 @@ private:
auto destruct() -> void {
terminate();
if(_display) {
XCloseDisplay(_display);
_display = nullptr;
_screen = 0;
}
XCloseDisplay(_display);
}
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
int versionMajor = 0, versionMinor = 0;
glXQueryVersion(_display, &versionMajor, &versionMinor);
@ -210,15 +248,21 @@ private:
auto visual = glXGetVisualFromFBConfig(_display, fbConfig[0]);
_parent = self.exclusive ? RootWindow(_display, visual->screen) : (Window)self.context;
_parent = self.fullScreen ? RootWindow(_display, visual->screen) : (Window)self.context;
XWindowAttributes windowAttributes;
XGetWindowAttributes(_display, _parent, &windowAttributes);
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
_colormap = XCreateColormap(_display, RootWindow(_display, visual->screen), visual->visual, AllocNone);
XSetWindowAttributes attributes{};
attributes.border_pixel = 0;
attributes.colormap = _colormap;
attributes.override_redirect = self.exclusive;
attributes.override_redirect = self.fullScreen;
_window = XCreateWindow(_display, _parent,
0, 0, windowAttributes.width, windowAttributes.height,
0, visual->depth, InputOutput, visual->visual,
@ -310,6 +354,10 @@ private:
bool blur = false;
Display* _display = nullptr;
uint _monitorX = 0;
uint _monitorY = 0;
uint _monitorWidth = 0;
uint _monitorHeight = 0;
int _screen = 0;
uint _depth = 24; //depth of the default root window
Window _parent = 0;

View file

@ -148,7 +148,7 @@ auto OpenGL::output() -> void {
glActiveTexture(GL_TEXTURE0);
glrParameters(sources[0].filter, sources[0].wrap);
p.render(sources[0].width, sources[0].height, targetWidth, targetHeight);
p.render(sources[0].width, sources[0].height, 0, 0, targetWidth, targetHeight);
glBindTexture(GL_TEXTURE_2D, p.texture);
p.phase = (p.phase + 1) % p.modulo;
@ -168,7 +168,7 @@ auto OpenGL::output() -> void {
glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
glrParameters(sources[0].filter, sources[0].wrap);
render(sources[0].width, sources[0].height, outputWidth, outputHeight);
render(sources[0].width, sources[0].height, outputX, outputY, outputWidth, outputHeight);
if(history.size() > 0) {
OpenGLTexture frame = history.takeRight();

View file

@ -38,7 +38,7 @@ struct OpenGLSurface : OpenGLTexture {
auto allocate() -> void;
auto size(uint width, uint height) -> void;
auto release() -> void;
auto render(uint sourceWidth, uint sourceHeight, uint targetWidth, uint targetHeight) -> void;
auto render(uint sourceWidth, uint sourceHeight, uint targetX, uint targetY, uint targetWidth, uint targetHeight) -> void;
GLuint program = 0;
GLuint framebuffer = 0;
@ -76,6 +76,8 @@ struct OpenGL : OpenGLProgram {
vector<OpenGLProgram> programs;
vector<OpenGLTexture> history;
GLuint inputFormat = GL_RGBA8;
uint outputX = 0;
uint outputY = 0;
uint outputWidth = 0;
uint outputHeight = 0;
struct Setting {

View file

@ -37,13 +37,14 @@ auto OpenGLSurface::release() -> void {
width = 0, height = 0;
}
auto OpenGLSurface::render(uint sourceWidth, uint sourceHeight, uint targetWidth, uint targetHeight) -> void {
glViewport(0, 0, targetWidth, targetHeight);
auto OpenGLSurface::render(uint sourceWidth, uint sourceHeight, uint targetX, uint targetY, uint targetWidth, uint targetHeight) -> void {
glViewport(targetX, targetY, targetWidth, targetHeight);
float w = (float)sourceWidth / (float)glrSize(sourceWidth);
float h = (float)sourceHeight / (float)glrSize(sourceHeight);
float u = (float)targetWidth, v = (float)targetHeight;
GLint location;
float u = (float)targetWidth;
float v = (float)targetHeight;
GLfloat modelView[] = {
1, 0, 0, 0,

View file

@ -36,6 +36,20 @@
namespace ruby {
auto Video::setFullScreen(bool fullScreen) -> bool {
if(instance->fullScreen == fullScreen) return true;
if(!instance->hasFullScreen()) return false;
if(!instance->setFullScreen(instance->fullScreen = fullScreen)) return false;
return true;
}
auto Video::setMonitor(string monitor) -> bool {
if(instance->monitor == monitor) return true;
if(!instance->hasMonitor()) return false;
if(!instance->setMonitor(instance->monitor = monitor)) return false;
return true;
}
auto Video::setExclusive(bool exclusive) -> bool {
if(instance->exclusive == exclusive) return true;
if(!instance->hasExclusive()) return false;
@ -255,4 +269,113 @@ auto Video::safestDriver() -> string {
#endif
}
#if defined(DISPLAY_WINDOWS)
static auto CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
vector<Video::Monitor>& monitors = *(vector<Video::Monitor>*)dwData;
MONITORINFOEX mi{};
mi.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hMonitor, &mi);
Video::Monitor monitor;
monitor.name = {"Monitor ", 1 + index};
string displayName = (const char*)utf8_t(mi.szDevice);
if(displayName.beginsWith(R"(\\.\DISPLAYV)")) return true; //ignore pseudo-monitors
monitor.primary = mi.dwFlags & MONITORINFOF_PRIMARY;
monitor.x = lprcMonitor->left;
monitor.y = lprcMonitor->top;
monitor.width = lprcMonitor->right - lprcMonitor->left;
monitor.height = lprcMonitor->bottom - lprcMonitor->top;
monitors.append(monitor);
return true;
}
auto Video::hasMonitors() -> vector<Monitor> {
vector<Monitor> monitors;
EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, (LPARAM)&monitors);
vector<Monitor> sorted;
for(auto& monitor : monitors) { if(monitor.primary == 1) sorted.append(monitor); }
for(auto& monitor : monitors) { if(monitor.primary == 0) sorted.append(monitor); }
return sorted;
}
#endif
#if defined(DISPLAY_QUARTZ)
auto Video::hasMonitors() -> vector<Monitor> {
vector<Monitor> monitors;
@autoreleasepool {
uint count = [[NSScreen screens] count];
for(uint index : range(count)) {
NSRect rectangle = [[[NSScreen screens] objectAtindex:index] frame];
Monitor monitor;
monitor.name = {"Monitor ", 1 + index}; //todo: retrieve vendor name here?
monitor.primary = monitors.size() == 0; //on macOS, the primary monitor is always the first monitor.
monitor.x = rectangle.origin.x;
monitor.y = rectangle.origin.y;
monitor.width = rectangle.size.width;
monitor.height = rectangle.size.height;
monitors.append(monitor);
}
}
return monitors;
}
#endif
#if defined(DISPLAY_XORG)
auto Video::hasMonitors() -> vector<Monitor> {
vector<Monitor> monitors;
auto display = XOpenDisplay(nullptr);
auto screen = DefaultScreen(display);
auto rootWindow = RootWindow(display, screen);
auto resources = XRRGetScreenResourcesCurrent(display, rootWindow);
auto primary = XRRGetOutputPrimary(display, rootWindow);
for(uint index : range(resources->noutput)) {
Monitor monitor;
auto output = XRRGetOutputInfo(display, resources, resources->outputs[index]);
if(output->connection != RR_Connected || output->crtc == None) {
XRRFreeOutputInfo(output);
continue;
}
auto crtc = XRRGetCrtcInfo(display, resources, output->crtc);
monitor.name = output->name;
monitor.primary = false;
for(uint n : range(crtc->noutput)) monitor.primary |= crtc->outputs[n] == primary;
monitor.x = crtc->x;
monitor.y = crtc->y;
monitor.width = crtc->width;
monitor.height = crtc->height;
monitors.append(monitor);
XRRFreeCrtcInfo(crtc);
XRRFreeOutputInfo(output);
}
XRRFreeScreenResources(resources);
XCloseDisplay(display);
vector<Monitor> sorted;
for(auto& monitor : monitors) { if(monitor.primary == 1) sorted.append(monitor); }
for(auto& monitor : monitors) { if(monitor.primary == 0) sorted.append(monitor); }
return sorted;
}
#endif
auto Video::monitor(string name) -> Monitor {
auto monitors = Video::hasMonitors();
//try to find by name if possible
for(auto& monitor : monitors) {
if(monitor.name == name) return monitor;
}
//fall back to primary if not found
for(auto& monitor : monitors) {
if(monitor.primary) return monitor;
}
//Video::monitors() should never let this occur
Monitor monitor;
monitor.name = "Primary";
monitor.primary = true;
monitor.x = 0;
monitor.y = 0;
monitor.width = 640;
monitor.height = 480;
return monitor;
}
}

View file

@ -8,15 +8,19 @@ struct VideoDriver {
virtual auto driver() -> string { return "None"; }
virtual auto ready() -> bool { return true; }
virtual auto hasFullScreen() -> bool { return false; }
virtual auto hasMonitor() -> bool { return false; }
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 hasFormats() -> vector<string> { return {"ARGB24"}; }
virtual auto hasShader() -> bool { return false; }
auto hasFormat(string format) -> bool { return (bool)hasFormats().find(format); }
virtual auto setFullScreen(bool fullScreen) -> bool { return true; }
virtual auto setMonitor(string monitor) -> bool { return true; }
virtual auto setExclusive(bool exclusive) -> bool { return true; }
virtual auto setContext(uintptr context) -> bool { return true; }
virtual auto setBlocking(bool blocking) -> bool { return true; }
@ -35,11 +39,13 @@ protected:
Video& super;
friend class Video;
bool fullScreen = false;
string monitor = "Primary";
bool exclusive = false;
uintptr context = 0;
bool blocking = false;
bool flush = false;
string format = "RGB24";
string format = "ARGB24";
string shader = "Blur";
};
@ -49,6 +55,23 @@ struct Video {
static auto optimalDriver() -> string;
static auto safestDriver() -> string;
struct Monitor {
string name;
bool primary = false;
int x = 0;
int y = 0;
int width = 0;
int height = 0;
};
static auto monitor(string name) -> Monitor;
static auto hasMonitors() -> vector<Monitor>;
static auto hasMonitor(string name) -> bool {
for(auto& monitor : hasMonitors()) {
if(monitor.name == name) return true;
}
return false;
}
Video() : self(*this) { reset(); }
explicit operator bool() { return instance->driver() != "None"; }
auto reset() -> void { instance = new VideoDriver(*this); }
@ -56,6 +79,8 @@ struct Video {
auto driver() -> string { return instance->driver(); }
auto ready() -> bool { return instance->ready(); }
auto hasFullScreen() -> bool { return instance->hasFullScreen(); }
auto hasMonitor() -> bool { return instance->hasMonitor(); }
auto hasExclusive() -> bool { return instance->hasExclusive(); }
auto hasContext() -> bool { return instance->hasContext(); }
auto hasBlocking() -> bool { return instance->hasBlocking(); }
@ -65,6 +90,8 @@ struct Video {
auto hasFormat(string format) -> bool { return instance->hasFormat(format); }
auto fullScreen() -> bool { return instance->fullScreen; }
auto monitor() -> string { return instance->monitor; }
auto exclusive() -> bool { return instance->exclusive; }
auto context() -> uintptr { return instance->context; }
auto blocking() -> bool { return instance->blocking; }
@ -72,6 +99,8 @@ struct Video {
auto format() -> string { return instance->format; }
auto shader() -> string { return instance->shader; }
auto setMonitor(string monitor) -> bool;
auto setFullScreen(bool fullScreen) -> bool;
auto setExclusive(bool exclusive) -> bool;
auto setContext(uintptr context) -> bool;
auto setBlocking(bool blocking) -> bool;

View file

@ -19,13 +19,18 @@ struct VideoWGL : VideoDriver, OpenGL {
auto driver() -> string override { return "OpenGL 3.2"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasFlush() -> bool override { return true; }
auto hasShader() -> bool override { return true; }
auto setExclusive(bool exclusive) -> bool override {
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setMonitor(string monitor) -> bool override {
return initialize();
}
@ -52,11 +57,16 @@ struct VideoWGL : VideoDriver, OpenGL {
SwapBuffers(_display);
}
auto size(uint& width, uint& height) -> void {
RECT rectangle;
GetClientRect(_context, &rectangle);
width = rectangle.right - rectangle.left;
height = rectangle.bottom - rectangle.top;
auto size(uint& width, uint& height) -> void override {
if(self.fullScreen) {
width = _monitorWidth;
height = _monitorHeight;
} else {
RECT rectangle;
GetClientRect(_context, &rectangle);
width = rectangle.right - rectangle.left;
height = rectangle.bottom - rectangle.top;
}
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
@ -70,11 +80,15 @@ struct VideoWGL : VideoDriver, OpenGL {
auto output(uint width, uint height) -> void override {
uint windowWidth, windowHeight;
size(windowWidth, windowHeight);
OpenGL::absoluteWidth = width;
OpenGL::absoluteHeight = height;
OpenGL::outputX = 0;
OpenGL::outputY = 0;
OpenGL::outputWidth = windowWidth;
OpenGL::outputHeight = windowHeight;
OpenGL::output();
SwapBuffers(_display);
if(self.flush) glFinish();
}
@ -101,19 +115,17 @@ private:
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
POINT point{0, 0};
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX information{};
information.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &information);
_monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
_monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
if(self.exclusive) {
_context = _exclusive = CreateWindowEx(WS_EX_TOPMOST, L"VideoOpenGL32_Window", L"", WS_VISIBLE | WS_POPUP,
information.rcMonitor.left, information.rcMonitor.top, _monitorWidth, _monitorHeight,
if(self.fullScreen) {
_context = _window = CreateWindowEx(WS_EX_TOPMOST, L"VideoOpenGL32_Window", L"", WS_VISIBLE | WS_POPUP,
_monitorX, _monitorY, _monitorWidth, _monitorHeight,
nullptr, nullptr, GetModuleHandle(0), nullptr);
} else {
_context = (HWND)self.context;
@ -162,9 +174,9 @@ private:
_wglContext = nullptr;
}
if(_exclusive) {
DestroyWindow(_exclusive);
_exclusive = nullptr;
if(_window) {
DestroyWindow(_window);
_window = nullptr;
}
_context = nullptr;
@ -175,10 +187,12 @@ private:
bool _ready = false;
uint _monitorWidth = 0;
uint _monitorHeight = 0;
int _monitorX = 0;
int _monitorY = 0;
int _monitorWidth = 0;
int _monitorHeight = 0;
HWND _exclusive = nullptr;
HWND _window = nullptr;
HWND _context = nullptr;
HDC _display = nullptr;
HGLRC _wglContext = nullptr;

View file

@ -14,19 +14,20 @@ struct VideoXShm : VideoDriver {
~VideoXShm() { destruct(); }
auto create() -> bool override {
VideoDriver::exclusive = true;
return initialize();
}
auto driver() -> string override { return "XShm"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasShader() -> bool override { return true; }
auto hasFormats() -> vector<string> override { return {"RGB24"}; }
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
auto setFullScreen(bool fullScreen) -> bool override { return initialize(); }
auto setMonitor(string monitor) -> bool override { return initialize(); }
auto setContext(uintptr context) -> bool override { return initialize(); }
auto setShader(string shader) -> bool override { return true; }
@ -38,21 +39,15 @@ struct VideoXShm : VideoDriver {
}
auto size(uint& width, uint& height) -> void override {
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
_outputWidth = parent.width;
_outputHeight = parent.height;
XResizeWindow(_display, _window, _outputWidth, _outputHeight);
allocate();
if(self.fullScreen) {
width = _monitorWidth;
height = _monitorHeight;
} else {
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
width = parent.width;
height = parent.height;
}
width = parent.width;
height = parent.height;
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
@ -72,21 +67,44 @@ struct VideoXShm : VideoDriver {
}
auto output(uint width = 0, uint height = 0) -> void override {
uint windowWidth, windowHeight;
size(windowWidth, windowHeight);
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
_outputWidth = parent.width;
_outputHeight = parent.height;
XResizeWindow(_display, _window, _outputWidth, _outputHeight);
allocate();
}
uint viewportX = 0;
uint viewportY = 0;
uint viewportWidth = parent.width;
uint viewportHeight = parent.height;
if(self.fullScreen) {
viewportX = _monitorX;
viewportY = _monitorY;
viewportWidth = _monitorWidth;
viewportHeight = _monitorHeight;
}
if(!_image || !_inputBuffer || !_outputBuffer) return;
if(!width) width = _outputWidth;
if(!height) height = _outputHeight;
if(!width) width = viewportWidth;
if(!height) height = viewportHeight;
float xratio = (float)_inputWidth / (float)width;
float yratio = (float)_inputHeight / (float)height;
int x = ((int)_outputWidth - (int)width) / 2;
int y = ((int)_outputHeight - (int)height) / 2;
int x = ((int)viewportWidth - (int)width) / 2;
int y = ((int)viewportHeight - (int)height) / 2;
width = min(width, _outputWidth);
height = min(height, _outputHeight);
width = min(width, viewportWidth);
height = min(height, viewportHeight);
auto inputBuffer = _inputBuffer;
auto outputBuffer = _outputBuffer;
@ -101,6 +119,9 @@ struct VideoXShm : VideoDriver {
y = 0;
}
x += viewportX;
y += viewportY;
#pragma omp parallel for
for(uint y = 0; y < height; y++) {
float ystep = y * yratio;
@ -148,38 +169,41 @@ private:
}
auto destruct() -> void {
terminate();
XCloseDisplay(_display);
}
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
_parent = self.exclusive ? RootWindow(_display, _screen) : (Window)self.context;
if(!self.fullScreen && !self.context) return false;
_parent = self.fullScreen ? RootWindow(_display, _screen) : (Window)self.context;
XWindowAttributes windowAttributes{};
XGetWindowAttributes(_display, _parent, &windowAttributes);
_outputWidth = windowAttributes.width;
_outputHeight = windowAttributes.height;
_depth = windowAttributes.depth;
_visual = windowAttributes.visual;
//driver only supports 32-bit pixels
//note that even on 15-bit and 16-bit displays, the window visual's depth should be 32
if(_depth < 24 || _depth > 32) {
free();
return false;
}
if(windowAttributes.depth < 24 || windowAttributes.depth > 32) return free(), false;
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
_depth = windowAttributes.depth;
_visual = windowAttributes.visual;
_colormap = XCreateColormap(_display, _parent, _visual, AllocNone);
XSetWindowAttributes attributes{};
attributes.border_pixel = 0;
attributes.colormap = _colormap;
attributes.override_redirect = self.exclusive;
attributes.override_redirect = self.fullScreen;
_window = XCreateWindow(_display, _parent,
0, 0, _outputWidth, _outputHeight,
0, 0, windowAttributes.width, windowAttributes.height,
0, _depth, InputOutput, _visual,
CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes
);
XSelectInput(_display, _window, ExposureMask);
XSetWindowBackground(_display, _window, 0);
XMapWindow(_display, _window);
@ -190,13 +214,22 @@ private:
XNextEvent(_display, &event);
}
_outputWidth = windowAttributes.width;
_outputHeight = windowAttributes.height;
allocate();
return _ready = true;
return _ready = (bool)_outputBuffer;
}
auto terminate() -> void {
_ready = false;
free();
if(_window) {
XUnmapWindow(_display, _window);
_window = 0;
}
if(_colormap) {
XFreeColormap(_display, _colormap);
_colormap = 0;
@ -217,13 +250,15 @@ private:
}
auto free() -> void {
if(_outputBuffer) {
_outputBuffer = nullptr;
if(_image) {
XShmDetach(_display, &_shmInfo);
XDestroyImage(_image);
shmdt(_shmInfo.shmaddr);
shmctl(_shmInfo.shmid, IPC_RMID, 0);
_image = nullptr;
}
_outputBuffer = nullptr;
}
alwaysinline auto interpolate(float mu, uint32_t a, uint32_t b) -> uint32_t {
@ -248,6 +283,10 @@ private:
uint _inputHeight = 0;
Display* _display = nullptr;
uint _monitorX = 0;
uint _monitorY = 0;
uint _monitorWidth = 0;
uint _monitorHeight = 0;
int _screen = 0;
int _depth = 0;
Visual* _visual = nullptr;

View file

@ -12,14 +12,16 @@ struct VideoXVideo : VideoDriver {
~VideoXVideo() { terminate(); }
auto create() -> bool override {
super.setShader("Blur");
VideoDriver::exclusive = true;
VideoDriver::shader = "Blur";
return initialize();
}
auto driver() -> string override { return "XVideo"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasFullScreen() -> bool override { return true; }
auto hasMonitor() -> bool override { return true; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
@ -27,7 +29,11 @@ struct VideoXVideo : VideoDriver {
return _formatNames;
}
auto setExclusive(bool exclusive) -> bool override {
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setMonitor(string monitor) -> bool override {
return initialize();
}
@ -59,18 +65,15 @@ struct VideoXVideo : VideoDriver {
}
auto size(uint& width, uint& height) -> void override {
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
if(self.fullScreen) {
width = _monitorWidth;
height = _monitorHeight;
} else {
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
width = parent.width;
height = parent.height;
}
width = parent.width;
height = parent.height;
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
@ -83,8 +86,27 @@ struct VideoXVideo : VideoDriver {
}
auto output(uint width = 0, uint height = 0) -> void override {
uint windowWidth, windowHeight;
size(windowWidth, windowHeight);
XWindowAttributes window;
XGetWindowAttributes(_display, _window, &window);
XWindowAttributes parent;
XGetWindowAttributes(_display, _parent, &parent);
if(window.width != parent.width || window.height != parent.height) {
XResizeWindow(_display, _window, parent.width, parent.height);
}
uint viewportX = 0;
uint viewportY = 0;
uint viewportWidth = parent.width;
uint viewportHeight = parent.height;
if(self.fullScreen) {
viewportX = _monitorX;
viewportY = _monitorY;
viewportWidth = _monitorWidth;
viewportHeight = _monitorHeight;
}
auto& name = _formatName;
if(name == "RGB24" ) renderRGB24 (_width, _height);
@ -96,10 +118,10 @@ struct VideoXVideo : VideoDriver {
if(name == "YV12" ) renderYV12 (_width, _height);
if(name == "I420" ) renderI420 (_width, _height);
if(!width) width = windowWidth;
if(!height) height = windowHeight;
int x = (windowWidth - width) / 2;
int y = (windowHeight - height) / 2;
if(!width) width = viewportWidth;
if(!height) height = viewportHeight;
int x = viewportX + ((int)viewportWidth - (int)width) / 2;
int y = viewportY + ((int)viewportHeight - (int)height) / 2;
XvShmPutImage(_display, _port, _window, _gc, _image,
0, 0, _width, _height,
@ -122,7 +144,7 @@ struct VideoXVideo : VideoDriver {
private:
auto initialize() -> bool {
terminate();
if(!self.exclusive && !self.context) return false;
if(!self.fullScreen && !self.context) return false;
_display = XOpenDisplay(nullptr);
_screen = DefaultScreen(_display);
@ -169,18 +191,24 @@ private:
return false;
}
_parent = self.exclusive ? RootWindow(_display, _screen) : (Window)self.context;
_parent = self.fullScreen ? RootWindow(_display, _screen) : (Window)self.context;
//create child window to attach to parent window.
//this is so that even if parent window visual depth doesn't match Xv visual
//(common with composited windows), Xv can still render to child window.
XWindowAttributes windowAttributes;
XWindowAttributes windowAttributes{};
XGetWindowAttributes(_display, _parent, &windowAttributes);
auto monitor = Video::monitor(self.monitor);
_monitorX = monitor.x;
_monitorY = monitor.y;
_monitorWidth = monitor.width;
_monitorHeight = monitor.height;
_colormap = XCreateColormap(_display, _parent, visualInfo->visual, AllocNone);
XSetWindowAttributes attributes{};
attributes.border_pixel = 0;
attributes.colormap = _colormap;
attributes.override_redirect = self.exclusive;
attributes.override_redirect = self.fullScreen;
_window = XCreateWindow(_display, _parent,
0, 0, windowAttributes.width, windowAttributes.height,
0, depth, InputOutput, visualInfo->visual,
@ -515,7 +543,11 @@ private:
uint8_t* _vtable = nullptr;
Display* _display = nullptr;
int _screen = 0;
uint _monitorX = 0;
uint _monitorY = 0;
uint _monitorWidth = 0;
uint _monitorHeight = 0;
uint _screen = 0;
GC _gc = 0;
Window _parent = 0;
Window _window = 0;