mirror of https://github.com/bsnes-emu/bsnes.git
v108.9
* multi-monitor support * improved pause/frame advance support * added option to disable video dimming when idle
This commit is contained in:
parent
252f479b22
commit
0b088b6b55
|
@ -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";
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([] {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -67,7 +67,7 @@ auto Program::create() -> void {
|
|||
|
||||
if(gameQueue) load();
|
||||
if(startFullScreen && emulator->loaded()) {
|
||||
presentation.toggleFullscreenMode();
|
||||
toggleVideoFullScreen();
|
||||
}
|
||||
Application::onMain({&Program::main, this});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
1378
hiro/qt/qt.moc
1378
hiro/qt/qt.moc
File diff suppressed because it is too large
Load Diff
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue