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:
Tim Allen 2017-07-09 12:23:17 +10:00
parent ee982f098a
commit 434e303ffb
18 changed files with 304 additions and 348 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -30,7 +30,7 @@ Settings::Settings() {
set("Video/Windowed/AspectCorrection", 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", "640x480");
set("Video/Windowed/Scale/Medium", "960x720");
@ -38,6 +38,7 @@ Settings::Settings() {
set("Video/Fullscreen/AspectCorrection", true);
set("Video/Fullscreen/IntegralScaling", true);
set("Video/Fullscreen/Exclusive", false);
set("Audio/Driver", ruby::Audio::optimalDriver());
set("Audio/Device", "");

View File

@ -96,12 +96,12 @@ auto InputManager::appendHotkeys() -> void {
}
auto InputManager::pollHotkeys() -> void {
if(!presentation || !presentation->focused()) return;
for(auto& hotkey : hotkeys) {
int16 state = hotkey->poll();
if(hotkey->state == 0 && state == 1 && hotkey->press) hotkey->press();
if(hotkey->state == 1 && state == 0 && hotkey->release) hotkey->release();
hotkey->state = state;
if(program->allowInput(true)) {
for(auto& hotkey : hotkeys) {
int16 state = hotkey->poll();
if(hotkey->state == 0 && state == 1 && hotkey->press) hotkey->press();
if(hotkey->state == 1 && state == 0 && hotkey->release) hotkey->release();
hotkey->state = state;
}
}
}

View File

@ -269,7 +269,7 @@ auto Presentation::resizeViewport(bool resizeWindow) -> void {
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);
emulatorWidth *= multiplier;
emulatorHeight *= multiplier;
@ -312,13 +312,13 @@ auto Presentation::toggleFullScreen() -> void {
if(!fullScreen()) {
menuBar.setVisible(false);
statusBar.setVisible(false);
setResizable(true);
setFullScreen(true);
video->set(Video::Exclusive, settings["Video/Fullscreen/Exclusive"].boolean());
if(!input->acquired()) input->acquire();
} else {
if(input->acquired()) input->release();
video->set(Video::Exclusive, false);
setFullScreen(false);
setResizable(false);
menuBar.setVisible(true);
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
}

View File

@ -96,7 +96,7 @@ auto Program::audioSample(const double* samples, uint channels) -> void {
}
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
if(presentation->focused() || settings["Input/FocusLoss/AllowInput"].boolean()) {
if(allowInput()) {
inputManager->poll();
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
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 {
if(presentation->focused() || settings["Input/FocusLoss/AllowInput"].boolean() || !enable) {
if(allowInput() || !enable) {
auto& mapping = inputManager->emulator->ports[port].devices[device].mappings[input];
return mapping.rumble(enable);
}

View File

@ -35,6 +35,7 @@ struct Program : Emulator::Platform {
auto updateVideoShader() -> void;
auto updateAudioDriver() -> void;
auto updateAudioEffects() -> void;
auto allowInput(bool hotkey = false) -> bool;
bool hasQuit = false;
bool pause = false;

View File

@ -92,3 +92,17 @@ auto Program::updateAudioEffects() -> void {
auto reverbEnable = settings["Audio/Reverb/Enable"].boolean();
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;
}

View File

@ -32,7 +32,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
resamplerCombo.append(ComboButtonItem().setText("IIR - Biquad"));
resamplerCombo.setEnabled(false);
exclusiveMode.setText("Exclusive Mode");
exclusiveMode.setText("Exclusive mode");
exclusiveMode.setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] { updateDriver(); });
if(!audio->cap(Audio::Exclusive)) exclusiveMode.remove();

View File

@ -28,11 +28,12 @@ struct VideoSettings : TabFrameItem {
HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}};
CheckLabel windowedModeAspectCorrection{&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};
HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}};
CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}};
CheckLabel fullscreenModeIntegralScaling{&fullscreenModeLayout, Size{0, 0}};
CheckLabel fullscreenModeExclusive{&fullscreenModeLayout, Size{0, 0}};
auto updateColor(bool initializing = false) -> void;
auto updateViewport(bool initializing = false) -> void;

View File

@ -26,11 +26,13 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode");
windowedModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Windowed/AspectCorrection"].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");
fullscreenModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Fullscreen/AspectCorrection"].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);
updateViewport(true);
@ -48,16 +50,17 @@ auto VideoSettings::updateColor(bool initializing) -> void {
}
auto VideoSettings::updateViewport(bool initializing) -> void {
bool wasAdaptive = settings["Video/Windowed/AdaptiveSizing"].boolean();
bool isAdaptive = windowedModeAdaptiveSizing.checked();
bool wasAdaptive = settings["Video/Windowed/Adaptive"].boolean();
bool isAdaptive = windowedModeAdaptive.checked();
settings["Video/Overscan/Horizontal"].setValue(horizontalMaskSlider.position());
settings["Video/Overscan/Vertical"].setValue(verticalMaskSlider.position());
settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.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/IntegralScaling"].setValue(fullscreenModeIntegralScaling.checked());
settings["Video/Fullscreen/Exclusive"].setValue(fullscreenModeExclusive.checked());
horizontalMaskValue.setText({horizontalMaskSlider.position()});
verticalMaskValue.setText({verticalMaskSlider.position()});

View File

@ -72,14 +72,15 @@ using namespace ruby;
namespace ruby {
const string Video::Exclusive = "Exclusive";
const string Video::Handle = "Handle";
const string Video::Synchronize = "Synchronize";
const string Video::Depth = "Depth";
const string Video::Filter = "Filter";
const string Video::Shader = "Shader";
const unsigned Video::FilterNearest = 0;
const unsigned Video::FilterLinear = 1;
const uint Video::FilterNearest = 0;
const uint Video::FilterLinear = 1;
auto Video::create(const string& driver) -> Video* {
if(!driver) return create(optimalDriver());
@ -89,11 +90,11 @@ auto Video::create(const string& driver) -> Video* {
#endif
#if defined(VIDEO_DIRECT3D)
if(driver == "Direct3D") return new VideoD3D;
if(driver == "Direct3D") return new VideoDirect3D;
#endif
#if defined(VIDEO_DIRECTDRAW)
if(driver == "DirectDraw") return new VideoDD;
if(driver == "DirectDraw") return new VideoDirectDraw;
#endif
#if defined(VIDEO_GDI)

View File

@ -3,7 +3,7 @@
/* ruby
* author: byuu
* license: ISC
* version: 0.15 (2016-04-18)
* version: 0.16 (2017-07-08)
*
* ruby is a cross-platform hardware abstraction layer.
* it provides a common interface to video, audio and input devices.
@ -14,14 +14,15 @@
namespace ruby {
struct Video {
static const nall::string Exclusive;
static const nall::string Handle;
static const nall::string Synchronize;
static const nall::string Depth;
static const nall::string Filter;
static const nall::string Shader;
static const unsigned FilterNearest;
static const unsigned FilterLinear;
static const uint FilterNearest;
static const uint FilterLinear;
static auto create(const nall::string& driver = "") -> Video*;
static auto optimalDriver() -> nall::string;
@ -34,7 +35,7 @@ struct Video {
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 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 clear() -> void {}
virtual auto refresh() -> void {}
@ -96,13 +97,13 @@ struct Input {
virtual auto init() -> bool { return true; }
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 doChange(nall::shared_pointer<nall::HID::Device> device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) -> void {
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, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
if(_onChange) _onChange(device, group, input, oldValue, newValue);
}
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;
};
}

View File

@ -1,67 +1,87 @@
#undef interface
#define interface struct
#include <d3d9.h>
#include <d3dx9.h>
#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*);
typedef HRESULT (__stdcall* TextureProc)(LPDIRECT3DDEVICE9, LPCTSTR, LPDIRECT3DTEXTURE9*);
struct VideoDirect3D : Video {
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 {
~VideoD3D() { term(); }
WNDCLASS windowClass = {};
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;
LPDIRECT3DDEVICE9 device = nullptr;
LPDIRECT3DVERTEXBUFFER9 vertex_buffer = nullptr;
LPDIRECT3DVERTEXBUFFER9* vertex_ptr = nullptr;
D3DPRESENT_PARAMETERS presentation;
D3DSURFACE_DESC d3dsd;
D3DLOCKED_RECT d3dlr;
D3DRASTER_STATUS d3drs;
D3DCAPS9 d3dcaps;
LPDIRECT3DTEXTURE9 texture = nullptr;
LPDIRECT3DSURFACE9 surface = nullptr;
LPD3DXEFFECT effect = nullptr;
string shader_source_markup;
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;
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = nullptr;
D3DPRESENT_PARAMETERS presentation = {};
D3DCAPS9 capabilities = {};
LPDIRECT3DTEXTURE9 texture = nullptr;
LPDIRECT3DSURFACE9 surface = nullptr;
bool lost = true;
unsigned iwidth;
unsigned iheight;
uint windowWidth;
uint windowHeight;
uint textureWidth;
uint textureHeight;
uint monitorWidth;
uint monitorHeight;
struct d3dvertex {
float x, y, z, rhw; //screen coords
float u, v; //texture coords
struct Vertex {
float x, y, z, rhw; //screen coordinates
float u, v; //texture coordinates
};
struct {
uint32_t t_usage, v_usage;
uint32_t t_pool, v_pool;
uint32_t lock;
uint32_t textureUsage;
uint32_t texturePool;
uint32_t vertexUsage;
uint32_t vertexPool;
uint32_t filter;
} flags;
struct {
bool dynamic; //device supports dynamic textures
bool shader; //device supports pixel shaders
} caps;
struct {
bool exclusive = false;
HWND handle = nullptr;
bool synchronize = false;
unsigned filter = Video::FilterLinear;
uint filter = Video::FilterLinear;
unsigned width;
unsigned height;
HWND exclusiveHandle = nullptr;
uint width;
uint height;
} settings;
struct {
unsigned width;
unsigned height;
} state;
auto cap(const string& name) -> bool {
if(name == Video::Exclusive) return true;
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
@ -70,6 +90,7 @@ struct VideoD3D : Video {
}
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::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter;
@ -77,8 +98,14 @@ struct VideoD3D : Video {
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (HWND)value.get<uintptr_t>();
if(name == Video::Exclusive && value.is<bool>()) {
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;
}
@ -87,18 +114,12 @@ struct VideoD3D : Video {
return true;
}
if(name == Video::Filter && value.is<unsigned>()) {
settings.filter = value.get<unsigned>();
if(lpd3d) update_filter();
if(name == Video::Filter && value.is<uint>()) {
settings.filter = value.get<uint>();
if(context) updateFilter();
return true;
}
if(name == Video::Shader && value.is<string>()) {
return false;
//set_shader(value.get<string>());
//return true;
}
return false;
}
@ -106,94 +127,74 @@ struct VideoD3D : Video {
if(!device) return false;
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;
}
lost = false;
device->SetDialogBoxMode(false);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
device->SetRenderState(D3DRS_LIGHTING, false);
device->SetRenderState(D3DRS_ZENABLE, false);
device->SetRenderState(D3DRS_ZENABLE, false);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
device->SetVertexShader(NULL);
device->SetFVF(D3DVERTEX);
device->SetVertexShader(nullptr);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, (D3DPOOL)flags.v_pool, &vertex_buffer, NULL);
iwidth = 0;
iheight = 0;
device->CreateVertexBuffer(sizeof(Vertex) * 4, flags.vertexUsage, D3DFVF_XYZRHW | D3DFVF_TEX1,
(D3DPOOL)flags.vertexPool, &vertexBuffer, nullptr);
textureWidth = 0;
textureHeight = 0;
resize(settings.width = 256, settings.height = 256);
update_filter();
updateFilter();
clear();
return true;
}
auto rounded_power_of_two(unsigned n) -> unsigned {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
auto resize(uint width, uint height) -> void {
if(textureWidth >= width && textureHeight >= height) return;
auto resize(unsigned width, unsigned height) -> void {
if(iwidth >= width && iheight >= height) return;
textureWidth = bit::round(max(width, textureWidth));
textureHeight = bit::round(max(height, textureHeight));
iwidth = rounded_power_of_two(max(width, iwidth ));
iheight = rounded_power_of_two(max(height, iheight));
if(d3dcaps.MaxTextureWidth < iwidth || d3dcaps.MaxTextureWidth < iheight) {
//TODO: attempt to handle this more gracefully
return;
}
if(capabilities.MaxTextureWidth < textureWidth || capabilities.MaxTextureWidth < textureHeight) return;
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(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_MAGFILTER, flags.filter);
}
// Vertex format:
//
// 0----------1
// | /|
// | / |
// | / |
// | / |
// | / |
// 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(
//(x,y) screen coordinates, in pixels
//(u,v) texture coordinates, betweeen 0.0 (top, left) to 1.0 (bottom, right)
auto setVertex(
uint32_t px, uint32_t py, uint32_t pw, uint32_t ph,
uint32_t tw, uint32_t th,
uint32_t x, uint32_t y, uint32_t w, uint32_t h
) -> void {
d3dvertex vertex[4];
Vertex vertex[4];
vertex[0].x = vertex[2].x = (double)(x - 0.5);
vertex[1].x = vertex[3].x = (double)(x + w - 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[2].v = vertex[3].v = (double)(py + h) / rh;
vertex_buffer->Lock(0, sizeof(d3dvertex) * 4, (void**)&vertex_ptr, 0);
memcpy(vertex_ptr, vertex, sizeof(d3dvertex) * 4);
vertex_buffer->Unlock();
LPDIRECT3DVERTEXBUFFER9* vertexPointer = nullptr;
vertexBuffer->Lock(0, sizeof(Vertex) * 4, (void**)&vertexPointer, 0);
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 {
if(lost && !recover()) return;
texture->GetLevelDesc(0, &d3dsd);
D3DSURFACE_DESC surfaceDescription;
texture->GetLevelDesc(0, &surfaceDescription);
texture->GetSurfaceLevel(0, &surface);
if(surface) {
@ -230,25 +233,27 @@ struct VideoD3D : Video {
}
//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->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(width != settings.width || height != settings.height) {
resize(settings.width = width, settings.height = height);
}
texture->GetLevelDesc(0, &d3dsd);
D3DSURFACE_DESC surfaceDescription;
texture->GetLevelDesc(0, &surfaceDescription);
texture->GetSurfaceLevel(0, &surface);
surface->LockRect(&d3dlr, 0, flags.lock);
pitch = d3dlr.Pitch;
return data = (uint32_t*)d3dlr.pBits;
D3DLOCKED_RECT lockedRectangle;
surface->LockRect(&lockedRectangle, 0, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD);
pitch = lockedRectangle.Pitch;
return data = (uint32_t*)lockedRectangle.pBits;
}
auto unlock() -> void {
@ -260,184 +265,111 @@ struct VideoD3D : Video {
auto refresh() -> void {
if(lost && !recover()) return;
RECT rd, rs; //dest, source rectangles
GetClientRect(settings.handle, &rd);
SetRect(&rs, 0, 0, settings.width, settings.height);
RECT rectangle;
GetClientRect(settings.handle, &rectangle);
//if output size changed, driver must be re-initialized.
//failure to do so causes scaling issues on some video drivers.
if(state.width != rd.right || state.height != rd.bottom) {
init();
set_shader(shader_source_markup);
return;
}
if(caps.shader && effect) {
device->BeginScene();
set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom);
D3DXVECTOR4 rubyTextureSize;
rubyTextureSize.x = iwidth;
rubyTextureSize.y = iheight;
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();
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->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->EndScene();
if(windowWidth != rectangle.right || windowHeight != rectangle.bottom) init();
device->BeginScene();
uint x = 0, y = 0;
if(settings.exclusive) {
//center output in exclusive mode fullscreen window
x = (monitorWidth - windowWidth) / 2;
y = (monitorHeight - windowHeight) / 2;
}
setVertex(0, 0, settings.width, settings.height, textureWidth, textureHeight, x, y, windowWidth, windowHeight);
device->SetTexture(0, texture);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->EndScene();
if(settings.synchronize) {
D3DRASTER_STATUS status;
//wait for a previous vblank to finish, if necessary
while(true) {
while(true) { //wait for a previous vblank to finish, if necessary
device->GetRasterStatus(0, &status);
if(status.InVBlank == false) break;
if(!status.InVBlank) break;
}
//wait for next vblank to begin
while(true) {
while(true) { //wait for next vblank to begin
device->GetRasterStatus(0, &status);
if(status.InVBlank == true) break;
if(status.InVBlank) break;
}
}
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 {
RECT rd;
GetClientRect(settings.handle, &rd);
state.width = rd.right;
state.height = rd.bottom;
term();
lpd3d = Direct3DCreate9(D3D_SDK_VERSION);
if(!lpd3d) return false;
RECT rectangle;
GetClientRect(settings.handle, &rectangle);
windowWidth = rectangle.right;
windowHeight = rectangle.bottom;
memset(&presentation, 0, sizeof(presentation));
presentation.Flags = D3DPRESENTFLAG_VIDEO;
presentation.SwapEffect = D3DSWAPEFFECT_FLIP;
presentation.hDeviceWindow = settings.handle;
presentation.BackBufferCount = 1;
presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
presentation.MultiSampleQuality = 0;
context = Direct3DCreate9(D3D_SDK_VERSION);
if(!context) return false;
memory::fill(&presentation, sizeof(presentation));
presentation.Flags = D3DPRESENTFLAG_VIDEO;
presentation.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentation.BackBufferCount = 1;
presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
presentation.MultiSampleQuality = 0;
presentation.EnableAutoDepthStencil = false;
presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
presentation.Windowed = true;
presentation.BackBufferFormat = D3DFMT_UNKNOWN;
presentation.BackBufferWidth = 0;
presentation.BackBufferHeight = 0;
presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if(lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle,
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
return false;
if(!settings.exclusive) {
presentation.hDeviceWindow = settings.handle;
presentation.Windowed = true;
presentation.BackBufferFormat = D3DFMT_UNKNOWN;
presentation.BackBufferWidth = 0;
presentation.BackBufferHeight = 0;
ShowWindow(settings.exclusiveHandle, SW_HIDE);
if(context->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle,
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
return false;
}
} else {
presentation.hDeviceWindow = settings.exclusiveHandle;
presentation.Windowed = false;
presentation.BackBufferFormat = D3DFMT_X8R8G8B8;
presentation.BackBufferWidth = monitorWidth;
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(&d3dcaps);
device->GetDeviceCaps(&capabilities);
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;
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.t_usage = 0;
flags.v_usage = D3DUSAGE_WRITEONLY;
flags.t_pool = D3DPOOL_MANAGED;
flags.v_pool = D3DPOOL_MANAGED;
flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD;
flags.textureUsage = 0;
flags.texturePool = D3DPOOL_MANAGED;
flags.vertexUsage = D3DUSAGE_WRITEONLY;
flags.vertexPool = D3DPOOL_MANAGED;
}
lost = false;
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; }
return recover();
}
auto term() -> void {
release_resources();
if(device) { device->Release(); device = 0; }
if(lpd3d) { lpd3d->Release(); lpd3d = 0; }
if(vertexBuffer) { vertexBuffer->Release(); vertexBuffer = nullptr; }
if(surface) { surface->Release(); surface = nullptr; }
if(texture) { texture->Release(); texture = nullptr; }
if(device) { device->Release(); device = nullptr; }
if(context) { context->Release(); context = nullptr; }
}
};
#undef D3DVERTEX

View File

@ -1,7 +1,7 @@
#include <ddraw.h>
struct VideoDD : Video {
~VideoDD() { term(); }
struct VideoDirectDraw : Video {
~VideoDirectDraw() { term(); }
LPDIRECTDRAW lpdd = nullptr;
LPDIRECTDRAW7 lpdd7 = nullptr;
@ -10,15 +10,15 @@ struct VideoDD : Video {
LPDIRECTDRAWCLIPPER clipper = nullptr;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
unsigned iwidth;
unsigned iheight;
uint iwidth;
uint iheight;
struct {
HWND handle = nullptr;
bool synchronize = false;
unsigned width;
unsigned height;
uint width;
uint height;
} settings;
auto cap(const string& name) -> bool {
@ -34,8 +34,8 @@ struct VideoDD : Video {
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (HWND)value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = (HWND)value.get<uintptr>();
return true;
}
@ -47,7 +47,7 @@ struct VideoDD : Video {
return false;
}
auto resize(unsigned width, unsigned height) -> void {
auto resize(uint width, uint height) -> void {
if(iwidth >= width && iheight >= height) return;
iwidth = max(width, iwidth);
@ -94,7 +94,7 @@ struct VideoDD : Video {
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) {
resize(settings.width = width, settings.height = height);
}
@ -136,6 +136,8 @@ struct VideoDD : Video {
}
auto init() -> bool {
term();
DirectDrawCreate(0, &lpdd, 0);
lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7);
if(lpdd) { lpdd->Release(); lpdd = 0; }

View File

@ -28,8 +28,8 @@ struct VideoGDI : Video {
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (HWND)value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = (HWND)value.get<uintptr>();
return true;
}
@ -44,7 +44,7 @@ struct VideoGDI : Video {
DeleteObject(device.dc);
}
settings.buffer = new uint32_t[width * height]();
settings.width = width;
settings.width = width;
settings.height = height;
HDC hdc = GetDC(settings.handle);
@ -56,13 +56,13 @@ struct VideoGDI : Video {
ReleaseDC(settings.handle, hdc);
memory::fill(&device.info, sizeof(BITMAPINFO));
device.info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
device.info.bmiHeader.biWidth = width;
device.info.bmiHeader.biHeight = -height;
device.info.bmiHeader.biPlanes = 1;
device.info.bmiHeader.biBitCount = 32;
device.info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
device.info.bmiHeader.biWidth = width;
device.info.bmiHeader.biHeight = -height;
device.info.bmiHeader.biPlanes = 1;
device.info.bmiHeader.biBitCount = 32;
device.info.bmiHeader.biCompression = BI_RGB;
device.info.bmiHeader.biSizeImage = width * height * sizeof(uint32_t);
device.info.bmiHeader.biSizeImage = width * height * sizeof(uint32_t);
}
data = settings.buffer;

View File

@ -6,9 +6,9 @@
struct VideoGLX2 : Video {
~VideoGLX2() { term(); }
auto (*glXSwapInterval)(signed) -> signed = nullptr;
auto (*glXSwapInterval)(int) -> int = nullptr;
Display* display = nullptr;
signed screen = 0;
int screen = 0;
Window xwindow = 0;
Colormap colormap = 0;
GLXContext glxcontext = nullptr;
@ -17,10 +17,10 @@ struct VideoGLX2 : Video {
struct {
Window handle = 0;
bool synchronize = false;
unsigned filter = 1; //linear
uint filter = Video::FilterLinear;
unsigned width = 256;
unsigned height = 256;
uint width = 256;
uint height = 256;
bool isDoubleBuffered = false;
bool isDirect = false;
@ -34,15 +34,15 @@ struct VideoGLX2 : Video {
}
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::Filter) return settings.filter;
return {};
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = value.get<uintptr>();
return true;
}
@ -54,15 +54,15 @@ struct VideoGLX2 : Video {
}
}
if(name == Video::Filter && value.is<unsigned>()) {
settings.filter = value.get<unsigned>();
if(name == Video::Filter && value.is<uint>()) {
settings.filter = value.get<uint>();
return true;
}
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);
pitch = glwidth * sizeof(uint32_t);
return data = glbuffer;
@ -105,8 +105,8 @@ struct VideoGLX2 : Video {
double w = (double)settings.width / (double)glwidth;
double h = (double)settings.height / (double)glheight;
signed u = parent.width;
signed v = parent.height;
int u = parent.width;
int v = parent.height;
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
@ -123,14 +123,14 @@ struct VideoGLX2 : Video {
display = XOpenDisplay(0);
screen = DefaultScreen(display);
signed versionMajor = 0, versionMinor = 0;
int versionMajor = 0, versionMinor = 0;
glXQueryVersion(display, &versionMajor, &versionMinor);
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
XWindowAttributes windowAttributes;
XGetWindowAttributes(display, settings.handle, &windowAttributes);
signed attributeList[] = {
int attributeList[] = {
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True,
@ -140,7 +140,7 @@ struct VideoGLX2 : Video {
None
};
signed fbCount = 0;
int fbCount = 0;
auto fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount);
if(fbCount == 0) return false;
@ -163,12 +163,12 @@ struct VideoGLX2 : Video {
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
signed value = 0;
int value = 0;
glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value);
settings.isDoubleBuffered = value;
settings.isDirect = glXIsDirect(display, glxcontext);
@ -224,10 +224,10 @@ struct VideoGLX2 : Video {
private:
GLuint gltexture = 0;
uint32_t* glbuffer = nullptr;
unsigned glwidth = 0;
unsigned glheight = 0;
uint glwidth = 0;
uint glheight = 0;
auto resize(unsigned width, unsigned height) -> void {
auto resize(uint width, uint height) -> void {
settings.width = width;
settings.height = height;

View File

@ -11,14 +11,14 @@ struct VideoSDL : Video {
Display* display = nullptr;
SDL_Surface* screen = nullptr;
SDL_Surface* buffer = nullptr;
unsigned iwidth = 0;
unsigned iheight = 0;
uint iwidth = 0;
uint iheight = 0;
struct {
uintptr_t handle = 0;
uintptr handle = 0;
unsigned width = 0;
unsigned height = 0;
uint width = 0;
uint height = 0;
} settings;
auto cap(const string& name) -> bool {
@ -32,15 +32,15 @@ struct VideoSDL : Video {
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = value.get<uintptr>();
return true;
}
return false;
}
auto resize(unsigned width, unsigned height) -> void {
auto resize(uint width, uint height) -> void {
if(iwidth >= width && iheight >= height) return;
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) {
resize(settings.width = width, settings.height = height);
}
@ -69,9 +69,9 @@ struct VideoSDL : Video {
auto clear() -> void {
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);
for(unsigned x = 0; x < iwidth; x++) *data++ = 0xff000000;
for(uint x : range(iwidth)) *data++ = 0xff000000;
}
if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer);
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)
//to prevent blending against the window beneath when X window visual is 32-bits.
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);
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);
@ -119,8 +119,8 @@ struct VideoSDL : Video {
screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE);
XUndefineCursor(display, settings.handle);
buffer = 0;
iwidth = 0;
buffer = nullptr;
iwidth = 0;
iheight = 0;
resize(settings.width = 256, settings.height = 256);

View File

@ -93,10 +93,10 @@ struct VideoWGL : Video, OpenGL {
auto init() -> bool {
GLuint pixel_format;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
memory::fill(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
display = GetDC(settings.handle);
@ -117,7 +117,7 @@ struct VideoWGL : Video, OpenGL {
};
HGLRC context = wglCreateContextAttribs(display, 0, attributes);
if(context) {
wglMakeCurrent(NULL, NULL);
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(wglcontext);
wglMakeCurrent(display, wglcontext = context);
}