mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-09 07:06:29 +02:00
Update to v103r12 release.
byuu says: Changelog: - ruby/video: cleaned up Direct3D9 driver and fixed catastrophic memory leak - ruby/video: added fullscreen exclusive mode support to the Direct3D9 driver¹ - ruby/video: minor cosmetic code cleanups to various drivers - tomoko: added support to always allow input when in fullscreen exclusive mode - tomoko: fixed window to not remove resizability flag when exiting fullscreen mode ¹: I am assuming that exclusive mode will try to capture the primary monitor. I don't know what will happen in multi-monitor setups, however, as I don't use such a setup here. Also, I am using `D3DPRESENT_DISCARD` instead of `D3DPRESENT_FLIP`. I'm not sure if this will prove better or worse, but I've heard it will waste less memory, and having a BackBufferCount of 1 should still result in page flipping anyway. The difference is supposedly just that you can't rely on the back buffer being a valid copy of the previous frame like you can with FLIP. Lastly, if you want Vsync, you can edit the configuration file to enable that, and then turn off audio sync. Errata: "pause emulation when focus is lost" is not working with exclusive mode. I need to add a check to never auto-pause when in exclusive mode. Thanks to bun for catching that one.
This commit is contained in:
@@ -12,7 +12,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "103.11";
|
static const string Version = "103.12";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@@ -30,7 +30,7 @@ Settings::Settings() {
|
|||||||
|
|
||||||
set("Video/Windowed/AspectCorrection", true);
|
set("Video/Windowed/AspectCorrection", true);
|
||||||
set("Video/Windowed/IntegralScaling", true);
|
set("Video/Windowed/IntegralScaling", true);
|
||||||
set("Video/Windowed/AdaptiveSizing", false);
|
set("Video/Windowed/Adaptive", false);
|
||||||
set("Video/Windowed/Scale", "Small");
|
set("Video/Windowed/Scale", "Small");
|
||||||
set("Video/Windowed/Scale/Small", "640x480");
|
set("Video/Windowed/Scale/Small", "640x480");
|
||||||
set("Video/Windowed/Scale/Medium", "960x720");
|
set("Video/Windowed/Scale/Medium", "960x720");
|
||||||
@@ -38,6 +38,7 @@ Settings::Settings() {
|
|||||||
|
|
||||||
set("Video/Fullscreen/AspectCorrection", true);
|
set("Video/Fullscreen/AspectCorrection", true);
|
||||||
set("Video/Fullscreen/IntegralScaling", true);
|
set("Video/Fullscreen/IntegralScaling", true);
|
||||||
|
set("Video/Fullscreen/Exclusive", false);
|
||||||
|
|
||||||
set("Audio/Driver", ruby::Audio::optimalDriver());
|
set("Audio/Driver", ruby::Audio::optimalDriver());
|
||||||
set("Audio/Device", "");
|
set("Audio/Device", "");
|
||||||
|
@@ -96,12 +96,12 @@ auto InputManager::appendHotkeys() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto InputManager::pollHotkeys() -> void {
|
auto InputManager::pollHotkeys() -> void {
|
||||||
if(!presentation || !presentation->focused()) return;
|
if(program->allowInput(true)) {
|
||||||
|
|
||||||
for(auto& hotkey : hotkeys) {
|
for(auto& hotkey : hotkeys) {
|
||||||
int16 state = hotkey->poll();
|
int16 state = hotkey->poll();
|
||||||
if(hotkey->state == 0 && state == 1 && hotkey->press) hotkey->press();
|
if(hotkey->state == 0 && state == 1 && hotkey->press) hotkey->press();
|
||||||
if(hotkey->state == 1 && state == 0 && hotkey->release) hotkey->release();
|
if(hotkey->state == 1 && state == 0 && hotkey->release) hotkey->release();
|
||||||
hotkey->state = state;
|
hotkey->state = state;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -269,7 +269,7 @@ auto Presentation::resizeViewport(bool resizeWindow) -> void {
|
|||||||
viewportHeight = resolution(1).natural();
|
viewportHeight = resolution(1).natural();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(settings["Video/Windowed/AdaptiveSizing"].boolean() && resizeWindow) {
|
if(settings["Video/Windowed/Adaptive"].boolean() && resizeWindow) {
|
||||||
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
||||||
emulatorWidth *= multiplier;
|
emulatorWidth *= multiplier;
|
||||||
emulatorHeight *= multiplier;
|
emulatorHeight *= multiplier;
|
||||||
@@ -312,13 +312,13 @@ auto Presentation::toggleFullScreen() -> void {
|
|||||||
if(!fullScreen()) {
|
if(!fullScreen()) {
|
||||||
menuBar.setVisible(false);
|
menuBar.setVisible(false);
|
||||||
statusBar.setVisible(false);
|
statusBar.setVisible(false);
|
||||||
setResizable(true);
|
|
||||||
setFullScreen(true);
|
setFullScreen(true);
|
||||||
|
video->set(Video::Exclusive, settings["Video/Fullscreen/Exclusive"].boolean());
|
||||||
if(!input->acquired()) input->acquire();
|
if(!input->acquired()) input->acquire();
|
||||||
} else {
|
} else {
|
||||||
if(input->acquired()) input->release();
|
if(input->acquired()) input->release();
|
||||||
|
video->set(Video::Exclusive, false);
|
||||||
setFullScreen(false);
|
setFullScreen(false);
|
||||||
setResizable(false);
|
|
||||||
menuBar.setVisible(true);
|
menuBar.setVisible(true);
|
||||||
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,7 @@ auto Program::audioSample(const double* samples, uint channels) -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
||||||
if(presentation->focused() || settings["Input/FocusLoss/AllowInput"].boolean()) {
|
if(allowInput()) {
|
||||||
inputManager->poll();
|
inputManager->poll();
|
||||||
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
|
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
|
||||||
return mapping.poll();
|
return mapping.poll();
|
||||||
@@ -105,7 +105,7 @@ auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> void {
|
auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> void {
|
||||||
if(presentation->focused() || settings["Input/FocusLoss/AllowInput"].boolean() || !enable) {
|
if(allowInput() || !enable) {
|
||||||
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
|
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
|
||||||
return mapping.rumble(enable);
|
return mapping.rumble(enable);
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,7 @@ struct Program : Emulator::Platform {
|
|||||||
auto updateVideoShader() -> void;
|
auto updateVideoShader() -> void;
|
||||||
auto updateAudioDriver() -> void;
|
auto updateAudioDriver() -> void;
|
||||||
auto updateAudioEffects() -> void;
|
auto updateAudioEffects() -> void;
|
||||||
|
auto allowInput(bool hotkey = false) -> bool;
|
||||||
|
|
||||||
bool hasQuit = false;
|
bool hasQuit = false;
|
||||||
bool pause = false;
|
bool pause = false;
|
||||||
|
@@ -92,3 +92,17 @@ auto Program::updateAudioEffects() -> void {
|
|||||||
auto reverbEnable = settings["Audio/Reverb/Enable"].boolean();
|
auto reverbEnable = settings["Audio/Reverb/Enable"].boolean();
|
||||||
Emulator::audio.setReverb(reverbEnable);
|
Emulator::audio.setReverb(reverbEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Program::allowInput(bool hotkey) -> bool {
|
||||||
|
//exclusive mode creates its own top-level window: presentation window will not have focus
|
||||||
|
if(video->cap(Video::Exclusive)) {
|
||||||
|
auto value = video->get(Video::Exclusive);
|
||||||
|
if(value.is<bool>() && value.get<bool>()) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(presentation && presentation->focused()) return true;
|
||||||
|
|
||||||
|
if(!hotkey && settings["Input/FocusLoss/AllowInput"].boolean()) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -32,7 +32,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||||||
resamplerCombo.append(ComboButtonItem().setText("IIR - Biquad"));
|
resamplerCombo.append(ComboButtonItem().setText("IIR - Biquad"));
|
||||||
resamplerCombo.setEnabled(false);
|
resamplerCombo.setEnabled(false);
|
||||||
|
|
||||||
exclusiveMode.setText("Exclusive Mode");
|
exclusiveMode.setText("Exclusive mode");
|
||||||
exclusiveMode.setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] { updateDriver(); });
|
exclusiveMode.setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] { updateDriver(); });
|
||||||
if(!audio->cap(Audio::Exclusive)) exclusiveMode.remove();
|
if(!audio->cap(Audio::Exclusive)) exclusiveMode.remove();
|
||||||
|
|
||||||
|
@@ -28,11 +28,12 @@ struct VideoSettings : TabFrameItem {
|
|||||||
HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}};
|
HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}};
|
||||||
CheckLabel windowedModeAspectCorrection{&windowedModeLayout, Size{0, 0}};
|
CheckLabel windowedModeAspectCorrection{&windowedModeLayout, Size{0, 0}};
|
||||||
CheckLabel windowedModeIntegralScaling{&windowedModeLayout, Size{0, 0}};
|
CheckLabel windowedModeIntegralScaling{&windowedModeLayout, Size{0, 0}};
|
||||||
CheckLabel windowedModeAdaptiveSizing{&windowedModeLayout, Size{0, 0}};
|
CheckLabel windowedModeAdaptive{&windowedModeLayout, Size{0, 0}};
|
||||||
Label fullscreenModeLabel{&layout, Size{~0, 0}, 2};
|
Label fullscreenModeLabel{&layout, Size{~0, 0}, 2};
|
||||||
HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}};
|
HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}};
|
||||||
CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}};
|
CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}};
|
||||||
CheckLabel fullscreenModeIntegralScaling{&fullscreenModeLayout, Size{0, 0}};
|
CheckLabel fullscreenModeIntegralScaling{&fullscreenModeLayout, Size{0, 0}};
|
||||||
|
CheckLabel fullscreenModeExclusive{&fullscreenModeLayout, Size{0, 0}};
|
||||||
|
|
||||||
auto updateColor(bool initializing = false) -> void;
|
auto updateColor(bool initializing = false) -> void;
|
||||||
auto updateViewport(bool initializing = false) -> void;
|
auto updateViewport(bool initializing = false) -> void;
|
||||||
|
@@ -26,11 +26,13 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||||||
windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode");
|
windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode");
|
||||||
windowedModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Windowed/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
windowedModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Windowed/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
windowedModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Windowed/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
windowedModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Windowed/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
windowedModeAdaptiveSizing.setText("Adaptive sizing").setChecked(settings["Video/Windowed/AdaptiveSizing"].boolean()).onToggle([&] { updateViewport(); });
|
windowedModeAdaptive.setText("Adaptive sizing").setChecked(settings["Video/Windowed/Adaptive"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
|
||||||
fullscreenModeLabel.setFont(Font().setBold()).setText("Fullscreen Mode");
|
fullscreenModeLabel.setFont(Font().setBold()).setText("Fullscreen Mode");
|
||||||
fullscreenModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Fullscreen/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
fullscreenModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Fullscreen/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
fullscreenModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Fullscreen/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
fullscreenModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Fullscreen/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
fullscreenModeExclusive.setText("Exclusive mode").setChecked(settings["Video/Fullscreen/Exclusive"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
if(!video->cap(Video::Exclusive)) fullscreenModeExclusive.remove();
|
||||||
|
|
||||||
updateColor(true);
|
updateColor(true);
|
||||||
updateViewport(true);
|
updateViewport(true);
|
||||||
@@ -48,16 +50,17 @@ auto VideoSettings::updateColor(bool initializing) -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto VideoSettings::updateViewport(bool initializing) -> void {
|
auto VideoSettings::updateViewport(bool initializing) -> void {
|
||||||
bool wasAdaptive = settings["Video/Windowed/AdaptiveSizing"].boolean();
|
bool wasAdaptive = settings["Video/Windowed/Adaptive"].boolean();
|
||||||
bool isAdaptive = windowedModeAdaptiveSizing.checked();
|
bool isAdaptive = windowedModeAdaptive.checked();
|
||||||
|
|
||||||
settings["Video/Overscan/Horizontal"].setValue(horizontalMaskSlider.position());
|
settings["Video/Overscan/Horizontal"].setValue(horizontalMaskSlider.position());
|
||||||
settings["Video/Overscan/Vertical"].setValue(verticalMaskSlider.position());
|
settings["Video/Overscan/Vertical"].setValue(verticalMaskSlider.position());
|
||||||
settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked());
|
settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked());
|
||||||
settings["Video/Windowed/IntegralScaling"].setValue(windowedModeIntegralScaling.checked());
|
settings["Video/Windowed/IntegralScaling"].setValue(windowedModeIntegralScaling.checked());
|
||||||
settings["Video/Windowed/AdaptiveSizing"].setValue(windowedModeAdaptiveSizing.checked());
|
settings["Video/Windowed/Adaptive"].setValue(windowedModeAdaptive.checked());
|
||||||
settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked());
|
settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked());
|
||||||
settings["Video/Fullscreen/IntegralScaling"].setValue(fullscreenModeIntegralScaling.checked());
|
settings["Video/Fullscreen/IntegralScaling"].setValue(fullscreenModeIntegralScaling.checked());
|
||||||
|
settings["Video/Fullscreen/Exclusive"].setValue(fullscreenModeExclusive.checked());
|
||||||
horizontalMaskValue.setText({horizontalMaskSlider.position()});
|
horizontalMaskValue.setText({horizontalMaskSlider.position()});
|
||||||
verticalMaskValue.setText({verticalMaskSlider.position()});
|
verticalMaskValue.setText({verticalMaskSlider.position()});
|
||||||
|
|
||||||
|
@@ -72,14 +72,15 @@ using namespace ruby;
|
|||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
|
const string Video::Exclusive = "Exclusive";
|
||||||
const string Video::Handle = "Handle";
|
const string Video::Handle = "Handle";
|
||||||
const string Video::Synchronize = "Synchronize";
|
const string Video::Synchronize = "Synchronize";
|
||||||
const string Video::Depth = "Depth";
|
const string Video::Depth = "Depth";
|
||||||
const string Video::Filter = "Filter";
|
const string Video::Filter = "Filter";
|
||||||
const string Video::Shader = "Shader";
|
const string Video::Shader = "Shader";
|
||||||
|
|
||||||
const unsigned Video::FilterNearest = 0;
|
const uint Video::FilterNearest = 0;
|
||||||
const unsigned Video::FilterLinear = 1;
|
const uint Video::FilterLinear = 1;
|
||||||
|
|
||||||
auto Video::create(const string& driver) -> Video* {
|
auto Video::create(const string& driver) -> Video* {
|
||||||
if(!driver) return create(optimalDriver());
|
if(!driver) return create(optimalDriver());
|
||||||
@@ -89,11 +90,11 @@ auto Video::create(const string& driver) -> Video* {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECT3D)
|
#if defined(VIDEO_DIRECT3D)
|
||||||
if(driver == "Direct3D") return new VideoD3D;
|
if(driver == "Direct3D") return new VideoDirect3D;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECTDRAW)
|
#if defined(VIDEO_DIRECTDRAW)
|
||||||
if(driver == "DirectDraw") return new VideoDD;
|
if(driver == "DirectDraw") return new VideoDirectDraw;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GDI)
|
#if defined(VIDEO_GDI)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
/* ruby
|
/* ruby
|
||||||
* author: byuu
|
* author: byuu
|
||||||
* license: ISC
|
* license: ISC
|
||||||
* version: 0.15 (2016-04-18)
|
* version: 0.16 (2017-07-08)
|
||||||
*
|
*
|
||||||
* ruby is a cross-platform hardware abstraction layer.
|
* ruby is a cross-platform hardware abstraction layer.
|
||||||
* it provides a common interface to video, audio and input devices.
|
* it provides a common interface to video, audio and input devices.
|
||||||
@@ -14,14 +14,15 @@
|
|||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
struct Video {
|
struct Video {
|
||||||
|
static const nall::string Exclusive;
|
||||||
static const nall::string Handle;
|
static const nall::string Handle;
|
||||||
static const nall::string Synchronize;
|
static const nall::string Synchronize;
|
||||||
static const nall::string Depth;
|
static const nall::string Depth;
|
||||||
static const nall::string Filter;
|
static const nall::string Filter;
|
||||||
static const nall::string Shader;
|
static const nall::string Shader;
|
||||||
|
|
||||||
static const unsigned FilterNearest;
|
static const uint FilterNearest;
|
||||||
static const unsigned FilterLinear;
|
static const uint FilterLinear;
|
||||||
|
|
||||||
static auto create(const nall::string& driver = "") -> Video*;
|
static auto create(const nall::string& driver = "") -> Video*;
|
||||||
static auto optimalDriver() -> nall::string;
|
static auto optimalDriver() -> nall::string;
|
||||||
@@ -34,7 +35,7 @@ struct Video {
|
|||||||
virtual auto get(const nall::string& name) -> nall::any { return false; }
|
virtual auto get(const nall::string& name) -> nall::any { return false; }
|
||||||
virtual auto set(const nall::string& name, const nall::any& value) -> bool { return false; }
|
virtual auto set(const nall::string& name, const nall::any& value) -> bool { return false; }
|
||||||
|
|
||||||
virtual auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { return false; }
|
virtual auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
||||||
virtual auto unlock() -> void {}
|
virtual auto unlock() -> void {}
|
||||||
virtual auto clear() -> void {}
|
virtual auto clear() -> void {}
|
||||||
virtual auto refresh() -> void {}
|
virtual auto refresh() -> void {}
|
||||||
@@ -96,13 +97,13 @@ struct Input {
|
|||||||
virtual auto init() -> bool { return true; }
|
virtual auto init() -> bool { return true; }
|
||||||
virtual auto term() -> void {}
|
virtual auto term() -> void {}
|
||||||
|
|
||||||
auto onChange(const nall::function<void (nall::shared_pointer<nall::HID::Device>, unsigned, unsigned, int16_t, int16_t)>& callback) { _onChange = callback; }
|
auto onChange(const nall::function<void (nall::shared_pointer<nall::HID::Device>, uint, uint, int16_t, int16_t)>& callback) { _onChange = callback; }
|
||||||
auto doChange(nall::shared_pointer<nall::HID::Device> device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) -> void {
|
auto doChange(nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
|
||||||
if(_onChange) _onChange(device, group, input, oldValue, newValue);
|
if(_onChange) _onChange(device, group, input, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nall::function<void (nall::shared_pointer<nall::HID::Device> device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue)> _onChange;
|
nall::function<void (nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> _onChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,67 +1,87 @@
|
|||||||
#undef interface
|
#undef interface
|
||||||
#define interface struct
|
#define interface struct
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
#include <d3dx9.h>
|
|
||||||
#undef interface
|
#undef interface
|
||||||
|
|
||||||
#define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1)
|
static LRESULT CALLBACK VideoDirect3D_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||||
|
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
typedef HRESULT (__stdcall* EffectProc)(LPDIRECT3DDEVICE9, LPCVOID, UINT, D3DXMACRO const*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*, LPD3DXBUFFER*);
|
struct VideoDirect3D : Video {
|
||||||
typedef HRESULT (__stdcall* TextureProc)(LPDIRECT3DDEVICE9, LPCTSTR, LPDIRECT3DTEXTURE9*);
|
VideoDirect3D() {
|
||||||
|
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;
|
||||||
|
|
||||||
struct VideoD3D : Video {
|
WNDCLASS windowClass = {};
|
||||||
~VideoD3D() { term(); }
|
windowClass.cbClsExtra = 0;
|
||||||
|
windowClass.cbWndExtra = 0;
|
||||||
|
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||||
|
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
||||||
|
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||||
|
windowClass.hInstance = GetModuleHandle(0);
|
||||||
|
windowClass.lpfnWndProc = VideoDirect3D_WindowProcedure;
|
||||||
|
windowClass.lpszClassName = L"VideoDirect3D_Window";
|
||||||
|
windowClass.lpszMenuName = 0;
|
||||||
|
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
RegisterClass(&windowClass);
|
||||||
|
|
||||||
LPDIRECT3D9 lpd3d = nullptr;
|
settings.exclusiveHandle = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirect3D_Window", L"", WS_POPUP,
|
||||||
|
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
|
||||||
|
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
~VideoDirect3D() {
|
||||||
|
term();
|
||||||
|
DestroyWindow(settings.exclusiveHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
LPDIRECT3D9 context = nullptr;
|
||||||
LPDIRECT3DDEVICE9 device = nullptr;
|
LPDIRECT3DDEVICE9 device = nullptr;
|
||||||
LPDIRECT3DVERTEXBUFFER9 vertex_buffer = nullptr;
|
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = nullptr;
|
||||||
LPDIRECT3DVERTEXBUFFER9* vertex_ptr = nullptr;
|
D3DPRESENT_PARAMETERS presentation = {};
|
||||||
D3DPRESENT_PARAMETERS presentation;
|
D3DCAPS9 capabilities = {};
|
||||||
D3DSURFACE_DESC d3dsd;
|
|
||||||
D3DLOCKED_RECT d3dlr;
|
|
||||||
D3DRASTER_STATUS d3drs;
|
|
||||||
D3DCAPS9 d3dcaps;
|
|
||||||
LPDIRECT3DTEXTURE9 texture = nullptr;
|
LPDIRECT3DTEXTURE9 texture = nullptr;
|
||||||
LPDIRECT3DSURFACE9 surface = nullptr;
|
LPDIRECT3DSURFACE9 surface = nullptr;
|
||||||
LPD3DXEFFECT effect = nullptr;
|
|
||||||
string shader_source_markup;
|
|
||||||
|
|
||||||
bool lost = true;
|
bool lost = true;
|
||||||
unsigned iwidth;
|
uint windowWidth;
|
||||||
unsigned iheight;
|
uint windowHeight;
|
||||||
|
uint textureWidth;
|
||||||
|
uint textureHeight;
|
||||||
|
uint monitorWidth;
|
||||||
|
uint monitorHeight;
|
||||||
|
|
||||||
struct d3dvertex {
|
struct Vertex {
|
||||||
float x, y, z, rhw; //screen coords
|
float x, y, z, rhw; //screen coordinates
|
||||||
float u, v; //texture coords
|
float u, v; //texture coordinates
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t t_usage, v_usage;
|
uint32_t textureUsage;
|
||||||
uint32_t t_pool, v_pool;
|
uint32_t texturePool;
|
||||||
uint32_t lock;
|
uint32_t vertexUsage;
|
||||||
|
uint32_t vertexPool;
|
||||||
uint32_t filter;
|
uint32_t filter;
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool dynamic; //device supports dynamic textures
|
bool exclusive = false;
|
||||||
bool shader; //device supports pixel shaders
|
|
||||||
} caps;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
HWND handle = nullptr;
|
HWND handle = nullptr;
|
||||||
bool synchronize = false;
|
bool synchronize = false;
|
||||||
unsigned filter = Video::FilterLinear;
|
uint filter = Video::FilterLinear;
|
||||||
|
|
||||||
unsigned width;
|
HWND exclusiveHandle = nullptr;
|
||||||
unsigned height;
|
uint width;
|
||||||
|
uint height;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned width;
|
|
||||||
unsigned height;
|
|
||||||
} state;
|
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
|
if(name == Video::Exclusive) return true;
|
||||||
if(name == Video::Handle) return true;
|
if(name == Video::Handle) return true;
|
||||||
if(name == Video::Synchronize) return true;
|
if(name == Video::Synchronize) return true;
|
||||||
if(name == Video::Filter) return true;
|
if(name == Video::Filter) return true;
|
||||||
@@ -70,6 +90,7 @@ struct VideoD3D : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto get(const string& name) -> any {
|
auto get(const string& name) -> any {
|
||||||
|
if(name == Video::Exclusive) return settings.exclusive;
|
||||||
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
||||||
if(name == Video::Synchronize) return settings.synchronize;
|
if(name == Video::Synchronize) return settings.synchronize;
|
||||||
if(name == Video::Filter) return settings.filter;
|
if(name == Video::Filter) return settings.filter;
|
||||||
@@ -77,8 +98,14 @@ struct VideoD3D : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
if(name == Video::Exclusive && value.is<bool>()) {
|
||||||
settings.handle = (HWND)value.get<uintptr_t>();
|
settings.exclusive = value.get<bool>();
|
||||||
|
if(context) init();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == Video::Handle && value.is<uintptr>()) {
|
||||||
|
settings.handle = (HWND)value.get<uintptr>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +114,12 @@ struct VideoD3D : Video {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == Video::Filter && value.is<unsigned>()) {
|
if(name == Video::Filter && value.is<uint>()) {
|
||||||
settings.filter = value.get<unsigned>();
|
settings.filter = value.get<uint>();
|
||||||
if(lpd3d) update_filter();
|
if(context) updateFilter();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == Video::Shader && value.is<string>()) {
|
|
||||||
return false;
|
|
||||||
//set_shader(value.get<string>());
|
|
||||||
//return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +127,11 @@ struct VideoD3D : Video {
|
|||||||
if(!device) return false;
|
if(!device) return false;
|
||||||
|
|
||||||
if(lost) {
|
if(lost) {
|
||||||
release_resources();
|
if(vertexBuffer) { vertexBuffer->Release(); vertexBuffer = nullptr; }
|
||||||
|
if(surface) { surface->Release(); surface = nullptr; }
|
||||||
|
if(texture) { texture->Release(); texture = nullptr; }
|
||||||
if(device->Reset(&presentation) != D3D_OK) return false;
|
if(device->Reset(&presentation) != D3D_OK) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lost = false;
|
lost = false;
|
||||||
|
|
||||||
device->SetDialogBoxMode(false);
|
device->SetDialogBoxMode(false);
|
||||||
@@ -130,70 +152,49 @@ struct VideoD3D : Video {
|
|||||||
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||||
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
||||||
|
|
||||||
device->SetVertexShader(NULL);
|
device->SetVertexShader(nullptr);
|
||||||
device->SetFVF(D3DVERTEX);
|
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
|
||||||
|
|
||||||
device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, (D3DPOOL)flags.v_pool, &vertex_buffer, NULL);
|
device->CreateVertexBuffer(sizeof(Vertex) * 4, flags.vertexUsage, D3DFVF_XYZRHW | D3DFVF_TEX1,
|
||||||
iwidth = 0;
|
(D3DPOOL)flags.vertexPool, &vertexBuffer, nullptr);
|
||||||
iheight = 0;
|
textureWidth = 0;
|
||||||
|
textureHeight = 0;
|
||||||
resize(settings.width = 256, settings.height = 256);
|
resize(settings.width = 256, settings.height = 256);
|
||||||
update_filter();
|
updateFilter();
|
||||||
clear();
|
clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rounded_power_of_two(unsigned n) -> unsigned {
|
auto resize(uint width, uint height) -> void {
|
||||||
n--;
|
if(textureWidth >= width && textureHeight >= height) return;
|
||||||
n |= n >> 1;
|
|
||||||
n |= n >> 2;
|
|
||||||
n |= n >> 4;
|
|
||||||
n |= n >> 8;
|
|
||||||
n |= n >> 16;
|
|
||||||
return n + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto resize(unsigned width, unsigned height) -> void {
|
textureWidth = bit::round(max(width, textureWidth));
|
||||||
if(iwidth >= width && iheight >= height) return;
|
textureHeight = bit::round(max(height, textureHeight));
|
||||||
|
|
||||||
iwidth = rounded_power_of_two(max(width, iwidth ));
|
if(capabilities.MaxTextureWidth < textureWidth || capabilities.MaxTextureWidth < textureHeight) return;
|
||||||
iheight = rounded_power_of_two(max(height, iheight));
|
|
||||||
|
|
||||||
if(d3dcaps.MaxTextureWidth < iwidth || d3dcaps.MaxTextureWidth < iheight) {
|
|
||||||
//TODO: attempt to handle this more gracefully
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(texture) texture->Release();
|
if(texture) texture->Release();
|
||||||
device->CreateTexture(iwidth, iheight, 1, flags.t_usage, D3DFMT_X8R8G8B8, (D3DPOOL)flags.t_pool, &texture, NULL);
|
device->CreateTexture(textureWidth, textureHeight, 1, flags.textureUsage, D3DFMT_X8R8G8B8,
|
||||||
|
(D3DPOOL)flags.texturePool, &texture, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto update_filter() -> void {
|
auto updateFilter() -> void {
|
||||||
if(!device) return;
|
if(!device) return;
|
||||||
if(lost && !recover()) return;
|
if(lost && !recover()) return;
|
||||||
|
|
||||||
flags.filter = (settings.filter == Video::FilterNearest ? D3DTEXF_POINT : D3DTEXF_LINEAR);
|
flags.filter = settings.filter == Video::FilterNearest ? D3DTEXF_POINT : D3DTEXF_LINEAR;
|
||||||
device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter);
|
device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter);
|
||||||
device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter);
|
device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex format:
|
//(x,y) screen coordinates, in pixels
|
||||||
//
|
//(u,v) texture coordinates, betweeen 0.0 (top, left) to 1.0 (bottom, right)
|
||||||
// 0----------1
|
auto setVertex(
|
||||||
// | /|
|
|
||||||
// | / |
|
|
||||||
// | / |
|
|
||||||
// | / |
|
|
||||||
// | / |
|
|
||||||
// 2----------3
|
|
||||||
//
|
|
||||||
// (x,y) screen coords, in pixels
|
|
||||||
// (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right)
|
|
||||||
auto set_vertex(
|
|
||||||
uint32_t px, uint32_t py, uint32_t pw, uint32_t ph,
|
uint32_t px, uint32_t py, uint32_t pw, uint32_t ph,
|
||||||
uint32_t tw, uint32_t th,
|
uint32_t tw, uint32_t th,
|
||||||
uint32_t x, uint32_t y, uint32_t w, uint32_t h
|
uint32_t x, uint32_t y, uint32_t w, uint32_t h
|
||||||
) -> void {
|
) -> void {
|
||||||
d3dvertex vertex[4];
|
Vertex vertex[4];
|
||||||
vertex[0].x = vertex[2].x = (double)(x - 0.5);
|
vertex[0].x = vertex[2].x = (double)(x - 0.5);
|
||||||
vertex[1].x = vertex[3].x = (double)(x + w - 0.5);
|
vertex[1].x = vertex[3].x = (double)(x + w - 0.5);
|
||||||
vertex[0].y = vertex[1].y = (double)(y - 0.5);
|
vertex[0].y = vertex[1].y = (double)(y - 0.5);
|
||||||
@@ -210,17 +211,19 @@ struct VideoD3D : Video {
|
|||||||
vertex[0].v = vertex[1].v = (double)(py ) / rh;
|
vertex[0].v = vertex[1].v = (double)(py ) / rh;
|
||||||
vertex[2].v = vertex[3].v = (double)(py + h) / rh;
|
vertex[2].v = vertex[3].v = (double)(py + h) / rh;
|
||||||
|
|
||||||
vertex_buffer->Lock(0, sizeof(d3dvertex) * 4, (void**)&vertex_ptr, 0);
|
LPDIRECT3DVERTEXBUFFER9* vertexPointer = nullptr;
|
||||||
memcpy(vertex_ptr, vertex, sizeof(d3dvertex) * 4);
|
vertexBuffer->Lock(0, sizeof(Vertex) * 4, (void**)&vertexPointer, 0);
|
||||||
vertex_buffer->Unlock();
|
memory::copy(vertexPointer, vertex, sizeof(Vertex) * 4);
|
||||||
|
vertexBuffer->Unlock();
|
||||||
|
|
||||||
device->SetStreamSource(0, vertex_buffer, 0, sizeof(d3dvertex));
|
device->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clear() -> void {
|
auto clear() -> void {
|
||||||
if(lost && !recover()) return;
|
if(lost && !recover()) return;
|
||||||
|
|
||||||
texture->GetLevelDesc(0, &d3dsd);
|
D3DSURFACE_DESC surfaceDescription;
|
||||||
|
texture->GetLevelDesc(0, &surfaceDescription);
|
||||||
texture->GetSurfaceLevel(0, &surface);
|
texture->GetSurfaceLevel(0, &surface);
|
||||||
|
|
||||||
if(surface) {
|
if(surface) {
|
||||||
@@ -230,25 +233,27 @@ struct VideoD3D : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//clear primary display and all backbuffers
|
//clear primary display and all backbuffers
|
||||||
for(unsigned i = 0; i < 3; i++) {
|
for(uint n : range(3)) {
|
||||||
device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0);
|
device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0);
|
||||||
device->Present(0, 0, 0, 0);
|
device->Present(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
if(lost && !recover()) return false;
|
if(lost && !recover()) return false;
|
||||||
|
|
||||||
if(width != settings.width || height != settings.height) {
|
if(width != settings.width || height != settings.height) {
|
||||||
resize(settings.width = width, settings.height = height);
|
resize(settings.width = width, settings.height = height);
|
||||||
}
|
}
|
||||||
|
|
||||||
texture->GetLevelDesc(0, &d3dsd);
|
D3DSURFACE_DESC surfaceDescription;
|
||||||
|
texture->GetLevelDesc(0, &surfaceDescription);
|
||||||
texture->GetSurfaceLevel(0, &surface);
|
texture->GetSurfaceLevel(0, &surface);
|
||||||
|
|
||||||
surface->LockRect(&d3dlr, 0, flags.lock);
|
D3DLOCKED_RECT lockedRectangle;
|
||||||
pitch = d3dlr.Pitch;
|
surface->LockRect(&lockedRectangle, 0, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD);
|
||||||
return data = (uint32_t*)d3dlr.pBits;
|
pitch = lockedRectangle.Pitch;
|
||||||
|
return data = (uint32_t*)lockedRectangle.pBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unlock() -> void {
|
auto unlock() -> void {
|
||||||
@@ -260,184 +265,111 @@ struct VideoD3D : Video {
|
|||||||
auto refresh() -> void {
|
auto refresh() -> void {
|
||||||
if(lost && !recover()) return;
|
if(lost && !recover()) return;
|
||||||
|
|
||||||
RECT rd, rs; //dest, source rectangles
|
RECT rectangle;
|
||||||
GetClientRect(settings.handle, &rd);
|
GetClientRect(settings.handle, &rectangle);
|
||||||
SetRect(&rs, 0, 0, settings.width, settings.height);
|
|
||||||
|
|
||||||
//if output size changed, driver must be re-initialized.
|
//if output size changed, driver must be re-initialized.
|
||||||
//failure to do so causes scaling issues on some video drivers.
|
//failure to do so causes scaling issues on some video drivers.
|
||||||
if(state.width != rd.right || state.height != rd.bottom) {
|
if(windowWidth != rectangle.right || windowHeight != rectangle.bottom) init();
|
||||||
init();
|
|
||||||
set_shader(shader_source_markup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(caps.shader && effect) {
|
|
||||||
device->BeginScene();
|
device->BeginScene();
|
||||||
set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom);
|
uint x = 0, y = 0;
|
||||||
|
if(settings.exclusive) {
|
||||||
D3DXVECTOR4 rubyTextureSize;
|
//center output in exclusive mode fullscreen window
|
||||||
rubyTextureSize.x = iwidth;
|
x = (monitorWidth - windowWidth) / 2;
|
||||||
rubyTextureSize.y = iheight;
|
y = (monitorHeight - windowHeight) / 2;
|
||||||
rubyTextureSize.z = 1.0 / iheight;
|
|
||||||
rubyTextureSize.w = 1.0 / iwidth;
|
|
||||||
effect->SetVector("rubyTextureSize", &rubyTextureSize);
|
|
||||||
|
|
||||||
D3DXVECTOR4 rubyInputSize;
|
|
||||||
rubyInputSize.x = settings.width;
|
|
||||||
rubyInputSize.y = settings.height;
|
|
||||||
rubyInputSize.z = 1.0 / settings.height;
|
|
||||||
rubyInputSize.w = 1.0 / settings.width;
|
|
||||||
effect->SetVector("rubyInputSize", &rubyInputSize);
|
|
||||||
|
|
||||||
D3DXVECTOR4 rubyOutputSize;
|
|
||||||
rubyOutputSize.x = rd.right;
|
|
||||||
rubyOutputSize.y = rd.bottom;
|
|
||||||
rubyOutputSize.z = 1.0 / rd.bottom;
|
|
||||||
rubyOutputSize.w = 1.0 / rd.right;
|
|
||||||
effect->SetVector("rubyOutputSize", &rubyOutputSize);
|
|
||||||
|
|
||||||
UINT passes;
|
|
||||||
effect->Begin(&passes, 0);
|
|
||||||
effect->SetTexture("rubyTexture", texture);
|
|
||||||
device->SetTexture(0, texture);
|
|
||||||
for(unsigned pass = 0; pass < passes; pass++) {
|
|
||||||
effect->BeginPass(pass);
|
|
||||||
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
|
||||||
effect->EndPass();
|
|
||||||
}
|
}
|
||||||
effect->End();
|
setVertex(0, 0, settings.width, settings.height, textureWidth, textureHeight, x, y, windowWidth, windowHeight);
|
||||||
device->EndScene();
|
|
||||||
} else {
|
|
||||||
device->BeginScene();
|
|
||||||
set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom);
|
|
||||||
device->SetTexture(0, texture);
|
device->SetTexture(0, texture);
|
||||||
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||||
device->EndScene();
|
device->EndScene();
|
||||||
}
|
|
||||||
|
|
||||||
if(settings.synchronize) {
|
if(settings.synchronize) {
|
||||||
D3DRASTER_STATUS status;
|
D3DRASTER_STATUS status;
|
||||||
//wait for a previous vblank to finish, if necessary
|
while(true) { //wait for a previous vblank to finish, if necessary
|
||||||
while(true) {
|
|
||||||
device->GetRasterStatus(0, &status);
|
device->GetRasterStatus(0, &status);
|
||||||
if(status.InVBlank == false) break;
|
if(!status.InVBlank) break;
|
||||||
}
|
}
|
||||||
//wait for next vblank to begin
|
while(true) { //wait for next vblank to begin
|
||||||
while(true) {
|
|
||||||
device->GetRasterStatus(0, &status);
|
device->GetRasterStatus(0, &status);
|
||||||
if(status.InVBlank == true) break;
|
if(status.InVBlank) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true;
|
if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set_shader(const char* source) -> void {
|
|
||||||
if(!caps.shader) return;
|
|
||||||
|
|
||||||
if(effect) {
|
|
||||||
effect->Release();
|
|
||||||
effect = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!source || !*source) {
|
|
||||||
shader_source_markup = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
shader_source_markup = source;
|
|
||||||
|
|
||||||
auto document = BML::unserialize(shader_source_markup);
|
|
||||||
bool is_hlsl = document["shader"]["language"].text() == "HLSL";
|
|
||||||
string shader_source = document["shader"]["source"].text();
|
|
||||||
if(shader_source == "") return;
|
|
||||||
|
|
||||||
HMODULE d3dx;
|
|
||||||
for(unsigned i = 0; i < 256; i++) {
|
|
||||||
char t[256];
|
|
||||||
sprintf(t, "d3dx9_%u.dll", i);
|
|
||||||
d3dx = LoadLibraryW(utf16_t(t));
|
|
||||||
if(d3dx) break;
|
|
||||||
}
|
|
||||||
if(!d3dx) d3dx = LoadLibraryW(L"d3dx9.dll");
|
|
||||||
if(!d3dx) return;
|
|
||||||
|
|
||||||
EffectProc effectProc = (EffectProc)GetProcAddress(d3dx, "D3DXCreateEffect");
|
|
||||||
TextureProc textureProc = (TextureProc)GetProcAddress(d3dx, "D3DXCreateTextureFromFileA");
|
|
||||||
|
|
||||||
LPD3DXBUFFER pBufferErrors = NULL;
|
|
||||||
effectProc(device, (const void*)shader_source.data(), lstrlenA(shader_source), NULL, NULL, 0, NULL, &effect, &pBufferErrors);
|
|
||||||
|
|
||||||
D3DXHANDLE hTech;
|
|
||||||
effect->FindNextValidTechnique(NULL, &hTech);
|
|
||||||
effect->SetTechnique(hTech);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto init() -> bool {
|
auto init() -> bool {
|
||||||
RECT rd;
|
term();
|
||||||
GetClientRect(settings.handle, &rd);
|
|
||||||
state.width = rd.right;
|
|
||||||
state.height = rd.bottom;
|
|
||||||
|
|
||||||
lpd3d = Direct3DCreate9(D3D_SDK_VERSION);
|
RECT rectangle;
|
||||||
if(!lpd3d) return false;
|
GetClientRect(settings.handle, &rectangle);
|
||||||
|
windowWidth = rectangle.right;
|
||||||
|
windowHeight = rectangle.bottom;
|
||||||
|
|
||||||
memset(&presentation, 0, sizeof(presentation));
|
context = Direct3DCreate9(D3D_SDK_VERSION);
|
||||||
|
if(!context) return false;
|
||||||
|
|
||||||
|
memory::fill(&presentation, sizeof(presentation));
|
||||||
presentation.Flags = D3DPRESENTFLAG_VIDEO;
|
presentation.Flags = D3DPRESENTFLAG_VIDEO;
|
||||||
presentation.SwapEffect = D3DSWAPEFFECT_FLIP;
|
presentation.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||||
presentation.hDeviceWindow = settings.handle;
|
|
||||||
presentation.BackBufferCount = 1;
|
presentation.BackBufferCount = 1;
|
||||||
presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
|
presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||||||
presentation.MultiSampleQuality = 0;
|
presentation.MultiSampleQuality = 0;
|
||||||
presentation.EnableAutoDepthStencil = false;
|
presentation.EnableAutoDepthStencil = false;
|
||||||
presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
||||||
presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||||
|
|
||||||
|
if(!settings.exclusive) {
|
||||||
|
presentation.hDeviceWindow = settings.handle;
|
||||||
presentation.Windowed = true;
|
presentation.Windowed = true;
|
||||||
presentation.BackBufferFormat = D3DFMT_UNKNOWN;
|
presentation.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||||
presentation.BackBufferWidth = 0;
|
presentation.BackBufferWidth = 0;
|
||||||
presentation.BackBufferHeight = 0;
|
presentation.BackBufferHeight = 0;
|
||||||
|
|
||||||
if(lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle,
|
ShowWindow(settings.exclusiveHandle, SW_HIDE);
|
||||||
|
if(context->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle,
|
||||||
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
|
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->GetDeviceCaps(&d3dcaps);
|
|
||||||
|
|
||||||
caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES);
|
|
||||||
caps.shader = d3dcaps.PixelShaderVersion > D3DPS_VERSION(1, 4);
|
|
||||||
|
|
||||||
if(caps.dynamic == true) {
|
|
||||||
flags.t_usage = D3DUSAGE_DYNAMIC;
|
|
||||||
flags.v_usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
|
|
||||||
flags.t_pool = D3DPOOL_DEFAULT;
|
|
||||||
flags.v_pool = D3DPOOL_DEFAULT;
|
|
||||||
flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD;
|
|
||||||
} else {
|
} else {
|
||||||
flags.t_usage = 0;
|
presentation.hDeviceWindow = settings.exclusiveHandle;
|
||||||
flags.v_usage = D3DUSAGE_WRITEONLY;
|
presentation.Windowed = false;
|
||||||
flags.t_pool = D3DPOOL_MANAGED;
|
presentation.BackBufferFormat = D3DFMT_X8R8G8B8;
|
||||||
flags.v_pool = D3DPOOL_MANAGED;
|
presentation.BackBufferWidth = monitorWidth;
|
||||||
flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD;
|
presentation.BackBufferHeight = monitorHeight;
|
||||||
|
presentation.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
||||||
|
|
||||||
|
ShowWindow(settings.exclusiveHandle, SW_SHOWNORMAL);
|
||||||
|
if(context->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.exclusiveHandle,
|
||||||
|
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device->GetDeviceCaps(&capabilities);
|
||||||
|
|
||||||
|
if(capabilities.Caps2 & D3DCAPS2_DYNAMICTEXTURES) {
|
||||||
|
flags.textureUsage = D3DUSAGE_DYNAMIC;
|
||||||
|
flags.texturePool = D3DPOOL_DEFAULT;
|
||||||
|
flags.vertexUsage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
|
||||||
|
flags.vertexPool = D3DPOOL_DEFAULT;
|
||||||
|
} else {
|
||||||
|
flags.textureUsage = 0;
|
||||||
|
flags.texturePool = D3DPOOL_MANAGED;
|
||||||
|
flags.vertexUsage = D3DUSAGE_WRITEONLY;
|
||||||
|
flags.vertexPool = D3DPOOL_MANAGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
lost = false;
|
lost = false;
|
||||||
recover();
|
return recover();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto release_resources() -> void {
|
|
||||||
if(effect) { effect->Release(); effect = 0; }
|
|
||||||
if(vertex_buffer) { vertex_buffer->Release(); vertex_buffer = 0; }
|
|
||||||
if(surface) { surface->Release(); surface = 0; }
|
|
||||||
if(texture) { texture->Release(); texture = 0; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto term() -> void {
|
auto term() -> void {
|
||||||
release_resources();
|
if(vertexBuffer) { vertexBuffer->Release(); vertexBuffer = nullptr; }
|
||||||
if(device) { device->Release(); device = 0; }
|
if(surface) { surface->Release(); surface = nullptr; }
|
||||||
if(lpd3d) { lpd3d->Release(); lpd3d = 0; }
|
if(texture) { texture->Release(); texture = nullptr; }
|
||||||
|
if(device) { device->Release(); device = nullptr; }
|
||||||
|
if(context) { context->Release(); context = nullptr; }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef D3DVERTEX
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
||||||
struct VideoDD : Video {
|
struct VideoDirectDraw : Video {
|
||||||
~VideoDD() { term(); }
|
~VideoDirectDraw() { term(); }
|
||||||
|
|
||||||
LPDIRECTDRAW lpdd = nullptr;
|
LPDIRECTDRAW lpdd = nullptr;
|
||||||
LPDIRECTDRAW7 lpdd7 = nullptr;
|
LPDIRECTDRAW7 lpdd7 = nullptr;
|
||||||
@@ -10,15 +10,15 @@ struct VideoDD : Video {
|
|||||||
LPDIRECTDRAWCLIPPER clipper = nullptr;
|
LPDIRECTDRAWCLIPPER clipper = nullptr;
|
||||||
DDSURFACEDESC2 ddsd;
|
DDSURFACEDESC2 ddsd;
|
||||||
DDSCAPS2 ddscaps;
|
DDSCAPS2 ddscaps;
|
||||||
unsigned iwidth;
|
uint iwidth;
|
||||||
unsigned iheight;
|
uint iheight;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
HWND handle = nullptr;
|
HWND handle = nullptr;
|
||||||
bool synchronize = false;
|
bool synchronize = false;
|
||||||
|
|
||||||
unsigned width;
|
uint width;
|
||||||
unsigned height;
|
uint height;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
@@ -34,8 +34,8 @@ struct VideoDD : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
if(name == Video::Handle && value.is<uintptr>()) {
|
||||||
settings.handle = (HWND)value.get<uintptr_t>();
|
settings.handle = (HWND)value.get<uintptr>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ struct VideoDD : Video {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resize(unsigned width, unsigned height) -> void {
|
auto resize(uint width, uint height) -> void {
|
||||||
if(iwidth >= width && iheight >= height) return;
|
if(iwidth >= width && iheight >= height) return;
|
||||||
|
|
||||||
iwidth = max(width, iwidth);
|
iwidth = max(width, iwidth);
|
||||||
@@ -94,7 +94,7 @@ struct VideoDD : Video {
|
|||||||
raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
if(width != settings.width || height != settings.height) {
|
if(width != settings.width || height != settings.height) {
|
||||||
resize(settings.width = width, settings.height = height);
|
resize(settings.width = width, settings.height = height);
|
||||||
}
|
}
|
||||||
@@ -136,6 +136,8 @@ struct VideoDD : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto init() -> bool {
|
auto init() -> bool {
|
||||||
|
term();
|
||||||
|
|
||||||
DirectDrawCreate(0, &lpdd, 0);
|
DirectDrawCreate(0, &lpdd, 0);
|
||||||
lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7);
|
lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7);
|
||||||
if(lpdd) { lpdd->Release(); lpdd = 0; }
|
if(lpdd) { lpdd->Release(); lpdd = 0; }
|
||||||
|
@@ -28,8 +28,8 @@ struct VideoGDI : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
if(name == Video::Handle && value.is<uintptr>()) {
|
||||||
settings.handle = (HWND)value.get<uintptr_t>();
|
settings.handle = (HWND)value.get<uintptr>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,9 +6,9 @@
|
|||||||
struct VideoGLX2 : Video {
|
struct VideoGLX2 : Video {
|
||||||
~VideoGLX2() { term(); }
|
~VideoGLX2() { term(); }
|
||||||
|
|
||||||
auto (*glXSwapInterval)(signed) -> signed = nullptr;
|
auto (*glXSwapInterval)(int) -> int = nullptr;
|
||||||
Display* display = nullptr;
|
Display* display = nullptr;
|
||||||
signed screen = 0;
|
int screen = 0;
|
||||||
Window xwindow = 0;
|
Window xwindow = 0;
|
||||||
Colormap colormap = 0;
|
Colormap colormap = 0;
|
||||||
GLXContext glxcontext = nullptr;
|
GLXContext glxcontext = nullptr;
|
||||||
@@ -17,10 +17,10 @@ struct VideoGLX2 : Video {
|
|||||||
struct {
|
struct {
|
||||||
Window handle = 0;
|
Window handle = 0;
|
||||||
bool synchronize = false;
|
bool synchronize = false;
|
||||||
unsigned filter = 1; //linear
|
uint filter = Video::FilterLinear;
|
||||||
|
|
||||||
unsigned width = 256;
|
uint width = 256;
|
||||||
unsigned height = 256;
|
uint height = 256;
|
||||||
|
|
||||||
bool isDoubleBuffered = false;
|
bool isDoubleBuffered = false;
|
||||||
bool isDirect = false;
|
bool isDirect = false;
|
||||||
@@ -34,15 +34,15 @@ struct VideoGLX2 : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto get(const string& name) -> any {
|
auto get(const string& name) -> any {
|
||||||
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
if(name == Video::Handle) return (uintptr)settings.handle;
|
||||||
if(name == Video::Synchronize) return settings.synchronize;
|
if(name == Video::Synchronize) return settings.synchronize;
|
||||||
if(name == Video::Filter) return settings.filter;
|
if(name == Video::Filter) return settings.filter;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
if(name == Video::Handle && value.is<uintptr>()) {
|
||||||
settings.handle = value.get<uintptr_t>();
|
settings.handle = value.get<uintptr>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,15 +54,15 @@ struct VideoGLX2 : Video {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == Video::Filter && value.is<unsigned>()) {
|
if(name == Video::Filter && value.is<uint>()) {
|
||||||
settings.filter = value.get<unsigned>();
|
settings.filter = value.get<uint>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
if(width != settings.width || height != settings.height) resize(width, height);
|
if(width != settings.width || height != settings.height) resize(width, height);
|
||||||
pitch = glwidth * sizeof(uint32_t);
|
pitch = glwidth * sizeof(uint32_t);
|
||||||
return data = glbuffer;
|
return data = glbuffer;
|
||||||
@@ -105,8 +105,8 @@ struct VideoGLX2 : Video {
|
|||||||
|
|
||||||
double w = (double)settings.width / (double)glwidth;
|
double w = (double)settings.width / (double)glwidth;
|
||||||
double h = (double)settings.height / (double)glheight;
|
double h = (double)settings.height / (double)glheight;
|
||||||
signed u = parent.width;
|
int u = parent.width;
|
||||||
signed v = parent.height;
|
int v = parent.height;
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
||||||
@@ -123,14 +123,14 @@ struct VideoGLX2 : Video {
|
|||||||
display = XOpenDisplay(0);
|
display = XOpenDisplay(0);
|
||||||
screen = DefaultScreen(display);
|
screen = DefaultScreen(display);
|
||||||
|
|
||||||
signed versionMajor = 0, versionMinor = 0;
|
int versionMajor = 0, versionMinor = 0;
|
||||||
glXQueryVersion(display, &versionMajor, &versionMinor);
|
glXQueryVersion(display, &versionMajor, &versionMinor);
|
||||||
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
||||||
|
|
||||||
XWindowAttributes windowAttributes;
|
XWindowAttributes windowAttributes;
|
||||||
XGetWindowAttributes(display, settings.handle, &windowAttributes);
|
XGetWindowAttributes(display, settings.handle, &windowAttributes);
|
||||||
|
|
||||||
signed attributeList[] = {
|
int attributeList[] = {
|
||||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
GLX_DOUBLEBUFFER, True,
|
GLX_DOUBLEBUFFER, True,
|
||||||
@@ -140,7 +140,7 @@ struct VideoGLX2 : Video {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
signed fbCount = 0;
|
int fbCount = 0;
|
||||||
auto fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount);
|
auto fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount);
|
||||||
if(fbCount == 0) return false;
|
if(fbCount == 0) return false;
|
||||||
|
|
||||||
@@ -163,12 +163,12 @@ struct VideoGLX2 : Video {
|
|||||||
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
|
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
|
||||||
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
|
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
|
||||||
|
|
||||||
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
|
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
||||||
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");
|
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
|
||||||
|
|
||||||
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
||||||
|
|
||||||
signed value = 0;
|
int value = 0;
|
||||||
glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value);
|
glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value);
|
||||||
settings.isDoubleBuffered = value;
|
settings.isDoubleBuffered = value;
|
||||||
settings.isDirect = glXIsDirect(display, glxcontext);
|
settings.isDirect = glXIsDirect(display, glxcontext);
|
||||||
@@ -224,10 +224,10 @@ struct VideoGLX2 : Video {
|
|||||||
private:
|
private:
|
||||||
GLuint gltexture = 0;
|
GLuint gltexture = 0;
|
||||||
uint32_t* glbuffer = nullptr;
|
uint32_t* glbuffer = nullptr;
|
||||||
unsigned glwidth = 0;
|
uint glwidth = 0;
|
||||||
unsigned glheight = 0;
|
uint glheight = 0;
|
||||||
|
|
||||||
auto resize(unsigned width, unsigned height) -> void {
|
auto resize(uint width, uint height) -> void {
|
||||||
settings.width = width;
|
settings.width = width;
|
||||||
settings.height = height;
|
settings.height = height;
|
||||||
|
|
||||||
|
@@ -11,14 +11,14 @@ struct VideoSDL : Video {
|
|||||||
Display* display = nullptr;
|
Display* display = nullptr;
|
||||||
SDL_Surface* screen = nullptr;
|
SDL_Surface* screen = nullptr;
|
||||||
SDL_Surface* buffer = nullptr;
|
SDL_Surface* buffer = nullptr;
|
||||||
unsigned iwidth = 0;
|
uint iwidth = 0;
|
||||||
unsigned iheight = 0;
|
uint iheight = 0;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uintptr_t handle = 0;
|
uintptr handle = 0;
|
||||||
|
|
||||||
unsigned width = 0;
|
uint width = 0;
|
||||||
unsigned height = 0;
|
uint height = 0;
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
auto cap(const string& name) -> bool {
|
auto cap(const string& name) -> bool {
|
||||||
@@ -32,15 +32,15 @@ struct VideoSDL : Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto set(const string& name, const any& value) -> bool {
|
auto set(const string& name, const any& value) -> bool {
|
||||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
if(name == Video::Handle && value.is<uintptr>()) {
|
||||||
settings.handle = value.get<uintptr_t>();
|
settings.handle = value.get<uintptr>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resize(unsigned width, unsigned height) -> void {
|
auto resize(uint width, uint height) -> void {
|
||||||
if(iwidth >= width && iheight >= height) return;
|
if(iwidth >= width && iheight >= height) return;
|
||||||
|
|
||||||
iwidth = max(width, iwidth);
|
iwidth = max(width, iwidth);
|
||||||
@@ -53,7 +53,7 @@ struct VideoSDL : Video {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||||
if(width != settings.width || height != settings.height) {
|
if(width != settings.width || height != settings.height) {
|
||||||
resize(settings.width = width, settings.height = height);
|
resize(settings.width = width, settings.height = height);
|
||||||
}
|
}
|
||||||
@@ -69,9 +69,9 @@ struct VideoSDL : Video {
|
|||||||
|
|
||||||
auto clear() -> void {
|
auto clear() -> void {
|
||||||
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
|
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
|
||||||
for(unsigned y = 0; y < iheight; y++) {
|
for(uint y : range(iheight)) {
|
||||||
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
|
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
|
||||||
for(unsigned x = 0; x < iwidth; x++) *data++ = 0xff000000;
|
for(uint x : range(iwidth)) *data++ = 0xff000000;
|
||||||
}
|
}
|
||||||
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
|
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
|
||||||
refresh();
|
refresh();
|
||||||
@@ -82,9 +82,9 @@ struct VideoSDL : Video {
|
|||||||
//as SDL forces us to use a 32-bit buffer, we must set alpha to 255 (full opacity)
|
//as SDL forces us to use a 32-bit buffer, we must set alpha to 255 (full opacity)
|
||||||
//to prevent blending against the window beneath when X window visual is 32-bits.
|
//to prevent blending against the window beneath when X window visual is 32-bits.
|
||||||
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
|
if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer);
|
||||||
for(unsigned y = 0; y < settings.height; y++) {
|
for(uint y : range(settings.height)) {
|
||||||
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
|
uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2);
|
||||||
for(unsigned x = 0; x < settings.width; x++) *data++ |= 0xff000000;
|
for(uint x : range(settings.width)) *data++ |= 0xff000000;
|
||||||
}
|
}
|
||||||
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
|
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ struct VideoSDL : Video {
|
|||||||
screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE);
|
screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE);
|
||||||
XUndefineCursor(display, settings.handle);
|
XUndefineCursor(display, settings.handle);
|
||||||
|
|
||||||
buffer = 0;
|
buffer = nullptr;
|
||||||
iwidth = 0;
|
iwidth = 0;
|
||||||
iheight = 0;
|
iheight = 0;
|
||||||
resize(settings.width = 256, settings.height = 256);
|
resize(settings.width = 256, settings.height = 256);
|
||||||
|
@@ -93,7 +93,7 @@ struct VideoWGL : Video, OpenGL {
|
|||||||
auto init() -> bool {
|
auto init() -> bool {
|
||||||
GLuint pixel_format;
|
GLuint pixel_format;
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
memory::fill(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
|
||||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||||
pfd.nVersion = 1;
|
pfd.nVersion = 1;
|
||||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
@@ -117,7 +117,7 @@ struct VideoWGL : Video, OpenGL {
|
|||||||
};
|
};
|
||||||
HGLRC context = wglCreateContextAttribs(display, 0, attributes);
|
HGLRC context = wglCreateContextAttribs(display, 0, attributes);
|
||||||
if(context) {
|
if(context) {
|
||||||
wglMakeCurrent(NULL, NULL);
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
wglDeleteContext(wglcontext);
|
wglDeleteContext(wglcontext);
|
||||||
wglMakeCurrent(display, wglcontext = context);
|
wglMakeCurrent(display, wglcontext = context);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user