Linux: SDL video/audio + linux key manager
This commit is contained in:
parent
efca5284b1
commit
9ca1bf263c
9 changed files with 722 additions and 12 deletions
|
@ -20,7 +20,7 @@
|
|||
#include "../Utilities/UTF8Util.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __forceinline inline
|
||||
#define __forceinline
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.Net;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Automation;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using Mesen.GUI.Config;
|
||||
|
@ -699,7 +698,6 @@ namespace Mesen.GUI.Forms
|
|||
bool IMessageFilter.PreFilterMessage(ref Message m)
|
||||
{
|
||||
if(m.Msg == WM_KEYUP) {
|
||||
int virtualKeyCode = (Int32)m.WParam;
|
||||
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
|
||||
InteropEmu.SetKeyState(scanCode, false);
|
||||
}
|
||||
|
@ -710,7 +708,6 @@ namespace Mesen.GUI.Forms
|
|||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if(msg.Msg == WM_KEYDOWN) {
|
||||
int virtualKeyCode = (Int32)((Int64)msg.WParam & 0xFF);
|
||||
int scanCode = (Int32)(((Int64)msg.LParam & 0x1FF0000) >> 16);
|
||||
InteropEmu.SetKeyState(scanCode, true);
|
||||
}
|
||||
|
@ -1346,10 +1343,7 @@ namespace Mesen.GUI.Forms
|
|||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
if(File.Exists(files[0])) {
|
||||
LoadFile(files[0]);
|
||||
AutomationElement element = AutomationElement.FromHandle(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
|
||||
if(element != null) {
|
||||
element.SetFocus();
|
||||
}
|
||||
this.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include "../Windows/SoundManager.h"
|
||||
#include "../Windows/WindowsKeyManager.h"
|
||||
#else
|
||||
#include "../SDL/SdlRenderer.h"
|
||||
#include "../SDL/SdlSoundManager.h"
|
||||
#include "../SDL/SdlKeyManager.h"
|
||||
#include "../Linux/SdlRenderer.h"
|
||||
#include "../Linux/SdlSoundManager.h"
|
||||
#include "../Linux/LinuxKeyManager.h"
|
||||
#endif
|
||||
|
||||
IRenderingDevice *_renderer = nullptr;
|
||||
|
@ -98,7 +98,7 @@ namespace InteropEmu {
|
|||
#ifdef _WIN32
|
||||
_keyManager = new WindowsKeyManager((HWND)_windowHandle);
|
||||
#else
|
||||
_keyManager = new SdlKeyManager();
|
||||
_keyManager = new LinuxKeyManager();
|
||||
#endif
|
||||
|
||||
ControlManager::RegisterKeyManager(_keyManager);
|
||||
|
|
304
Linux/LinuxKeyManager.cpp
Executable file
304
Linux/LinuxKeyManager.cpp
Executable file
|
@ -0,0 +1,304 @@
|
|||
#include "LinuxKeyManager.h"
|
||||
#include "../Core/ControlManager.h"
|
||||
|
||||
static vector<KeyDefinition> _keyDefinitions = {
|
||||
{ "", 9, "Escape", "" },
|
||||
{ "", 10, "1", "" },
|
||||
{ "", 11, "2", "" },
|
||||
{ "", 12, "3", "" },
|
||||
{ "", 13, "4", "" },
|
||||
{ "", 14, "5", "" },
|
||||
{ "", 15, "6", "" },
|
||||
{ "", 16, "7", "" },
|
||||
{ "", 17, "8", "" },
|
||||
{ "", 18, "9", "" },
|
||||
{ "", 19, "0", "" },
|
||||
{ "", 20, "Minus", "" },
|
||||
{ "", 21, "Equal", "" },
|
||||
{ "", 22, "BackSpace", "" },
|
||||
{ "", 23, "Tab", "" },
|
||||
{ "", 24, "Q", "" },
|
||||
{ "", 25, "W", "" },
|
||||
{ "", 26, "E", "" },
|
||||
{ "", 27, "R", "" },
|
||||
{ "", 28, "T", "" },
|
||||
{ "", 29, "Y", "" },
|
||||
{ "", 30, "U", "" },
|
||||
{ "", 31, "I", "" },
|
||||
{ "", 32, "O", "" },
|
||||
{ "", 33, "P", "" },
|
||||
{ "", 34, "Left Bracket", "" },
|
||||
{ "", 35, "Right Bracket", "" },
|
||||
{ "", 36, "Return", "" },
|
||||
{ "", 37, "Left Control", "" },
|
||||
{ "", 38, "A", "" },
|
||||
{ "", 39, "S", "" },
|
||||
{ "", 40, "D", "" },
|
||||
{ "", 41, "F", "" },
|
||||
{ "", 42, "G", "" },
|
||||
{ "", 43, "H", "" },
|
||||
{ "", 44, "J", "" },
|
||||
{ "", 45, "K", "" },
|
||||
{ "", 46, "L", "" },
|
||||
{ "", 47, "Semicolor", "" },
|
||||
{ "", 48, "Apostrophe", "" },
|
||||
{ "", 49, "Grave", "" },
|
||||
{ "", 50, "Left Shift", "" },
|
||||
{ "", 51, "\\", "" },
|
||||
{ "", 52, "Z", "" },
|
||||
{ "", 53, "X", "" },
|
||||
{ "", 54, "C", "" },
|
||||
{ "", 55, "V", "" },
|
||||
{ "", 56, "B", "" },
|
||||
{ "", 57, "N", "" },
|
||||
{ "", 58, "M", "" },
|
||||
{ "", 59, ",", "" },
|
||||
{ "", 60, ".", "" },
|
||||
{ "", 61, "/", "" },
|
||||
{ "", 62, "Right Shift", "" },
|
||||
{ "", 63, "KP Multiply", "" },
|
||||
{ "", 64, "Left Alt", "" },
|
||||
{ "", 65, "Space", "" },
|
||||
{ "", 66, "Caps Lock", "" },
|
||||
{ "", 67, "F1", "" },
|
||||
{ "", 68, "F2", "" },
|
||||
{ "", 69, "F3", "" },
|
||||
{ "", 70, "F4", "" },
|
||||
{ "", 71, "F5", "" },
|
||||
{ "", 72, "F6", "" },
|
||||
{ "", 73, "F7", "" },
|
||||
{ "", 74, "F8", "" },
|
||||
{ "", 75, "F9", "" },
|
||||
{ "", 76, "F10", "" },
|
||||
{ "", 77, "Num Lock", "" },
|
||||
{ "", 78, "Scroll Lock", "" },
|
||||
{ "", 79, "KP Home", "" },
|
||||
{ "", 80, "KP Up", "" },
|
||||
{ "", 81, "KP Prior", "" },
|
||||
{ "", 82, "KP Subtract", "" },
|
||||
{ "", 83, "KP Left", "" },
|
||||
{ "", 84, "KP Begin", "" },
|
||||
{ "", 85, "KP Right", "" },
|
||||
{ "", 86, "KP Add", "" },
|
||||
{ "", 87, "KP End", "" },
|
||||
{ "", 88, "KP Down", "" },
|
||||
{ "", 89, "KP Next", "" },
|
||||
{ "", 90, "KP Insert", "" },
|
||||
{ "", 91, "KP Delete", "" },
|
||||
{ "", 92, "ISO_Level3_Shift", "" },
|
||||
{ "", 94, "Less", "" },
|
||||
{ "", 95, "F11", "" },
|
||||
{ "", 96, "F12", "" },
|
||||
{ "", 98, "Katakana", "" },
|
||||
{ "", 99, "Hiragana", "" },
|
||||
{ "", 100, "Henkan_Mode", "" },
|
||||
{ "", 101, "Hiragana_Katakana", "" },
|
||||
{ "", 102, "Muhenkan", "" },
|
||||
{ "", 104, "KP_Enter", "" },
|
||||
{ "", 105, "Control_R", "" },
|
||||
{ "", 106, "KP_Divide", "" },
|
||||
{ "", 107, "Print", "" },
|
||||
{ "", 108, "Right Alt", "" },
|
||||
{ "", 109, "Linefeed", "" },
|
||||
{ "", 110, "Home", "" },
|
||||
{ "", 111, "Up Arrow", "" },
|
||||
{ "", 112, "Prior", "" },
|
||||
{ "", 113, "Left Arrow", "" },
|
||||
{ "", 114, "Right Arrow", "" },
|
||||
{ "", 115, "End", "" },
|
||||
{ "", 116, "Down Arrow", "" },
|
||||
{ "", 117, "Next", "" },
|
||||
{ "", 118, "Insert", "" },
|
||||
{ "", 119, "Delete", "" },
|
||||
{ "", 121, "XF86AudioMute", "" },
|
||||
{ "", 122, "XF86AudioLowerVolume", "" },
|
||||
{ "", 123, "XF86AudioRaiseVolume", "" },
|
||||
{ "", 124, "XF86PowerOff", "" },
|
||||
{ "", 125, "KP_Equal", "" },
|
||||
{ "", 126, "PlusMinus", "" },
|
||||
{ "", 127, "Pause", "" },
|
||||
{ "", 128, "XF86LaunchA", "" },
|
||||
{ "", 129, "KP_Decimal", "" },
|
||||
{ "", 130, "Hangul", "" },
|
||||
{ "", 131, "Hangul_Hanja", "" },
|
||||
{ "", 133, "Super_L", "" },
|
||||
{ "", 134, "Super_R", "" },
|
||||
{ "", 135, "Menu", "" },
|
||||
{ "", 136, "Cancel", "" },
|
||||
{ "", 137, "Redo", "" },
|
||||
{ "", 138, "SunProps", "" },
|
||||
{ "", 139, "Undo", "" },
|
||||
{ "", 140, "SunFront", "" },
|
||||
{ "", 141, "XF86Copy", "" },
|
||||
{ "", 142, "XF86Open", "" },
|
||||
{ "", 143, "XF86Paste", "" },
|
||||
{ "", 144, "Find", "" },
|
||||
{ "", 145, "XF86Cut", "" },
|
||||
{ "", 146, "Help", "" },
|
||||
{ "", 147, "XF86MenuKB", "" },
|
||||
{ "", 148, "XF86Calculator", "" },
|
||||
{ "", 150, "XF86Sleep", "" },
|
||||
{ "", 151, "XF86WakeUp", "" },
|
||||
{ "", 152, "XF86Explorer", "" },
|
||||
{ "", 153, "XF86Send", "" },
|
||||
{ "", 155, "XF86Xfer", "" },
|
||||
{ "", 156, "XF86Launch1", "" },
|
||||
{ "", 157, "XF86Launch2", "" },
|
||||
{ "", 158, "XF86WWW", "" },
|
||||
{ "", 159, "XF86DOS", "" },
|
||||
{ "", 160, "XF86ScreenSaver", "" },
|
||||
{ "", 161, "XF86RotateWindows", "" },
|
||||
{ "", 162, "XF86TaskPane", "" },
|
||||
{ "", 163, "XF86Mail", "" },
|
||||
{ "", 164, "XF86Favorites", "" },
|
||||
{ "", 165, "XF86MyComputer", "" },
|
||||
{ "", 166, "XF86Back", "" },
|
||||
{ "", 167, "XF86Forward", "" },
|
||||
{ "", 169, "XF86Eject", "" },
|
||||
{ "", 170, "XF86Eject", "" },
|
||||
{ "", 171, "XF86AudioNext", "" },
|
||||
{ "", 172, "XF86AudioPlay", "" },
|
||||
{ "", 173, "XF86AudioPrev", "" },
|
||||
{ "", 174, "XF86AudioStop", "" },
|
||||
{ "", 175, "XF86AudioRecord", "" },
|
||||
{ "", 176, "XF86AudioRewind", "" },
|
||||
{ "", 177, "XF86Phone", "" },
|
||||
{ "", 179, "XF86Tools", "" },
|
||||
{ "", 180, "XF86HomePage", "" },
|
||||
{ "", 181, "XF86Reload", "" },
|
||||
{ "", 182, "XF86Close", "" },
|
||||
{ "", 185, "XF86ScrollUp", "" },
|
||||
{ "", 186, "XF86ScrollDown", "" },
|
||||
{ "", 187, "Paren Left", "" },
|
||||
{ "", 188, "Paren Right", "" },
|
||||
{ "", 189, "XF86New", "" },
|
||||
{ "", 190, "Redo", "" },
|
||||
{ "", 191, "XF86Tools", "" },
|
||||
{ "", 192, "XF86Launch5", "" },
|
||||
{ "", 193, "XF86Launch6", "" },
|
||||
{ "", 194, "XF86Launch7", "" },
|
||||
{ "", 195, "XF86Launch8", "" },
|
||||
{ "", 196, "XF86Launch9", "" },
|
||||
{ "", 198, "XF86AudioMicMute", "" },
|
||||
{ "", 199, "XF86TouchpadToggle", "" },
|
||||
{ "", 200, "XF86TouchpadOn", "" },
|
||||
{ "", 201, "XF86TouchpadOff", "" },
|
||||
{ "", 203, "Mode_switch", "" },
|
||||
{ "", 204, "NoSymbol", "" },
|
||||
{ "", 205, "NoSymbol", "" },
|
||||
{ "", 206, "NoSymbol", "" },
|
||||
{ "", 207, "NoSymbol", "" },
|
||||
{ "", 208, "XF86AudioPlay", "" },
|
||||
{ "", 209, "XF86AudioPause", "" },
|
||||
{ "", 210, "XF86Launch3", "" },
|
||||
{ "", 211, "XF86Launch4", "" },
|
||||
{ "", 212, "XF86LaunchB", "" },
|
||||
{ "", 213, "XF86Suspend", "" },
|
||||
{ "", 214, "XF86Close", "" },
|
||||
{ "", 215, "XF86AudioPlay", "" },
|
||||
{ "", 216, "XF86AudioForward", "" },
|
||||
{ "", 218, "Print", "" },
|
||||
{ "", 220, "XF86WebCam", "" },
|
||||
{ "", 223, "XF86Mail", "" },
|
||||
{ "", 224, "XF86Messenger", "" },
|
||||
{ "", 225, "XF86Search", "" },
|
||||
{ "", 226, "XF86Go", "" },
|
||||
{ "", 227, "XF86Finance", "" },
|
||||
{ "", 228, "XF86Game", "" },
|
||||
{ "", 229, "XF86Shop", "" },
|
||||
{ "", 231, "Cancel", "" },
|
||||
{ "", 232, "XF86MonBrightnessDown", "" },
|
||||
{ "", 233, "XF86MonBrightnessUp", "" },
|
||||
{ "", 234, "XF86AudioMedia", "" },
|
||||
{ "", 235, "XF86Display", "" },
|
||||
{ "", 236, "XF86KbdLightOnOff", "" },
|
||||
{ "", 237, "XF86KbdBrightnessDown", "" },
|
||||
{ "", 238, "XF86KbdBrightnessUp", "" },
|
||||
{ "", 239, "XF86Send", "" },
|
||||
{ "", 240, "XF86Reply", "" },
|
||||
{ "", 241, "XF86MailForward", "" },
|
||||
{ "", 242, "XF86Save", "" },
|
||||
{ "", 243, "XF86Documents", "" },
|
||||
{ "", 244, "XF86Battery", "" },
|
||||
{ "", 245, "XF86Bluetooth", "" },
|
||||
{ "", 246, "XF86WLAN", "" },
|
||||
};
|
||||
|
||||
LinuxKeyManager::LinuxKeyManager()
|
||||
{
|
||||
_keyState.insert(_keyState.end(), 0x200, 0);
|
||||
|
||||
for(KeyDefinition &keyDef : _keyDefinitions) {
|
||||
_keyNames[keyDef.keyCode] = keyDef.description;
|
||||
_keyCodes[keyDef.description] = keyDef.keyCode;
|
||||
}
|
||||
}
|
||||
|
||||
LinuxKeyManager::~LinuxKeyManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LinuxKeyManager::RefreshState()
|
||||
{
|
||||
//TODO: NOT IMPLEMENTED YET;
|
||||
//Only needed to detect poll controller input
|
||||
}
|
||||
|
||||
bool LinuxKeyManager::IsKeyPressed(uint32_t key)
|
||||
{
|
||||
if(key < 0x200) {
|
||||
return _keyState[key & 0xFF] != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LinuxKeyManager::IsMouseButtonPressed(MouseButton button)
|
||||
{
|
||||
//TODO: NOT IMPLEMENTED YET
|
||||
//Only needed for zapper/etc
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t LinuxKeyManager::GetPressedKey()
|
||||
{
|
||||
for(int i = 0; i < 0x200; i++) {
|
||||
if(_keyState[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string LinuxKeyManager::GetKeyName(uint32_t key)
|
||||
{
|
||||
auto keyDef = _keyNames.find(key & 0xFF);
|
||||
if(keyDef != _keyNames.end()) {
|
||||
return keyDef->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
uint32_t LinuxKeyManager::GetKeyCode(string keyName)
|
||||
{
|
||||
auto keyDef = _keyCodes.find(keyName);
|
||||
if(keyDef != _keyCodes.end()) {
|
||||
return keyDef->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LinuxKeyManager::UpdateDevices()
|
||||
{
|
||||
//TODO: NOT IMPLEMENTED YET
|
||||
//Only needed to detect newly plugged in devices
|
||||
}
|
||||
|
||||
void LinuxKeyManager::SetKeyState(uint16_t scanCode, bool state)
|
||||
{
|
||||
_keyState[scanCode & 0xFF] = state ? 1 : 0;
|
||||
}
|
||||
|
||||
void LinuxKeyManager::ResetKeyState()
|
||||
{
|
||||
memset(_keyState.data(), 0, 0x200 * sizeof(uint32_t));
|
||||
}
|
34
Linux/LinuxKeyManager.h
Executable file
34
Linux/LinuxKeyManager.h
Executable file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "../Core/IKeyManager.h"
|
||||
|
||||
struct KeyDefinition {
|
||||
string name;
|
||||
uint32_t keyCode;
|
||||
string description;
|
||||
string extDescription;
|
||||
};
|
||||
|
||||
class LinuxKeyManager : public IKeyManager
|
||||
{
|
||||
private:
|
||||
int _numKeys;
|
||||
vector<uint32_t> _keyState;
|
||||
std::unordered_map<uint32_t, string> _keyNames;
|
||||
std::unordered_map<string, uint32_t> _keyCodes;
|
||||
|
||||
public:
|
||||
LinuxKeyManager();
|
||||
virtual ~LinuxKeyManager();
|
||||
|
||||
void RefreshState();
|
||||
bool IsKeyPressed(uint32_t key);
|
||||
bool IsMouseButtonPressed(MouseButton button);
|
||||
uint32_t GetPressedKey();
|
||||
string GetKeyName(uint32_t key);
|
||||
uint32_t GetKeyCode(string keyName);
|
||||
|
||||
void UpdateDevices();
|
||||
void SetKeyState(uint16_t scanCode, bool state);
|
||||
void ResetKeyState();
|
||||
};
|
114
Linux/SdlRenderer.cpp
Executable file
114
Linux/SdlRenderer.cpp
Executable file
|
@ -0,0 +1,114 @@
|
|||
#include "SdlRenderer.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
#include "../Core/VideoDecoder.h"
|
||||
#include "../Core/EmulationSettings.h"
|
||||
|
||||
SdlRenderer::SdlRenderer(void* windowHandle) : _windowHandle(windowHandle)
|
||||
{
|
||||
_frameBuffer = nullptr;
|
||||
SetScreenSize(256,240);
|
||||
VideoRenderer::GetInstance()->RegisterRenderingDevice(this);
|
||||
}
|
||||
|
||||
SdlRenderer::~SdlRenderer()
|
||||
{
|
||||
VideoRenderer::GetInstance()->UnregisterRenderingDevice(this);
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void SdlRenderer::Init()
|
||||
{
|
||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||
_sdlWindow = SDL_CreateWindowFrom(_windowHandle);
|
||||
|
||||
//Hack to make this work properly - otherwise SDL_CreateRenderer never returns
|
||||
_sdlWindow->flags |= SDL_WINDOW_OPENGL;
|
||||
SDL_GL_LoadLibrary(NULL);
|
||||
|
||||
_sdlRenderer = SDL_CreateRenderer(_sdlWindow, -1, SDL_RENDERER_ACCELERATED);
|
||||
_sdlTexture = SDL_CreateTexture(_sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, _nesFrameWidth, _nesFrameHeight);
|
||||
|
||||
_frameBuffer = new uint8_t[_nesFrameHeight*_nesFrameWidth*4];
|
||||
memset(_frameBuffer, 0, _nesFrameHeight*_nesFrameWidth*4);
|
||||
}
|
||||
|
||||
void SdlRenderer::Cleanup()
|
||||
{
|
||||
if(_sdlTexture) {
|
||||
SDL_DestroyTexture(_sdlTexture);
|
||||
_sdlTexture = nullptr;
|
||||
}
|
||||
if(_sdlRenderer) {
|
||||
SDL_DestroyRenderer(_sdlRenderer);
|
||||
_sdlRenderer = nullptr;
|
||||
}
|
||||
if(_frameBuffer) {
|
||||
delete[] _frameBuffer;
|
||||
_frameBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlRenderer::Reset()
|
||||
{
|
||||
_frameLock.Acquire();
|
||||
Cleanup();
|
||||
Init();
|
||||
_frameLock.Release();
|
||||
}
|
||||
|
||||
void SdlRenderer::SetScreenSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
ScreenSize screenSize;
|
||||
VideoDecoder::GetInstance()->GetScreenSize(screenSize, true);
|
||||
|
||||
double scale = EmulationSettings::GetVideoScale();
|
||||
if(_scale != scale || _screenHeight != (uint32_t)screenSize.Height || _screenWidth != (uint32_t)screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != EmulationSettings::GetVideoResizeFilter()) {
|
||||
_frameLock.Acquire();
|
||||
|
||||
_nesFrameHeight = height;
|
||||
_nesFrameWidth = width;
|
||||
_newFrameBufferSize = width*height;
|
||||
|
||||
_screenHeight = screenSize.Height;
|
||||
_screenWidth = screenSize.Width;
|
||||
|
||||
_resizeFilter = EmulationSettings::GetVideoResizeFilter();
|
||||
_scale = scale;
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, _resizeFilter == VideoResizeFilter::Bilinear ? "1" : "0");
|
||||
SDL_RenderSetLogicalSize(_sdlRenderer, _nesFrameWidth, _nesFrameHeight);
|
||||
|
||||
_screenBufferSize = _screenHeight*_screenWidth;
|
||||
|
||||
Reset();
|
||||
_frameLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
void SdlRenderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height)
|
||||
{
|
||||
_frameLock.Acquire();
|
||||
SetScreenSize(width, height);
|
||||
memcpy(_frameBuffer, frameBuffer, width*height*4);
|
||||
_frameLock.Release();
|
||||
}
|
||||
|
||||
void SdlRenderer::Render()
|
||||
{
|
||||
auto lock = _frameLock.AcquireSafe();
|
||||
|
||||
SDL_RenderClear(_sdlRenderer);
|
||||
|
||||
uint8_t *textureBuffer;
|
||||
int rowPitch;
|
||||
SDL_LockTexture(_sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch);
|
||||
uint32_t* ppuFrameBuffer = (uint32_t*)_frameBuffer;
|
||||
for(uint32_t i = 0, iMax = _nesFrameHeight; i < iMax; i++) {
|
||||
memcpy(textureBuffer, ppuFrameBuffer, _nesFrameWidth*4);
|
||||
ppuFrameBuffer += _nesFrameWidth;
|
||||
textureBuffer += rowPitch;
|
||||
}
|
||||
SDL_UnlockTexture(_sdlTexture);
|
||||
|
||||
SDL_RenderCopy(_sdlRenderer, _sdlTexture, nullptr, nullptr);
|
||||
SDL_RenderPresent(_sdlRenderer);
|
||||
}
|
56
Linux/SdlRenderer.h
Executable file
56
Linux/SdlRenderer.h
Executable file
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include "../Core/IRenderingDevice.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "../Core/EmulationSettings.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
|
||||
struct SDL_Window
|
||||
{
|
||||
const void *magic;
|
||||
Uint32 id;
|
||||
char *title;
|
||||
SDL_Surface *icon;
|
||||
int x, y;
|
||||
int w, h;
|
||||
int min_w, min_h;
|
||||
int max_w, max_h;
|
||||
Uint32 flags;
|
||||
};
|
||||
typedef struct SDL_Window SDL_Window;
|
||||
|
||||
class SdlRenderer : public IRenderingDevice
|
||||
{
|
||||
private:
|
||||
void* _windowHandle;
|
||||
SDL_Window* _sdlWindow = nullptr;
|
||||
SDL_Renderer *_sdlRenderer = nullptr;
|
||||
SDL_Texture *_sdlTexture = nullptr;
|
||||
|
||||
VideoResizeFilter _resizeFilter = VideoResizeFilter::NearestNeighbor;
|
||||
|
||||
SimpleLock _frameLock;
|
||||
uint8_t* _frameBuffer;
|
||||
|
||||
const uint32_t _bytesPerPixel = 4;
|
||||
uint32_t _screenWidth = 0;
|
||||
uint32_t _screenHeight = 0;
|
||||
uint32_t _screenBufferSize = 0;
|
||||
double _scale = 0;
|
||||
|
||||
uint32_t _nesFrameHeight = 0;
|
||||
uint32_t _nesFrameWidth = 0;
|
||||
uint32_t _newFrameBufferSize = 0;
|
||||
|
||||
void Init();
|
||||
void Cleanup();
|
||||
void SetScreenSize(uint32_t width, uint32_t height);
|
||||
|
||||
public:
|
||||
SdlRenderer(void* windowHandle);
|
||||
virtual ~SdlRenderer();
|
||||
|
||||
void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height);
|
||||
void Render();
|
||||
void Reset();
|
||||
};
|
168
Linux/SdlSoundManager.cpp
Executable file
168
Linux/SdlSoundManager.cpp
Executable file
|
@ -0,0 +1,168 @@
|
|||
#include "SdlSoundManager.h"
|
||||
#include "../Core/EmulationSettings.h"
|
||||
#include "../Core/SoundMixer.h"
|
||||
|
||||
SdlSoundManager::SdlSoundManager()
|
||||
{
|
||||
if(InitializeAudio(44100, false)) {
|
||||
SoundMixer::RegisterAudioDevice(this);
|
||||
|
||||
_buffer = new uint8_t[0xFFFF];
|
||||
}
|
||||
}
|
||||
|
||||
SdlSoundManager::~SdlSoundManager()
|
||||
{
|
||||
if(_buffer) {
|
||||
delete[] _buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::FillAudioBuffer(void *userData, uint8_t *stream, int len)
|
||||
{
|
||||
SdlSoundManager* soundManager = (SdlSoundManager*)userData;
|
||||
|
||||
soundManager->ReadFromBuffer(stream, len);
|
||||
}
|
||||
|
||||
bool SdlSoundManager::InitializeAudio(uint32_t sampleRate, bool isStereo)
|
||||
{
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int isCapture = 0;
|
||||
|
||||
_sampleRate = sampleRate;
|
||||
_isStereo = isStereo;
|
||||
|
||||
SDL_AudioSpec audioSpec;
|
||||
SDL_memset(&audioSpec, 0, sizeof(audioSpec));
|
||||
audioSpec.freq = sampleRate;
|
||||
audioSpec.format = AUDIO_S16SYS; //16-bit samples
|
||||
audioSpec.channels = isStereo ? 2 : 1;
|
||||
audioSpec.samples = 1024;
|
||||
audioSpec.callback = &SdlSoundManager::FillAudioBuffer;
|
||||
audioSpec.userdata = this;
|
||||
|
||||
SDL_AudioSpec obtainedSpec;
|
||||
|
||||
_audioDeviceID = SDL_OpenAudioDevice(_deviceName.empty() ? nullptr : _deviceName.c_str(), isCapture, &audioSpec, &obtainedSpec, 0);
|
||||
|
||||
_writePosition = 0;
|
||||
_readPosition = 0;
|
||||
|
||||
_needReset = false;
|
||||
|
||||
return _audioDeviceID != 0;
|
||||
}
|
||||
|
||||
string SdlSoundManager::GetAvailableDevices()
|
||||
{
|
||||
string deviceString;
|
||||
for(string device : GetAvailableDeviceInfo()) {
|
||||
deviceString += device + std::string("||");
|
||||
}
|
||||
return deviceString;
|
||||
}
|
||||
|
||||
vector<string> SdlSoundManager::GetAvailableDeviceInfo()
|
||||
{
|
||||
vector<string> deviceList;
|
||||
int isCapture = 0;
|
||||
int deviceCount = SDL_GetNumAudioDevices(isCapture);
|
||||
|
||||
if(deviceCount == -1) {
|
||||
//No devices found
|
||||
} else {
|
||||
for(int i = 0; i < deviceCount; i++) {
|
||||
deviceList.push_back(SDL_GetAudioDeviceName(i, isCapture));
|
||||
}
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
void SdlSoundManager::SetAudioDevice(string deviceName)
|
||||
{
|
||||
if(deviceName.compare(_deviceName) != 0) {
|
||||
_deviceName = deviceName;
|
||||
_needReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::ReadFromBuffer(uint8_t* output, uint32_t len)
|
||||
{
|
||||
if(_readPosition + len < 65536) {
|
||||
memcpy(output, _buffer+_readPosition, len);
|
||||
_readPosition += len;
|
||||
} else {
|
||||
int remainingBytes = (65536 - _readPosition);
|
||||
memcpy(output, _buffer+_readPosition, remainingBytes);
|
||||
memcpy(output+remainingBytes, _buffer, len - remainingBytes);
|
||||
_readPosition = len - remainingBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::WriteToBuffer(uint8_t* input, uint32_t len)
|
||||
{
|
||||
if(_writePosition + len < 65536) {
|
||||
memcpy(_buffer+_writePosition, input, len);
|
||||
_writePosition += len;
|
||||
} else {
|
||||
int remainingBytes = 65536 - _writePosition;
|
||||
memcpy(_buffer+_writePosition, input, remainingBytes);
|
||||
memcpy(_buffer, ((uint8_t*)input)+remainingBytes, len - remainingBytes);
|
||||
_writePosition = len - remainingBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo)
|
||||
{
|
||||
uint32_t bytesPerSample = (SoundMixer::BitsPerSample / 8);
|
||||
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset) {
|
||||
Stop();
|
||||
InitializeAudio(sampleRate, isStereo);
|
||||
}
|
||||
|
||||
if(isStereo) {
|
||||
bytesPerSample *= 2;
|
||||
}
|
||||
|
||||
int32_t byteLatency = (int32_t)((float)(sampleRate * EmulationSettings::GetAudioLatency()) / 1000.0f * bytesPerSample);
|
||||
if(byteLatency != _previousLatency) {
|
||||
Stop();
|
||||
_previousLatency = byteLatency;
|
||||
}
|
||||
|
||||
WriteToBuffer((uint8_t*)soundBuffer, sampleCount * bytesPerSample);
|
||||
|
||||
int32_t playWriteByteLatency = _writePosition - _readPosition;
|
||||
if(playWriteByteLatency < 0) {
|
||||
playWriteByteLatency = 0xFFFF - _readPosition + _writePosition;
|
||||
}
|
||||
|
||||
if(playWriteByteLatency > byteLatency * 3) {
|
||||
//Out of sync, resync
|
||||
Stop();
|
||||
WriteToBuffer((uint8_t*)soundBuffer, sampleCount * bytesPerSample);
|
||||
playWriteByteLatency = _writePosition - _readPosition;
|
||||
}
|
||||
|
||||
if(playWriteByteLatency > byteLatency) {
|
||||
//Start playing
|
||||
SDL_PauseAudioDevice(_audioDeviceID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::Pause()
|
||||
{
|
||||
SDL_PauseAudioDevice(_audioDeviceID, 1);
|
||||
}
|
||||
|
||||
void SdlSoundManager::Stop()
|
||||
{
|
||||
Pause();
|
||||
_readPosition = 0;
|
||||
_writePosition = 0;
|
||||
}
|
40
Linux/SdlSoundManager.h
Executable file
40
Linux/SdlSoundManager.h
Executable file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include "../Core/IAudioDevice.h"
|
||||
|
||||
class SdlSoundManager : public IAudioDevice
|
||||
{
|
||||
public:
|
||||
SdlSoundManager();
|
||||
~SdlSoundManager();
|
||||
|
||||
void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo);
|
||||
void Pause();
|
||||
void Stop();
|
||||
|
||||
string GetAvailableDevices();
|
||||
void SetAudioDevice(string deviceName);
|
||||
|
||||
private:
|
||||
vector<string> GetAvailableDeviceInfo();
|
||||
bool InitializeAudio(uint32_t sampleRate, bool isStereo);
|
||||
|
||||
static void FillAudioBuffer(void *userData, uint8_t *stream, int len);
|
||||
|
||||
void ReadFromBuffer(uint8_t* output, uint32_t len);
|
||||
void WriteToBuffer(uint8_t* output, uint32_t len);
|
||||
|
||||
private:
|
||||
SDL_AudioDeviceID _audioDeviceID;
|
||||
string _deviceName;
|
||||
bool _needReset = false;
|
||||
|
||||
uint16_t _lastWriteOffset = 0;
|
||||
uint16_t _previousLatency = 0;
|
||||
uint32_t _sampleRate = 0;
|
||||
bool _isStereo = false;
|
||||
|
||||
uint8_t* _buffer = nullptr;
|
||||
uint32_t _writePosition = 0;
|
||||
uint32_t _readPosition = 0;
|
||||
};
|
Loading…
Add table
Reference in a new issue