bsnes/ruby/video/directdraw.cpp
Tim Allen 1e4affe5f9 Update to 20180808 release.
byuu says:

This release fixes the XAudio 2.1 and WASAPI drivers on Windows, and
extends XAudio to support device selection (eg headphones, speakers,
monitor, etc.) It also adds DRC to XAudio, however it's not currently
working.

The code is courtesy of Talarubi, I just botched it somewhere upon
porting it to the newer version of ruby.
2018-08-09 14:16:46 +10:00

163 lines
5.1 KiB
C++

#include <ddraw.h>
#undef interface
struct VideoDirectDraw : VideoDriver {
VideoDirectDraw& self = *this;
VideoDirectDraw(Video& super) : VideoDriver(super) {}
~VideoDirectDraw() { terminate(); }
auto create() -> bool override {
return initialize();
}
auto driver() -> string override { return "DirectDraw 7.0"; }
auto ready() -> bool override { return _ready; }
auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto setContext(uintptr context) -> bool override {
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
return true;
}
auto clear() -> void override {
DDBLTFX fx = {};
fx.dwSize = sizeof(DDBLTFX);
fx.dwFillColor = 0x00000000;
_screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
_raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
}
auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
if(width != _width || height != _height) resize(_width = width, _height = height);
DDSURFACEDESC2 description = {};
description.dwSize = sizeof(DDSURFACEDESC2);
if(_raster->Lock(0, &description, DDLOCK_WAIT, 0) != DD_OK) {
_raster->Restore();
if(_raster->Lock(0, &description, DDLOCK_WAIT, 0) != DD_OK) return false;
}
pitch = description.lPitch;
return data = (uint32_t*)description.lpSurface;
}
auto release() -> void override {
_raster->Unlock(0);
}
auto output() -> void override {
if(self.blocking) while(true) {
BOOL vblank;
_interface->GetVerticalBlankStatus(&vblank);
if(vblank) break;
}
RECT source;
SetRect(&source, 0, 0, _width, _height);
POINT point = {0, 0};
ClientToScreen((HWND)self.context, &point);
RECT target;
GetClientRect((HWND)self.context, &target);
OffsetRect(&target, point.x, point.y);
if(_screen->Blt(&target, _raster, &source, DDBLT_WAIT, 0) == DDERR_SURFACELOST) {
_screen->Restore();
_raster->Restore();
}
}
private:
auto initialize() -> bool {
terminate();
if(!self.context) return false;
LPDIRECTDRAW interface = nullptr;
DirectDrawCreate(0, &interface, 0);
interface->QueryInterface(IID_IDirectDraw7, (void**)&_interface);
interface->Release();
_interface->SetCooperativeLevel((HWND)self.context, DDSCL_NORMAL);
DDSURFACEDESC2 description = {};
description.dwSize = sizeof(DDSURFACEDESC2);
description.dwFlags = DDSD_CAPS;
description.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
_interface->CreateSurface(&description, &_screen, 0);
_interface->CreateClipper(0, &_clipper, 0);
_clipper->SetHWnd(0, (HWND)self.context);
_screen->SetClipper(_clipper);
_raster = nullptr;
_surfaceWidth = 0;
_surfaceHeight = 0;
resize(_width = 256, _height = 256);
return _ready = true;
}
auto terminate() -> void {
_ready = false;
if(_clipper) { _clipper->Release(); _clipper = nullptr; }
if(_raster) { _raster->Release(); _raster = nullptr; }
if(_screen) { _screen->Release(); _screen = nullptr; }
if(_interface) { _interface->Release(); _interface = nullptr; }
}
auto resize(uint width, uint height) -> void {
if(_surfaceWidth >= width && _surfaceHeight >= height) return;
_surfaceWidth = max(width, _surfaceWidth);
_surfaceHeight = max(height, _surfaceHeight);
if(_raster) _raster->Release();
DDSURFACEDESC2 description = {};
description.dwSize = sizeof(DDSURFACEDESC2);
_screen->GetSurfaceDesc(&description);
int depth = description.ddpfPixelFormat.dwRGBBitCount;
if(depth == 32) goto tryNativeSurface;
memory::fill(&description, sizeof(DDSURFACEDESC2));
description.dwSize = sizeof(DDSURFACEDESC2);
description.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
description.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY
description.dwWidth = _surfaceWidth;
description.dwHeight = _surfaceHeight;
description.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
description.ddpfPixelFormat.dwFlags = DDPF_RGB;
description.ddpfPixelFormat.dwRGBBitCount = 32;
description.ddpfPixelFormat.dwRBitMask = 0xff0000;
description.ddpfPixelFormat.dwGBitMask = 0x00ff00;
description.ddpfPixelFormat.dwBBitMask = 0x0000ff;
if(_interface->CreateSurface(&description, &_raster, 0) == DD_OK) return clear();
tryNativeSurface:
memory::fill(&description, sizeof(DDSURFACEDESC2));
description.dwSize = sizeof(DDSURFACEDESC2);
description.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
description.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY
description.dwWidth = _surfaceWidth;
description.dwHeight = _surfaceHeight;
if(_interface->CreateSurface(&description, &_raster, 0) == DD_OK) return clear();
}
bool _ready = false;
uint _width = 0;
uint _height = 0;
LPDIRECTDRAW7 _interface = nullptr;
LPDIRECTDRAWSURFACE7 _screen = nullptr;
LPDIRECTDRAWSURFACE7 _raster = nullptr;
LPDIRECTDRAWCLIPPER _clipper = nullptr;
uint _surfaceWidth = 0;
uint _surfaceHeight = 0;
};