Linux: Fixed build/makefile and compilation errors/warnings (and add missing files to git)
This commit is contained in:
parent
ace5321598
commit
e1c7e7b9c4
51 changed files with 7569 additions and 137 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -182,8 +182,6 @@ packages/*
|
|||
|
||||
!Libretro/hakchi/bin
|
||||
|
||||
Dependencies/*
|
||||
Linux/*
|
||||
Libretro/*
|
||||
Docs/*
|
||||
Lua/*
|
||||
|
|
|
@ -201,7 +201,7 @@ void BaseCartridge::MapBanks(MemoryManager &mm, vector<unique_ptr<IMemoryHandler
|
|||
uint32_t baseAddress = i << 16;
|
||||
pageNumber += pageIncrement;
|
||||
for(uint32_t j = startPage; j <= endPage; j++) {
|
||||
mm.RegisterHandler(baseAddress + (j * 0x1000), baseAddress + (j * 0x1000) | 0xFFF, handlers[pageNumber].get());
|
||||
mm.RegisterHandler(baseAddress + (j * 0x1000), (baseAddress + (j * 0x1000)) | 0xFFF, handlers[pageNumber].get());
|
||||
//MessageManager::Log("Map [$" + HexUtilities::ToHex(i) + ":" + HexUtilities::ToHex(j)[1] + "xxx] to page number " + HexUtilities::ToHex(pageNumber));
|
||||
pageNumber++;
|
||||
if(pageNumber >= handlers.size()) {
|
||||
|
|
|
@ -44,7 +44,7 @@ private:
|
|||
void DisplayCartInfo();
|
||||
|
||||
public:
|
||||
~BaseCartridge();
|
||||
virtual ~BaseCartridge();
|
||||
|
||||
static shared_ptr<BaseCartridge> CreateCartridge(VirtualFile &romFile, VirtualFile &patchFile);
|
||||
|
||||
|
|
|
@ -327,6 +327,7 @@ double Console::GetFrameDelay()
|
|||
} else {
|
||||
UpdateRegion();
|
||||
switch(_region) {
|
||||
default:
|
||||
case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 16.6666666666666666667 : 16.63926405550947; break;
|
||||
case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; break;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ protected:
|
|||
|
||||
public:
|
||||
ControlManager(shared_ptr<Console> console);
|
||||
~ControlManager();
|
||||
virtual ~ControlManager();
|
||||
|
||||
void UpdateControlDevices();
|
||||
void UpdateInputState();
|
||||
|
|
|
@ -289,7 +289,7 @@ private:
|
|||
|
||||
public:
|
||||
Cpu(Console *console);
|
||||
~Cpu();
|
||||
virtual ~Cpu();
|
||||
|
||||
void PowerOn();
|
||||
|
||||
|
@ -316,8 +316,6 @@ private:
|
|||
uint32_t _readAddresses[10];
|
||||
uint8_t _readValue[10];
|
||||
|
||||
uint32_t _valueSize = 0;
|
||||
|
||||
void LogRead(uint32_t addr, uint8_t value);
|
||||
void LogWrite(uint32_t addr, uint8_t value);
|
||||
|
||||
|
|
|
@ -43,11 +43,9 @@ void DebugStats::DisplayStats(double lastFrameTime)
|
|||
hud->DrawString(134, 10, "Video Stats", 0xFFFFFF, 0xFF000000, 1, startFrame);
|
||||
|
||||
double totalDuration = 0;
|
||||
if(_frameDurations) {
|
||||
for(int i = 0; i < 60; i++) {
|
||||
totalDuration += _frameDurations[i];
|
||||
}
|
||||
}
|
||||
|
||||
ss = std::stringstream();
|
||||
ss << "FPS: " << std::fixed << std::setprecision(4) << (1000 / (totalDuration / 60));
|
||||
|
|
|
@ -251,7 +251,7 @@ void Debugger::SleepUntilResume()
|
|||
|
||||
void Debugger::ProcessStepConditions(uint8_t opCode, uint32_t currentPc)
|
||||
{
|
||||
if(_breakAddress == currentPc && (opCode == 0x60 || opCode == 0x40 || opCode == 0x6B || opCode == 0x44 || opCode == 0x54)) {
|
||||
if(_breakAddress == (int32_t)currentPc && (opCode == 0x60 || opCode == 0x40 || opCode == 0x6B || opCode == 0x44 || opCode == 0x54)) {
|
||||
//RTS/RTL/RTI found, if we're on the expected return address, break immediately (for step over/step out)
|
||||
_cpuStepCount = 0;
|
||||
}
|
||||
|
@ -277,6 +277,8 @@ void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool fo
|
|||
void Debugger::ProcessEvent(EventType type)
|
||||
{
|
||||
switch(type) {
|
||||
default: break;
|
||||
|
||||
case EventType::StartFrame:
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh);
|
||||
_eventManager->ClearFrameEvents();
|
||||
|
|
|
@ -10,7 +10,6 @@ private:
|
|||
uint32_t _calculatedPalette[0x8000];
|
||||
double _yiqToRgbMatrix[6];
|
||||
VideoConfig _videoConfig;
|
||||
bool _needToProcess = false;
|
||||
|
||||
void InitConversionMatrix(double hueShift, double saturationShift);
|
||||
void InitLookupTable();
|
||||
|
|
|
@ -182,6 +182,7 @@ DisassemblyInfo Disassembler::GetDisassemblyInfo(AddressInfo &info)
|
|||
{
|
||||
DisassemblyInfo* disassemblyInfo = nullptr;
|
||||
switch(info.Type) {
|
||||
default: break;
|
||||
case SnesMemoryType::PrgRom: disassemblyInfo = _prgCache[info.Address].get(); break;
|
||||
case SnesMemoryType::WorkRam: disassemblyInfo = _wramCache[info.Address].get(); break;
|
||||
case SnesMemoryType::SaveRam: disassemblyInfo = _sramCache[info.Address].get(); break;
|
||||
|
@ -204,7 +205,7 @@ uint32_t Disassembler::GetLineIndex(uint32_t cpuAddress)
|
|||
{
|
||||
auto lock = _disassemblyLock.AcquireSafe();
|
||||
uint32_t lastAddress = 0;
|
||||
for(int i = 1; i < _disassembly.size(); i++) {
|
||||
for(size_t i = 1; i < _disassembly.size(); i++) {
|
||||
if(_disassembly[i].CpuAddress < 0) {
|
||||
continue;
|
||||
}
|
||||
|
@ -228,6 +229,7 @@ bool Disassembler::GetLineData(uint32_t lineIndex, CodeLineData &data)
|
|||
data.Flags = result.Flags;
|
||||
|
||||
switch(result.Address.Type) {
|
||||
default: break;
|
||||
case SnesMemoryType::PrgRom: data.Flags |= (uint8_t)LineFlags::PrgRom; break;
|
||||
case SnesMemoryType::WorkRam: data.Flags |= (uint8_t)LineFlags::WorkRam; break;
|
||||
case SnesMemoryType::SaveRam: data.Flags |= (uint8_t)LineFlags::SaveRam; break;
|
||||
|
@ -297,7 +299,7 @@ int32_t Disassembler::SearchDisassembly(const char *searchString, int32_t startP
|
|||
}
|
||||
|
||||
//Continue search from start/end of document
|
||||
if(!searchBackwards && i == _disassembly.size() - 1) {
|
||||
if(!searchBackwards && i == (int)(_disassembly.size() - 1)) {
|
||||
i = 0;
|
||||
} else if(searchBackwards && i == 0) {
|
||||
i = (int32_t)(_disassembly.size() - 1);
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
#include "MessageManager.h"
|
||||
#include "../Utilities/Serializer.h"
|
||||
|
||||
static constexpr uint8_t _transferByteCount[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
static constexpr uint8_t _transferOffset[8][4] = {
|
||||
{ 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 },
|
||||
{ 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }
|
||||
};
|
||||
|
||||
DmaController::DmaController(MemoryManager *memoryManager)
|
||||
{
|
||||
_memoryManager = memoryManager;
|
||||
|
@ -53,7 +59,7 @@ void DmaController::RunSingleTransfer(DmaChannelConfig &channel)
|
|||
do {
|
||||
CopyDmaByte(
|
||||
(channel.SrcBank << 16) | channel.SrcAddress,
|
||||
0x2100 | channel.DestAddress + transferOffsets[i],
|
||||
0x2100 | (channel.DestAddress + transferOffsets[i]),
|
||||
channel.InvertDirection
|
||||
);
|
||||
|
||||
|
@ -137,7 +143,7 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
|
|||
do {
|
||||
CopyDmaByte(
|
||||
(channel.HdmaBank << 16) | channel.TransferSize,
|
||||
0x2100 | channel.DestAddress + transferOffsets[i],
|
||||
0x2100 | (channel.DestAddress + transferOffsets[i]),
|
||||
channel.InvertDirection
|
||||
);
|
||||
channel.TransferSize++;
|
||||
|
@ -148,7 +154,7 @@ void DmaController::RunHdmaTransfer(DmaChannelConfig &channel)
|
|||
do {
|
||||
CopyDmaByte(
|
||||
(channel.SrcBank << 16) | channel.HdmaTableAddress,
|
||||
0x2100 | channel.DestAddress + transferOffsets[i],
|
||||
0x2100 | (channel.DestAddress + transferOffsets[i]),
|
||||
channel.InvertDirection
|
||||
);
|
||||
channel.HdmaTableAddress++;
|
||||
|
|
|
@ -29,15 +29,9 @@ struct DmaChannelConfig
|
|||
bool UnusedFlag;
|
||||
};
|
||||
|
||||
class DmaController : public ISerializable
|
||||
class DmaController final : public ISerializable
|
||||
{
|
||||
private:
|
||||
static constexpr uint8_t _transferByteCount[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
static constexpr uint8_t _transferOffset[8][4] = {
|
||||
{ 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 },
|
||||
{ 0, 1, 2, 3 }, { 0, 1, 0, 1 }, { 0, 0, 0, 0 }, { 0, 0, 1, 1 }
|
||||
};
|
||||
|
||||
bool _hdmaPending = false;
|
||||
uint8_t _hdmaChannels = 0;
|
||||
|
||||
|
|
|
@ -130,9 +130,9 @@ void EmuSettings::SetShortcutKeys(vector<ShortcutKeyInfo> shortcuts)
|
|||
|
||||
for(ShortcutKeyInfo &shortcut : shortcuts) {
|
||||
if(_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty()) {
|
||||
SetShortcutKey(shortcut.Shortcut, shortcut.KeyCombination, 0);
|
||||
SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 0);
|
||||
} else {
|
||||
SetShortcutKey(shortcut.Shortcut, shortcut.KeyCombination, 1);
|
||||
SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,6 @@ void EventManager::GetDisplayBuffer(uint32_t *buffer, EventViewerDisplayOptions
|
|||
bool overscanMode = _ppu->GetState().OverscanMode;
|
||||
//Skip the first 8 blank lines in the buffer when overscan mode is off
|
||||
uint16_t *ppuBuffer = _ppu->GetScreenBuffer() + (overscanMode ? 0 : (512 * 16));
|
||||
uint32_t pixelCount = 256*2*239*2;
|
||||
for(uint32_t y = 0, len = overscanMode ? 239*2 : 224*2; y < len; y++) {
|
||||
for(uint32_t x = 0; x < 512; x++) {
|
||||
buffer[(y + 2)*340*2 + x + 22*2] = DefaultVideoFilter::ToArgb(ppuBuffer[(y << 9) | x]);
|
||||
|
|
|
@ -56,7 +56,7 @@ EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator)
|
|||
bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data)
|
||||
{
|
||||
string token;
|
||||
size_t initialPos = pos;
|
||||
//size_t initialPos = pos;
|
||||
size_t len = expression.size();
|
||||
do {
|
||||
char c = std::tolower(expression[pos]);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class Console;
|
||||
|
||||
class InternalRegisters : public ISerializable
|
||||
class InternalRegisters final : public ISerializable
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
|
|
@ -23,6 +23,7 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
|
|||
}
|
||||
|
||||
switch(type) {
|
||||
default:
|
||||
case SnesMemoryType::CpuMemory:
|
||||
break;
|
||||
|
||||
|
@ -39,6 +40,7 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
|
|||
uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
|
||||
{
|
||||
switch(type) {
|
||||
default: return 0;
|
||||
case SnesMemoryType::CpuMemory: return 0x1000000;
|
||||
case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize();
|
||||
case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize;
|
||||
|
@ -48,12 +50,13 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
|
|||
case SnesMemoryType::CGRam: return Ppu::CgRamSize;
|
||||
case SnesMemoryType::SpcRam: return Spc::SpcRamSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
|
||||
{
|
||||
switch(type) {
|
||||
default: break;
|
||||
|
||||
case SnesMemoryType::CpuMemory:
|
||||
for(int i = 0; i <= 0xFFFFFF; i+=0x1000) {
|
||||
_memoryManager->PeekBlock(i, buffer+i);
|
||||
|
@ -84,6 +87,8 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
|
|||
}
|
||||
|
||||
switch(memoryType) {
|
||||
default: break;
|
||||
|
||||
case SnesMemoryType::CpuMemory: _memoryManager->Write(address, value, MemoryOperationType::Write); break;
|
||||
|
||||
case SnesMemoryType::PrgRom: _cartridge->DebugGetPrgRom()[address] = value; break;
|
||||
|
@ -104,6 +109,8 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
|
|||
}
|
||||
|
||||
switch(memoryType) {
|
||||
default: return 0;
|
||||
|
||||
case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address);
|
||||
|
||||
case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom()[address];
|
||||
|
@ -115,8 +122,6 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
|
|||
case SnesMemoryType::CGRam: return _ppu->GetCgRam()[address];
|
||||
case SnesMemoryType::SpcRam: return _spc->GetSpcRam()[address];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t MemoryDumper::GetMemoryValueWord(SnesMemoryType memoryType, uint32_t address)
|
||||
|
|
|
@ -39,7 +39,7 @@ private:
|
|||
|
||||
public:
|
||||
void Initialize(shared_ptr<Console> console);
|
||||
~MemoryManager();
|
||||
virtual ~MemoryManager();
|
||||
|
||||
void Reset();
|
||||
|
||||
|
|
11
Core/Ppu.cpp
11
Core/Ppu.cpp
|
@ -15,6 +15,17 @@
|
|||
#include "../Utilities/HexUtilities.h"
|
||||
#include "../Utilities/Serializer.h"
|
||||
|
||||
static constexpr uint8_t _oamSizes[8][2][2] = {
|
||||
{ { 1, 1 }, { 2, 2 } }, //8x8 + 16x16
|
||||
{ { 1, 1 }, { 4, 4 } }, //8x8 + 32x32
|
||||
{ { 1, 1 }, { 8, 8 } }, //8x8 + 64x64
|
||||
{ { 2, 2 }, { 4, 4 } }, //16x16 + 32x32
|
||||
{ { 2, 2 }, { 8, 8 } }, //16x16 + 64x64
|
||||
{ { 4, 4 }, { 8, 8 } }, //32x32 + 64x64
|
||||
{ { 2, 4 }, { 4, 8 } }, //16x32 + 32x64
|
||||
{ { 2, 4 }, { 4, 4 } } //16x32 + 32x32
|
||||
};
|
||||
|
||||
Ppu::Ppu(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
|
|
13
Core/Ppu.h
13
Core/Ppu.h
|
@ -32,17 +32,6 @@ private:
|
|||
constexpr static int SpriteLayerIndex = 4;
|
||||
constexpr static int ColorWindowIndex = 5;
|
||||
|
||||
constexpr static const uint8_t _oamSizes[8][2][2] = {
|
||||
{ { 1, 1 }, { 2, 2 } }, //8x8 + 16x16
|
||||
{ { 1, 1 }, { 4, 4 } }, //8x8 + 32x32
|
||||
{ { 1, 1 }, { 8, 8 } }, //8x8 + 64x64
|
||||
{ { 2, 2 }, { 4, 4 } }, //16x16 + 32x32
|
||||
{ { 2, 2 }, { 8, 8 } }, //16x16 + 64x64
|
||||
{ { 4, 4 }, { 8, 8 } }, //32x32 + 64x64
|
||||
{ { 2, 4 }, { 4, 8 } }, //16x32 + 32x64
|
||||
{ { 2, 4 }, { 4, 4 } } //16x32 + 32x32
|
||||
};
|
||||
|
||||
shared_ptr<Console> _console;
|
||||
shared_ptr<InternalRegisters> _regs;
|
||||
|
||||
|
@ -223,7 +212,7 @@ private:
|
|||
|
||||
public:
|
||||
Ppu(shared_ptr<Console> console);
|
||||
~Ppu();
|
||||
virtual ~Ppu();
|
||||
|
||||
void Reset();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
|
||||
enum class EmulationFlags
|
||||
{
|
||||
|
@ -226,7 +227,7 @@ struct InputConfig
|
|||
uint32_t MouseSensitivity = 1;
|
||||
};
|
||||
|
||||
enum class RamPowerOnState
|
||||
enum class RamState
|
||||
{
|
||||
AllZeros = 0,
|
||||
AllOnes = 1,
|
||||
|
@ -254,7 +255,7 @@ struct EmulationConfig
|
|||
uint32_t PpuExtraScanlinesBeforeNmi = 0;
|
||||
uint32_t PpuExtraScanlinesAfterNmi = 0;
|
||||
|
||||
RamPowerOnState RamPowerOnState = RamPowerOnState::AllZeros;
|
||||
RamState RamPowerOnState = RamState::AllZeros;
|
||||
};
|
||||
|
||||
struct PreferencesConfig
|
||||
|
@ -409,5 +410,5 @@ struct KeyCombination
|
|||
struct ShortcutKeyInfo
|
||||
{
|
||||
EmulatorShortcut Shortcut;
|
||||
KeyCombination KeyCombination;
|
||||
KeyCombination Keys;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Console.h"
|
||||
#include "RewindManager.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "SaveStateManager.h"
|
||||
|
||||
ShortcutKeyHandler::ShortcutKeyHandler(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -110,7 +111,7 @@ void ShortcutKeyHandler::CheckMappedKeys()
|
|||
{
|
||||
shared_ptr<EmuSettings> settings = _console->GetSettings();
|
||||
bool isNetplayClient = false; //TODO GameClient::Connected();
|
||||
bool isMovieActive = false; //TODO MovieManager::Playing() || MovieManager::Recording();
|
||||
//bool isMovieActive = false; //TODO MovieManager::Playing() || MovieManager::Recording();
|
||||
bool isMovieRecording = false; //TODO MovieManager::Recording();
|
||||
|
||||
//Let the UI handle these shortcuts
|
||||
|
@ -135,7 +136,6 @@ void ShortcutKeyHandler::CheckMappedKeys()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if(DetectKeyPress(EmulatorShortcut::MoveToNextStateSlot)) {
|
||||
_console->GetSaveStateManager()->MoveToNextSlot();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ void ShortcutKeyHandler::CheckMappedKeys()
|
|||
_console->GetSaveStateManager()->LoadState();
|
||||
}
|
||||
|
||||
if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) {
|
||||
/*if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) {
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats);
|
||||
}*/
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ private:
|
|||
|
||||
public:
|
||||
Spc(shared_ptr<Console> console, vector<uint8_t> &spcRomData);
|
||||
~Spc();
|
||||
virtual ~Spc();
|
||||
|
||||
void Run();
|
||||
void Reset();
|
||||
|
|
49
Core/dsp.cpp
49
Core/dsp.cpp
|
@ -1,49 +0,0 @@
|
|||
#include "stdafx.h"
|
||||
// snes_spc 0.9.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "SPC_DSP.h"
|
||||
|
||||
/* Copyright (C) 2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
SPC_DSP* spc_dsp_new( void )
|
||||
{
|
||||
// be sure constants match
|
||||
assert( spc_dsp_voice_count == (int) SPC_DSP::voice_count );
|
||||
assert( spc_dsp_register_count == (int) SPC_DSP::register_count );
|
||||
#if !SPC_NO_COPY_STATE_FUNCS
|
||||
assert( spc_dsp_state_size == (int) SPC_DSP::state_size );
|
||||
#endif
|
||||
|
||||
return new SPC_DSP;
|
||||
}
|
||||
|
||||
void spc_dsp_delete ( SPC_DSP* s ) { delete s; }
|
||||
void spc_dsp_init ( SPC_DSP* s, void* ram_64k ) { s->init( ram_64k ); }
|
||||
void spc_dsp_set_output ( SPC_DSP* s, spc_dsp_sample_t* p, int n ) { s->set_output( p, n ); }
|
||||
int spc_dsp_sample_count( SPC_DSP const* s ) { return s->sample_count(); }
|
||||
void spc_dsp_reset ( SPC_DSP* s ) { s->reset(); }
|
||||
void spc_dsp_soft_reset ( SPC_DSP* s ) { s->soft_reset(); }
|
||||
int spc_dsp_read ( SPC_DSP const* s, int addr ) { return s->read( addr ); }
|
||||
void spc_dsp_write ( SPC_DSP* s, int addr, int data ) { s->write( addr, data ); }
|
||||
void spc_dsp_run ( SPC_DSP* s, int clock_count ) { s->run( clock_count ); }
|
||||
void spc_dsp_mute_voices ( SPC_DSP* s, int mask ) { s->mute_voices( mask ); }
|
||||
void spc_dsp_disable_surround( SPC_DSP* s, int disable ) { s->disable_surround( disable ); }
|
||||
void spc_dsp_load ( SPC_DSP* s, unsigned char const regs [spc_dsp_register_count] ) { s->load( regs ); }
|
||||
|
||||
#if !SPC_NO_COPY_STATE_FUNCS
|
||||
void spc_dsp_copy_state ( SPC_DSP* s, unsigned char** p, spc_dsp_copy_func_t f ) { s->copy_state( p, f ); }
|
||||
int spc_dsp_check_kon ( SPC_DSP* s ) { return s->check_kon(); }
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
#include <string>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
@ -50,9 +51,3 @@ using std::atomic_flag;
|
|||
using std::atomic;
|
||||
using std::thread;
|
||||
using std::deque;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "C:\\Code\\Mesen-S\\bin\\x64\\Debug\\Utilities.lib")
|
||||
#else
|
||||
#pragma comment(lib, "C:\\Code\\Mesen-S\\bin\\x64\\Release\\Utilities.lib")
|
||||
#endif
|
BIN
Dependencies/DirectXTK.Debug.Static.x64.lib
vendored
Normal file
BIN
Dependencies/DirectXTK.Debug.Static.x64.lib
vendored
Normal file
Binary file not shown.
BIN
Dependencies/DirectXTK.Debug.Static.x86.lib
vendored
Normal file
BIN
Dependencies/DirectXTK.Debug.Static.x86.lib
vendored
Normal file
Binary file not shown.
BIN
Dependencies/DirectXTK.Release.Static.x64.lib
vendored
Normal file
BIN
Dependencies/DirectXTK.Release.Static.x64.lib
vendored
Normal file
Binary file not shown.
BIN
Dependencies/DirectXTK.Release.Static.x86.lib
vendored
Normal file
BIN
Dependencies/DirectXTK.Release.Static.x86.lib
vendored
Normal file
Binary file not shown.
|
@ -11,6 +11,7 @@
|
|||
#include "../Core/KeyManager.h"
|
||||
#include "../Core/ShortcutKeyHandler.h"
|
||||
#include "../Utilities/ArchiveReader.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "InteropNotificationListeners.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -172,12 +173,12 @@ extern "C" {
|
|||
|
||||
_console->Stop(true);
|
||||
|
||||
_console->Release();
|
||||
_console.reset();
|
||||
|
||||
_renderer.reset();
|
||||
_soundManager.reset();
|
||||
_keyManager.reset();
|
||||
|
||||
_console->Release();
|
||||
_console.reset();
|
||||
}
|
||||
|
||||
DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback)
|
||||
|
|
231
Linux/LinuxGameController.cpp
Normal file
231
Linux/LinuxGameController.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
#include "../Core/MessageManager.h"
|
||||
#include "../Core/Console.h"
|
||||
#include "../Core/EmuSettings.h"
|
||||
#include "LinuxGameController.h"
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
|
||||
std::shared_ptr<LinuxGameController> LinuxGameController::GetController(shared_ptr<Console> console, int deviceID, bool logInformation)
|
||||
{
|
||||
std::string deviceName = "/dev/input/event" + std::to_string(deviceID);
|
||||
struct stat buffer;
|
||||
if(stat(deviceName.c_str(), &buffer) == 0) {
|
||||
int fd = open(deviceName.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if(fd < 0) {
|
||||
if(logInformation) {
|
||||
MessageManager::Log("[Input] " + deviceName + " error: " + std::to_string(errno) + " " + strerror(errno));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
libevdev* device = nullptr;
|
||||
int rc = libevdev_new_from_fd(fd, &device);
|
||||
if(rc < 0) {
|
||||
if(logInformation) {
|
||||
MessageManager::Log("[Input] " + deviceName + " error: " + std::to_string(errno) + " " + strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if((libevdev_has_event_type(device, EV_KEY) && libevdev_has_event_code(device, EV_KEY, BTN_GAMEPAD)) ||
|
||||
(libevdev_has_event_type(device, EV_ABS) && libevdev_has_event_code(device, EV_ABS, ABS_X))) {
|
||||
MessageManager::Log(std::string("[Input Connected] Name: ") + libevdev_get_name(device) + " Vendor: " + std::to_string(libevdev_get_id_vendor(device)) + " Product: " + std::to_string(libevdev_get_id_product(device)));
|
||||
return std::shared_ptr<LinuxGameController>(new LinuxGameController(console, deviceID, fd, device));
|
||||
} else {
|
||||
MessageManager::Log(std::string("[Input] Device ignored (Not a gamepad) - Name: ") + libevdev_get_name(device) + " Vendor: " + std::to_string(libevdev_get_id_vendor(device)) + " Product: " + std::to_string(libevdev_get_id_product(device)));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LinuxGameController::LinuxGameController(shared_ptr<Console> console, int deviceID, int fileDescriptor, libevdev* device)
|
||||
{
|
||||
_console = console;
|
||||
_deviceID = deviceID;
|
||||
_stopFlag = false;
|
||||
_device = device;
|
||||
_fd = fileDescriptor;
|
||||
memset(_axisDefaultValue, 0, sizeof(_axisDefaultValue));
|
||||
|
||||
_eventThread = std::thread([=]() {
|
||||
int rc;
|
||||
bool calibrate = true;
|
||||
|
||||
do {
|
||||
fd_set readSet;
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET(_fd, &readSet);
|
||||
|
||||
//Timeout after 0.1 seconds (to allow thread to be terminated quickly)
|
||||
timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100000;
|
||||
|
||||
rc = select((int)_fd+1, &readSet, nullptr, nullptr, &timeout);
|
||||
if(rc) {
|
||||
do {
|
||||
struct input_event ev;
|
||||
rc = libevdev_next_event(_device, LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||
if(rc == LIBEVDEV_READ_STATUS_SYNC) {
|
||||
while (rc == LIBEVDEV_READ_STATUS_SYNC) {
|
||||
rc = libevdev_next_event(_device, LIBEVDEV_READ_FLAG_SYNC, &ev);
|
||||
}
|
||||
} else if(rc == LIBEVDEV_READ_STATUS_SUCCESS) {
|
||||
//print_event(&ev);
|
||||
}
|
||||
} while(rc == LIBEVDEV_READ_STATUS_SYNC || rc == LIBEVDEV_READ_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
if(rc != LIBEVDEV_READ_STATUS_SYNC && rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN && rc != EWOULDBLOCK) {
|
||||
//Device was disconnected
|
||||
MessageManager::Log("[Input Device] Disconnected");
|
||||
break;
|
||||
}
|
||||
|
||||
if(calibrate) {
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
Calibrate();
|
||||
calibrate = false;
|
||||
}
|
||||
} while(!_stopFlag);
|
||||
|
||||
_disconnected = true;
|
||||
});
|
||||
}
|
||||
|
||||
LinuxGameController::~LinuxGameController()
|
||||
{
|
||||
_stopFlag = true;
|
||||
_eventThread.join();
|
||||
|
||||
libevdev_free(_device);
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
void LinuxGameController::Calibrate()
|
||||
{
|
||||
int axes[14] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y, ABS_HAT3X, ABS_HAT3Y };
|
||||
for(int axis : axes) {
|
||||
_axisDefaultValue[axis] = libevdev_get_event_value(_device, EV_ABS, axis);
|
||||
//std::cout << "center values: " << std::to_string(_axisDefaultValue[axis]) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxGameController::CheckAxis(unsigned int code, bool forPositive)
|
||||
{
|
||||
double deadZoneRatio = 1; //TODO _console->GetSettings()->GetControllerDeadzoneRatio();
|
||||
int deadZoneNegative = (_axisDefaultValue[code] - libevdev_get_abs_minimum(_device, code)) * 0.400 * deadZoneRatio;
|
||||
int deadZonePositive = (libevdev_get_abs_maximum(_device, code) - _axisDefaultValue[code]) * 0.400 * deadZoneRatio;
|
||||
|
||||
if(forPositive) {
|
||||
return libevdev_get_event_value(_device, EV_ABS, code) - _axisDefaultValue[code] > deadZonePositive;
|
||||
} else {
|
||||
return libevdev_get_event_value(_device, EV_ABS, code) - _axisDefaultValue[code] < -deadZoneNegative;
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxGameController::IsButtonPressed(int buttonNumber)
|
||||
{
|
||||
switch(buttonNumber) {
|
||||
case 0: return libevdev_get_event_value(_device, EV_KEY, BTN_A) == 1;
|
||||
case 1: return libevdev_get_event_value(_device, EV_KEY, BTN_B) == 1;
|
||||
case 2: return libevdev_get_event_value(_device, EV_KEY, BTN_C) == 1;
|
||||
case 3: return libevdev_get_event_value(_device, EV_KEY, BTN_X) == 1;
|
||||
case 4: return libevdev_get_event_value(_device, EV_KEY, BTN_Y) == 1;
|
||||
case 5: return libevdev_get_event_value(_device, EV_KEY, BTN_Z) == 1;
|
||||
case 6: return libevdev_get_event_value(_device, EV_KEY, BTN_TL) == 1;
|
||||
case 7: return libevdev_get_event_value(_device, EV_KEY, BTN_TR) == 1;
|
||||
case 8: return libevdev_get_event_value(_device, EV_KEY, BTN_TL2) == 1;
|
||||
case 9: return libevdev_get_event_value(_device, EV_KEY, BTN_TR2) == 1;
|
||||
case 10: return libevdev_get_event_value(_device, EV_KEY, BTN_SELECT) == 1;
|
||||
case 11: return libevdev_get_event_value(_device, EV_KEY, BTN_START) == 1;
|
||||
case 12: return libevdev_get_event_value(_device, EV_KEY, BTN_THUMBL) == 1;
|
||||
case 13: return libevdev_get_event_value(_device, EV_KEY, BTN_THUMBR) == 1;
|
||||
|
||||
case 14: return CheckAxis(ABS_X, true);
|
||||
case 15: return CheckAxis(ABS_X, false);
|
||||
case 16: return CheckAxis(ABS_Y, true);
|
||||
case 17: return CheckAxis(ABS_Y, false);
|
||||
case 18: return CheckAxis(ABS_Z, true);
|
||||
case 19: return CheckAxis(ABS_Z, false);
|
||||
case 20: return CheckAxis(ABS_RX, true);
|
||||
case 21: return CheckAxis(ABS_RX, false);
|
||||
case 22: return CheckAxis(ABS_RY, true);
|
||||
case 23: return CheckAxis(ABS_RY, false);
|
||||
case 24: return CheckAxis(ABS_RZ, true);
|
||||
case 25: return CheckAxis(ABS_RZ, false);
|
||||
|
||||
case 26: return CheckAxis(ABS_HAT0X, true);
|
||||
case 27: return CheckAxis(ABS_HAT0X, false);
|
||||
case 28: return CheckAxis(ABS_HAT0Y, true);
|
||||
case 29: return CheckAxis(ABS_HAT0Y, false);
|
||||
case 30: return CheckAxis(ABS_HAT1X, true);
|
||||
case 31: return CheckAxis(ABS_HAT1X, false);
|
||||
case 32: return CheckAxis(ABS_HAT1Y, true);
|
||||
case 33: return CheckAxis(ABS_HAT1Y, false);
|
||||
case 34: return CheckAxis(ABS_HAT2X, true);
|
||||
case 35: return CheckAxis(ABS_HAT2X, false);
|
||||
case 36: return CheckAxis(ABS_HAT2Y, true);
|
||||
case 37: return CheckAxis(ABS_HAT2Y, false);
|
||||
case 38: return CheckAxis(ABS_HAT3X, true);
|
||||
case 39: return CheckAxis(ABS_HAT3X, false);
|
||||
case 40: return CheckAxis(ABS_HAT3Y, true);
|
||||
case 41: return CheckAxis(ABS_HAT3Y, false);
|
||||
|
||||
case 42: return libevdev_get_event_value(_device, EV_KEY, BTN_TRIGGER) == 1;
|
||||
case 43: return libevdev_get_event_value(_device, EV_KEY, BTN_THUMB) == 1;
|
||||
case 44: return libevdev_get_event_value(_device, EV_KEY, BTN_THUMB2) == 1;
|
||||
case 45: return libevdev_get_event_value(_device, EV_KEY, BTN_TOP) == 1;
|
||||
case 46: return libevdev_get_event_value(_device, EV_KEY, BTN_TOP2) == 1;
|
||||
case 47: return libevdev_get_event_value(_device, EV_KEY, BTN_PINKIE) == 1;
|
||||
case 48: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE) == 1;
|
||||
case 49: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE2) == 1;
|
||||
case 50: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE3) == 1;
|
||||
case 51: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE4) == 1;
|
||||
case 52: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE5) == 1;
|
||||
case 53: return libevdev_get_event_value(_device, EV_KEY, BTN_BASE6) == 1;
|
||||
case 54: return libevdev_get_event_value(_device, EV_KEY, BTN_DEAD) == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LinuxGameController::IsDisconnected()
|
||||
{
|
||||
return _disconnected;
|
||||
}
|
||||
|
||||
int LinuxGameController::GetDeviceID()
|
||||
{
|
||||
return _deviceID;
|
||||
}
|
||||
|
||||
/*
|
||||
static int print_event(struct input_event *ev)
|
||||
{
|
||||
if (ev->type == EV_SYN)
|
||||
printf("Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n",
|
||||
ev->time.tv_sec,
|
||||
ev->time.tv_usec,
|
||||
libevdev_event_type_get_name(ev->type));
|
||||
else
|
||||
printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
|
||||
ev->time.tv_sec,
|
||||
ev->time.tv_usec,
|
||||
ev->type,
|
||||
libevdev_event_type_get_name(ev->type),
|
||||
ev->code,
|
||||
libevdev_event_code_get_name(ev->type, ev->code),
|
||||
ev->value);
|
||||
return 0;
|
||||
}
|
||||
*/
|
32
Linux/LinuxGameController.h
Normal file
32
Linux/LinuxGameController.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
struct libevdev;
|
||||
class Console;
|
||||
|
||||
class LinuxGameController
|
||||
{
|
||||
private:
|
||||
int _fd = -1;
|
||||
int _deviceID = -1;
|
||||
libevdev *_device = nullptr;
|
||||
bool _disconnected = false;
|
||||
std::thread _eventThread;
|
||||
std::atomic<bool> _stopFlag;
|
||||
shared_ptr<Console> _console;
|
||||
int _axisDefaultValue[0x100];
|
||||
|
||||
LinuxGameController(shared_ptr<Console> console, int deviceID, int fileDescriptor, libevdev *device);
|
||||
bool CheckAxis(unsigned int code, bool forPositive);
|
||||
void Calibrate();
|
||||
|
||||
public:
|
||||
~LinuxGameController();
|
||||
|
||||
static std::shared_ptr<LinuxGameController> GetController(shared_ptr<Console> console, int deviceID, bool logInformation);
|
||||
|
||||
bool IsDisconnected();
|
||||
int GetDeviceID();
|
||||
bool IsButtonPressed(int buttonNumber);
|
||||
};
|
443
Linux/LinuxKeyManager.cpp
Normal file
443
Linux/LinuxKeyManager.cpp
Normal file
|
@ -0,0 +1,443 @@
|
|||
#include <algorithm>
|
||||
#include "LinuxKeyManager.h"
|
||||
#include "LinuxGameController.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Core/ControlManager.h"
|
||||
#include "../Core/Console.h"
|
||||
|
||||
static vector<KeyDefinition> _keyDefinitions = {
|
||||
{ "", 9, "Esc", "" },
|
||||
{ "", 10, "1", "" },
|
||||
{ "", 11, "2", "" },
|
||||
{ "", 12, "3", "" },
|
||||
{ "", 13, "4", "" },
|
||||
{ "", 14, "5", "" },
|
||||
{ "", 15, "6", "" },
|
||||
{ "", 16, "7", "" },
|
||||
{ "", 17, "8", "" },
|
||||
{ "", 18, "9", "" },
|
||||
{ "", 19, "0", "" },
|
||||
{ "", 20, "-", "" },
|
||||
{ "", 21, "=", "" },
|
||||
{ "", 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, "[", "" },
|
||||
{ "", 35, "]", "" },
|
||||
{ "", 36, "Enter", "" },
|
||||
{ "", 37, "Ctrl", "" },
|
||||
{ "", 38, "A", "" },
|
||||
{ "", 39, "S", "" },
|
||||
{ "", 40, "D", "" },
|
||||
{ "", 41, "F", "" },
|
||||
{ "", 42, "G", "" },
|
||||
{ "", 43, "H", "" },
|
||||
{ "", 44, "J", "" },
|
||||
{ "", 45, "K", "" },
|
||||
{ "", 46, "L", "" },
|
||||
{ "", 47, ";", "" },
|
||||
{ "", 48, "'", "" },
|
||||
{ "", 49, "`", "" },
|
||||
{ "", 50, "Shift", "" },
|
||||
{ "", 51, "\\", "" },
|
||||
{ "", 52, "Z", "" },
|
||||
{ "", 53, "X", "" },
|
||||
{ "", 54, "C", "" },
|
||||
{ "", 55, "V", "" },
|
||||
{ "", 56, "B", "" },
|
||||
{ "", 57, "N", "" },
|
||||
{ "", 58, "M", "" },
|
||||
{ "", 59, ",", "" },
|
||||
{ "", 60, ".", "" },
|
||||
{ "", 61, "/", "" },
|
||||
{ "", 62, "Right Shift", "" },
|
||||
{ "", 63, "Numpad *", "" },
|
||||
{ "", 64, "Alt", "" },
|
||||
{ "", 65, "Spacebar", "" },
|
||||
{ "", 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, "Numpad 7", "" },
|
||||
{ "", 80, "Numpad 8", "" },
|
||||
{ "", 81, "Numpad 9", "" },
|
||||
{ "", 82, "Numpad -", "" },
|
||||
{ "", 83, "Numpad 4", "" },
|
||||
{ "", 84, "Numpad 5", "" },
|
||||
{ "", 85, "Numpad 6", "" },
|
||||
{ "", 86, "Numpad +", "" },
|
||||
{ "", 87, "Numpad 1", "" },
|
||||
{ "", 88, "Numpad 2", "" },
|
||||
{ "", 89, "Numpad 3", "" },
|
||||
{ "", 90, "Numpad 0", "" },
|
||||
{ "", 91, "Numpad .", "" },
|
||||
{ "", 92, "ISO_Level3_Shift", "" },
|
||||
{ "", 94, "Pipe", "" },
|
||||
{ "", 95, "F11", "" },
|
||||
{ "", 96, "F12", "" },
|
||||
{ "", 98, "Katakana", "" },
|
||||
{ "", 99, "Hiragana", "" },
|
||||
{ "", 100, "Henkan_Mode", "" },
|
||||
{ "", 101, "Hiragana_Katakana", "" },
|
||||
{ "", 102, "Muhenkan", "" },
|
||||
{ "", 104, "Numpad Enter", "" },
|
||||
{ "", 105, "Control_R", "" },
|
||||
{ "", 106, "Numpad /", "" },
|
||||
{ "", 107, "Print", "" },
|
||||
{ "", 108, "Right Alt", "" },
|
||||
{ "", 109, "Linefeed", "" },
|
||||
{ "", 110, "Home", "" },
|
||||
{ "", 111, "Up Arrow", "" },
|
||||
{ "", 112, "Page Up", "" },
|
||||
{ "", 113, "Left Arrow", "" },
|
||||
{ "", 114, "Right Arrow", "" },
|
||||
{ "", 115, "End", "" },
|
||||
{ "", 116, "Down Arrow", "" },
|
||||
{ "", 117, "Page Down", "" },
|
||||
{ "", 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(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
|
||||
ResetKeyState();
|
||||
|
||||
vector<string> buttonNames = {
|
||||
"A", "B", "C", "X", "Y", "Z", "L1", "R1", "L2", "R2", "Select", "Start", "L3", "R3",
|
||||
"X+", "X-", "Y+", "Y-", "Z+", "Z-",
|
||||
"X2+", "X2-", "Y2+", "Y2-", "Z2+", "Z2-",
|
||||
"Right", "Left", "Down", "Up",
|
||||
"Right 2", "Left 2", "Down 2", "Up 2",
|
||||
"Right 3", "Left 3", "Down 3", "Up 3",
|
||||
"Right 4", "Left 4", "Down 4", "Up 4",
|
||||
"Trigger", "Thumb", "Thumb2", "Top", "Top2",
|
||||
"Pinkie", "Base", "Base2", "Base3", "Base4",
|
||||
"Base5", "Base6", "Dead"
|
||||
};
|
||||
|
||||
for(int i = 0; i < 20; i++) {
|
||||
for(int j = 0; j < (int)buttonNames.size(); j++) {
|
||||
_keyDefinitions.push_back({ "", (uint32_t)(0x10000 + i * 0x100 + j), "Pad" + std::to_string(i + 1) + " " + buttonNames[j], "" });
|
||||
}
|
||||
}
|
||||
|
||||
for(KeyDefinition &keyDef : _keyDefinitions) {
|
||||
_keyNames[keyDef.keyCode] = keyDef.description;
|
||||
_keyCodes[keyDef.description] = keyDef.keyCode;
|
||||
}
|
||||
|
||||
CheckForGamepads(true);
|
||||
|
||||
_disableAllKeys = false;
|
||||
_stopUpdateDeviceThread = false;
|
||||
StartUpdateDeviceThread();
|
||||
}
|
||||
|
||||
LinuxKeyManager::~LinuxKeyManager()
|
||||
{
|
||||
_stopUpdateDeviceThread = true;
|
||||
_stopSignal.Signal();
|
||||
_updateDeviceThread.join();
|
||||
}
|
||||
|
||||
void LinuxKeyManager::RefreshState()
|
||||
{
|
||||
//TODO: NOT IMPLEMENTED YET;
|
||||
//Only needed to detect poll controller input
|
||||
}
|
||||
|
||||
bool LinuxKeyManager::IsKeyPressed(uint32_t key)
|
||||
{
|
||||
if(_disableAllKeys) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(key >= 0x10000) {
|
||||
uint8_t gamepadPort = (key - 0x10000) / 0x100;
|
||||
uint8_t gamepadButton = (key - 0x10000) % 0x100;
|
||||
if(_controllers.size() > gamepadPort) {
|
||||
return _controllers[gamepadPort]->IsButtonPressed(gamepadButton);
|
||||
}
|
||||
} else if(key < 0x200) {
|
||||
return _keyState[key & 0xFF] != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LinuxKeyManager::IsMouseButtonPressed(MouseButton button)
|
||||
{
|
||||
switch(button) {
|
||||
case MouseButton::LeftButton: return _mouseState[0];
|
||||
case MouseButton::RightButton: return _mouseState[1];
|
||||
case MouseButton::MiddleButton: return _mouseState[2];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<uint32_t> LinuxKeyManager::GetPressedKeys()
|
||||
{
|
||||
vector<uint32_t> pressedKeys;
|
||||
for(size_t i = 0; i < _controllers.size(); i++) {
|
||||
for(int j = 0; j <= 54; j++) {
|
||||
if(_controllers[i]->IsButtonPressed(j)) {
|
||||
pressedKeys.push_back(0x10000 + i * 0x100 + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 0x200; i++) {
|
||||
if(_keyState[i]) {
|
||||
pressedKeys.push_back(i);
|
||||
}
|
||||
}
|
||||
return pressedKeys;
|
||||
}
|
||||
|
||||
string LinuxKeyManager::GetKeyName(uint32_t key)
|
||||
{
|
||||
auto keyDef = _keyNames.find(key);
|
||||
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::CheckForGamepads(bool logInformation)
|
||||
{
|
||||
vector<int> connectedIDs;
|
||||
for(int i = _controllers.size() - 1; i >= 0; i--) {
|
||||
if(!_controllers[i]->IsDisconnected()) {
|
||||
connectedIDs.push_back(_controllers[i]->GetDeviceID());
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> files = FolderUtilities::GetFilesInFolder("/dev/input/", {}, false);
|
||||
for(size_t i = 0; i < files.size(); i++) {
|
||||
string filename = FolderUtilities::GetFilename(files[i], false);
|
||||
if(filename.find("event", 0) == 0) {
|
||||
int deviceId = 0;
|
||||
try {
|
||||
deviceId = std::stoi(filename.substr(5));
|
||||
} catch(std::exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(std::find(connectedIDs.begin(), connectedIDs.end(), deviceId) == connectedIDs.end()) {
|
||||
std::shared_ptr<LinuxGameController> controller = LinuxGameController::GetController(_console, deviceId, logInformation);
|
||||
if(controller) {
|
||||
_controllers.push_back(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxKeyManager::StartUpdateDeviceThread()
|
||||
{
|
||||
_updateDeviceThread = std::thread([=]() {
|
||||
while(!_stopUpdateDeviceThread) {
|
||||
//Check for newly plugged in controllers every 5 secs
|
||||
vector<shared_ptr<LinuxGameController>> controllersToAdd;
|
||||
vector<int> indexesToRemove;
|
||||
for(int i = _controllers.size() - 1; i >= 0; i--) {
|
||||
if(_controllers[i]->IsDisconnected()) {
|
||||
indexesToRemove.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
CheckForGamepads(false);
|
||||
|
||||
if(!indexesToRemove.empty() || !controllersToAdd.empty()) {
|
||||
_console->Pause();
|
||||
for(int index : indexesToRemove) {
|
||||
_controllers.erase(_controllers.begin()+index);
|
||||
}
|
||||
for(std::shared_ptr<LinuxGameController> controller : controllersToAdd) {
|
||||
_controllers.push_back(controller);
|
||||
}
|
||||
_console->Resume();
|
||||
}
|
||||
|
||||
_stopSignal.Wait(5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LinuxKeyManager::SetKeyState(uint16_t scanCode, bool state)
|
||||
{
|
||||
if(scanCode > 0x1FF) {
|
||||
_mouseState[scanCode & 0x03] = state;
|
||||
} else {
|
||||
scanCode &= 0xFF;
|
||||
if(scanCode == 105) {
|
||||
//Left + Right Ctrl
|
||||
scanCode = 37;
|
||||
} else if(scanCode == 62) {
|
||||
//Left + Right Shift
|
||||
scanCode = 50;
|
||||
} else if(scanCode == 108) {
|
||||
//Left + Right Alt
|
||||
scanCode = 64;
|
||||
}
|
||||
_keyState[scanCode & 0xFF] = state;
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxKeyManager::ResetKeyState()
|
||||
{
|
||||
memset(_mouseState, 0, sizeof(_mouseState));
|
||||
memset(_keyState, 0, sizeof(_keyState));
|
||||
}
|
||||
|
||||
void LinuxKeyManager::SetDisabled(bool disabled)
|
||||
{
|
||||
_disableAllKeys = disabled;
|
||||
}
|
52
Linux/LinuxKeyManager.h
Normal file
52
Linux/LinuxKeyManager.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include "../Core/IKeyManager.h"
|
||||
#include "../Utilities/AutoResetEvent.h"
|
||||
|
||||
class LinuxGameController;
|
||||
class Console;
|
||||
|
||||
struct KeyDefinition {
|
||||
string name;
|
||||
uint32_t keyCode;
|
||||
string description;
|
||||
string extDescription;
|
||||
};
|
||||
|
||||
class LinuxKeyManager : public IKeyManager
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
std::vector<shared_ptr<LinuxGameController>> _controllers;
|
||||
bool _keyState[0x200];
|
||||
bool _mouseState[0x03];
|
||||
std::unordered_map<uint32_t, string> _keyNames;
|
||||
std::unordered_map<string, uint32_t> _keyCodes;
|
||||
|
||||
std::thread _updateDeviceThread;
|
||||
atomic<bool> _stopUpdateDeviceThread;
|
||||
AutoResetEvent _stopSignal;
|
||||
bool _disableAllKeys;
|
||||
|
||||
void StartUpdateDeviceThread();
|
||||
void CheckForGamepads(bool logInformation);
|
||||
|
||||
public:
|
||||
LinuxKeyManager(shared_ptr<Console> console);
|
||||
virtual ~LinuxKeyManager();
|
||||
|
||||
void RefreshState();
|
||||
bool IsKeyPressed(uint32_t key);
|
||||
bool IsMouseButtonPressed(MouseButton button);
|
||||
std::vector<uint32_t> GetPressedKeys();
|
||||
string GetKeyName(uint32_t key);
|
||||
uint32_t GetKeyCode(string keyName);
|
||||
|
||||
void UpdateDevices();
|
||||
void SetKeyState(uint16_t scanCode, bool state);
|
||||
void ResetKeyState();
|
||||
|
||||
void SetDisabled(bool disabled);
|
||||
};
|
219
Linux/SdlRenderer.cpp
Normal file
219
Linux/SdlRenderer.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include "SdlRenderer.h"
|
||||
#include "../Core/Console.h"
|
||||
#include "../Core/Debugger.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
#include "../Core/VideoDecoder.h"
|
||||
#include "../Core/EmuSettings.h"
|
||||
#include "../Core/MessageManager.h"
|
||||
|
||||
SimpleLock SdlRenderer::_reinitLock;
|
||||
SimpleLock SdlRenderer::_frameLock;
|
||||
|
||||
SdlRenderer::SdlRenderer(shared_ptr<Console> console, void* windowHandle, bool registerAsMessageManager) : BaseRenderer(console, registerAsMessageManager), _windowHandle(windowHandle)
|
||||
{
|
||||
_frameBuffer = nullptr;
|
||||
SetScreenSize(512,480);
|
||||
}
|
||||
|
||||
SdlRenderer::~SdlRenderer()
|
||||
{
|
||||
shared_ptr<VideoRenderer> videoRenderer = _console->GetVideoRenderer();
|
||||
if(videoRenderer) {
|
||||
videoRenderer->UnregisterRenderingDevice(this);
|
||||
}
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void SdlRenderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
|
||||
{
|
||||
//TODO: Implement exclusive fullscreen for Linux
|
||||
}
|
||||
|
||||
bool SdlRenderer::Init()
|
||||
{
|
||||
auto log = [](const char* msg) {
|
||||
MessageManager::Log(msg);
|
||||
MessageManager::Log(SDL_GetError());
|
||||
};
|
||||
|
||||
if(SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
log("[SDL] Failed to initialize video subsystem.");
|
||||
return false;
|
||||
};
|
||||
|
||||
_sdlWindow = SDL_CreateWindowFrom(_windowHandle);
|
||||
if(!_sdlWindow) {
|
||||
log("[SDL] Failed to create window from handle.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Hack to make this work properly - otherwise SDL_CreateRenderer never returns
|
||||
_sdlWindow->flags |= SDL_WINDOW_OPENGL;
|
||||
|
||||
if(SDL_GL_LoadLibrary(NULL) != 0) {
|
||||
log("[SDL] Failed to initialize OpenGL, attempting to continue with initialization.");
|
||||
}
|
||||
|
||||
uint32_t baseFlags = _vsyncEnabled ? SDL_RENDERER_PRESENTVSYNC : 0;
|
||||
|
||||
_sdlRenderer = SDL_CreateRenderer(_sdlWindow, -1, baseFlags | SDL_RENDERER_ACCELERATED);
|
||||
if(!_sdlRenderer) {
|
||||
log("[SDL] Failed to create accelerated renderer.");
|
||||
|
||||
MessageManager::Log("[SDL] Attempting to create software renderer...");
|
||||
_sdlRenderer = SDL_CreateRenderer(_sdlWindow, -1, baseFlags | SDL_RENDERER_SOFTWARE);
|
||||
if(!_sdlRenderer) {
|
||||
log("[SDL] Failed to create software renderer.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_sdlTexture = SDL_CreateTexture(_sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, _nesFrameWidth, _nesFrameHeight);
|
||||
if(!_sdlTexture) {
|
||||
log("[SDL] Failed to create texture.");
|
||||
return false;
|
||||
}
|
||||
|
||||
_spriteFont.reset(new SpriteFont(_sdlRenderer, "Resources/Font.24.spritefont"));
|
||||
_largeFont.reset(new SpriteFont(_sdlRenderer, "Resources/Font.64.spritefont"));
|
||||
|
||||
SDL_SetWindowSize(_sdlWindow, _screenWidth, _screenHeight);
|
||||
|
||||
_frameBuffer = new uint32_t[_nesFrameHeight*_nesFrameWidth];
|
||||
memset(_frameBuffer, 0, _nesFrameHeight*_nesFrameWidth*_bytesPerPixel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Cleanup();
|
||||
if(Init()) {
|
||||
_console->GetVideoRenderer()->RegisterRenderingDevice(this);
|
||||
} else {
|
||||
Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void SdlRenderer::SetScreenSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
ScreenSize screenSize = _console->GetVideoDecoder()->GetScreenSize(false);
|
||||
|
||||
VideoConfig cfg = _console->GetSettings()->GetVideoConfig();
|
||||
if(_screenHeight != (uint32_t)screenSize.Height || _screenWidth != (uint32_t)screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _useBilinearInterpolation != cfg.UseBilinearInterpolation || _vsyncEnabled != cfg.VerticalSync) {
|
||||
_reinitLock.Acquire();
|
||||
|
||||
_vsyncEnabled = cfg.VerticalSync;
|
||||
_useBilinearInterpolation = cfg.UseBilinearInterpolation;
|
||||
|
||||
_nesFrameHeight = height;
|
||||
_nesFrameWidth = width;
|
||||
_newFrameBufferSize = width*height;
|
||||
|
||||
_screenHeight = screenSize.Height;
|
||||
_screenWidth = screenSize.Width;
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, _useBilinearInterpolation ? "1" : "0");
|
||||
_screenBufferSize = _screenHeight*_screenWidth;
|
||||
|
||||
Reset();
|
||||
_reinitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
void SdlRenderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height)
|
||||
{
|
||||
SetScreenSize(width, height);
|
||||
_frameLock.Acquire();
|
||||
memcpy(_frameBuffer, frameBuffer, width*height*_bytesPerPixel);
|
||||
_frameChanged = true;
|
||||
_frameLock.Release();
|
||||
}
|
||||
|
||||
void SdlRenderer::Render()
|
||||
{
|
||||
if(!_sdlRenderer || !_sdlTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool paused = _console->IsPaused() && _console->IsRunning();
|
||||
|
||||
if(_noUpdateCount > 10 || _frameChanged || paused || IsMessageShown()) {
|
||||
auto lock = _reinitLock.AcquireSafe();
|
||||
|
||||
SDL_RenderClear(_sdlRenderer);
|
||||
|
||||
uint8_t *textureBuffer;
|
||||
int rowPitch;
|
||||
SDL_LockTexture(_sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch);
|
||||
{
|
||||
auto frameLock = _frameLock.AcquireSafe();
|
||||
uint32_t* ppuFrameBuffer = _frameBuffer;
|
||||
for(uint32_t i = 0, iMax = _nesFrameHeight; i < iMax; i++) {
|
||||
memcpy(textureBuffer, ppuFrameBuffer, _nesFrameWidth*_bytesPerPixel);
|
||||
ppuFrameBuffer += _nesFrameWidth;
|
||||
textureBuffer += rowPitch;
|
||||
}
|
||||
}
|
||||
SDL_UnlockTexture(_sdlTexture);
|
||||
|
||||
if(_frameChanged) {
|
||||
_renderedFrameCount++;
|
||||
_frameChanged = false;
|
||||
}
|
||||
|
||||
SDL_Rect source = {0, 0, (int)_nesFrameWidth, (int)_nesFrameHeight };
|
||||
SDL_Rect dest = {0, 0, (int)_screenWidth, (int)_screenHeight };
|
||||
SDL_RenderCopy(_sdlRenderer, _sdlTexture, &source, &dest);
|
||||
|
||||
if(paused) {
|
||||
DrawPauseScreen();
|
||||
} else if(_console->GetVideoDecoder()->IsRunning()) {
|
||||
DrawCounters();
|
||||
}
|
||||
|
||||
DrawToasts();
|
||||
|
||||
SDL_RenderPresent(_sdlRenderer);
|
||||
} else {
|
||||
_noUpdateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlRenderer::DrawPauseScreen()
|
||||
{
|
||||
DrawString(L"I", 15, 15, 106, 90, 205, 168);
|
||||
DrawString(L"I", 23, 15, 106, 90, 205, 168);
|
||||
}
|
||||
|
||||
void SdlRenderer::DrawString(std::wstring message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity)
|
||||
{
|
||||
const wchar_t *text = message.c_str();
|
||||
_spriteFont->DrawString(_sdlRenderer, text, x, y, r, g, b);
|
||||
}
|
||||
|
||||
float SdlRenderer::MeasureString(std::wstring text)
|
||||
{
|
||||
return _spriteFont->MeasureString(text.c_str()).x;
|
||||
}
|
||||
|
||||
bool SdlRenderer::ContainsCharacter(wchar_t character)
|
||||
{
|
||||
return _spriteFont->ContainsCharacter(character);
|
||||
}
|
73
Linux/SdlRenderer.h
Normal file
73
Linux/SdlRenderer.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include "../Core/IRenderingDevice.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
#include "../Core/BaseRenderer.h"
|
||||
#include "SpriteFont.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 Console;
|
||||
|
||||
class SdlRenderer : public IRenderingDevice, public BaseRenderer
|
||||
{
|
||||
private:
|
||||
void* _windowHandle;
|
||||
SDL_Window* _sdlWindow = nullptr;
|
||||
SDL_Renderer *_sdlRenderer = nullptr;
|
||||
SDL_Texture *_sdlTexture = nullptr;
|
||||
std::unique_ptr<SpriteFont> _spriteFont;
|
||||
std::unique_ptr<SpriteFont> _largeFont;
|
||||
|
||||
bool _useBilinearInterpolation = false;
|
||||
|
||||
static SimpleLock _frameLock;
|
||||
static SimpleLock _reinitLock;
|
||||
uint32_t* _frameBuffer;
|
||||
|
||||
const uint32_t _bytesPerPixel = 4;
|
||||
uint32_t _screenBufferSize = 0;
|
||||
|
||||
bool _frameChanged = true;
|
||||
uint32_t _noUpdateCount = 0;
|
||||
|
||||
uint32_t _nesFrameHeight = 0;
|
||||
uint32_t _nesFrameWidth = 0;
|
||||
uint32_t _newFrameBufferSize = 0;
|
||||
|
||||
bool _vsyncEnabled = false;
|
||||
|
||||
bool Init();
|
||||
void Cleanup();
|
||||
void SetScreenSize(uint32_t width, uint32_t height);
|
||||
|
||||
void DrawPauseScreen();
|
||||
|
||||
float MeasureString(std::wstring text) override;
|
||||
bool ContainsCharacter(wchar_t character) override;
|
||||
|
||||
public:
|
||||
SdlRenderer(shared_ptr<Console> console, void* windowHandle, bool registerAsMessageManager);
|
||||
virtual ~SdlRenderer();
|
||||
|
||||
void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) override;
|
||||
void Render() override;
|
||||
void Reset() override;
|
||||
|
||||
void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255) override;
|
||||
|
||||
void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override;
|
||||
};
|
195
Linux/SdlSoundManager.cpp
Normal file
195
Linux/SdlSoundManager.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "SdlSoundManager.h"
|
||||
#include "../Core/EmuSettings.h"
|
||||
#include "../Core/MessageManager.h"
|
||||
#include "../Core/SoundMixer.h"
|
||||
#include "../Core/Console.h"
|
||||
|
||||
SdlSoundManager::SdlSoundManager(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
|
||||
if(InitializeAudio(44100, false)) {
|
||||
_console->GetSoundMixer()->RegisterAudioDevice(this);
|
||||
}
|
||||
}
|
||||
|
||||
SdlSoundManager::~SdlSoundManager()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void SdlSoundManager::FillAudioBuffer(void *userData, uint8_t *stream, int len)
|
||||
{
|
||||
SdlSoundManager* soundManager = (SdlSoundManager*)userData;
|
||||
|
||||
soundManager->ReadFromBuffer(stream, len);
|
||||
}
|
||||
|
||||
void SdlSoundManager::Release()
|
||||
{
|
||||
if(_audioDeviceID != 0) {
|
||||
Stop();
|
||||
SDL_CloseAudioDevice(_audioDeviceID);
|
||||
}
|
||||
|
||||
if(_buffer) {
|
||||
delete[] _buffer;
|
||||
_buffer = nullptr;
|
||||
_bufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlSoundManager::InitializeAudio(uint32_t sampleRate, bool isStereo)
|
||||
{
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
MessageManager::Log("[Audio] Failed to initialize audio subsystem");
|
||||
return false;
|
||||
}
|
||||
|
||||
int isCapture = 0;
|
||||
|
||||
_sampleRate = sampleRate;
|
||||
_isStereo = isStereo;
|
||||
_previousLatency = _console->GetSettings()->GetAudioConfig().AudioLatency;
|
||||
|
||||
int bytesPerSample = 2 * (isStereo ? 2 : 1);
|
||||
int32_t requestedByteLatency = (int32_t)((float)(sampleRate * _previousLatency) / 1000.0f * bytesPerSample);
|
||||
_bufferSize = (int32_t)std::ceil((double)requestedByteLatency * 2 / 0x10000) * 0x10000;
|
||||
_buffer = new uint8_t[_bufferSize];
|
||||
memset(_buffer, 0, _bufferSize);
|
||||
|
||||
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);
|
||||
if(_audioDeviceID == 0 && !_deviceName.empty()) {
|
||||
MessageManager::Log("[Audio] Failed opening audio device '" + _deviceName + "', will retry with default device.");
|
||||
_audioDeviceID = SDL_OpenAudioDevice(nullptr, 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 < _bufferSize) {
|
||||
memcpy(output, _buffer+_readPosition, len);
|
||||
_readPosition += len;
|
||||
} else {
|
||||
int remainingBytes = (_bufferSize - _readPosition);
|
||||
memcpy(output, _buffer+_readPosition, remainingBytes);
|
||||
memcpy(output+remainingBytes, _buffer, len - remainingBytes);
|
||||
_readPosition = len - remainingBytes;
|
||||
}
|
||||
|
||||
if(_readPosition >= _writePosition && _readPosition - _writePosition < _bufferSize / 2) {
|
||||
_bufferUnderrunEventCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::WriteToBuffer(uint8_t* input, uint32_t len)
|
||||
{
|
||||
if(_writePosition + len < _bufferSize) {
|
||||
memcpy(_buffer+_writePosition, input, len);
|
||||
_writePosition += len;
|
||||
} else {
|
||||
int remainingBytes = _bufferSize - _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 = 2 * (isStereo ? 2 : 1);
|
||||
uint32_t latency = _console->GetSettings()->GetAudioConfig().AudioLatency;
|
||||
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || _previousLatency != latency) {
|
||||
Release();
|
||||
InitializeAudio(sampleRate, isStereo);
|
||||
}
|
||||
|
||||
WriteToBuffer((uint8_t*)soundBuffer, sampleCount * bytesPerSample);
|
||||
|
||||
int32_t byteLatency = (int32_t)((float)(sampleRate * latency) / 1000.0f * bytesPerSample);
|
||||
int32_t playWriteByteLatency = _writePosition - _readPosition;
|
||||
if(playWriteByteLatency < 0) {
|
||||
playWriteByteLatency = _bufferSize - _readPosition + _writePosition;
|
||||
}
|
||||
|
||||
if(playWriteByteLatency > byteLatency) {
|
||||
//Start playing
|
||||
SDL_PauseAudioDevice(_audioDeviceID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSoundManager::Pause()
|
||||
{
|
||||
SDL_PauseAudioDevice(_audioDeviceID, 1);
|
||||
}
|
||||
|
||||
void SdlSoundManager::Stop()
|
||||
{
|
||||
Pause();
|
||||
|
||||
_readPosition = 0;
|
||||
_writePosition = 0;
|
||||
ResetStats();
|
||||
}
|
||||
|
||||
void SdlSoundManager::ProcessEndOfFrame()
|
||||
{
|
||||
ProcessLatency(_readPosition, _writePosition);
|
||||
|
||||
uint32_t emulationSpeed = _console->GetSettings()->GetEmulationSpeed();
|
||||
if(_averageLatency > 0 && emulationSpeed <= 100 && emulationSpeed > 0 && std::abs(_averageLatency - _console->GetSettings()->GetAudioConfig().AudioLatency) > 50) {
|
||||
//Latency is way off (over 50ms gap), stop audio & start again
|
||||
Stop();
|
||||
}
|
||||
}
|
43
Linux/SdlSoundManager.h
Normal file
43
Linux/SdlSoundManager.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include <SDL2/SDL.h>
|
||||
#include "../Core/BaseSoundManager.h"
|
||||
|
||||
class Console;
|
||||
|
||||
class SdlSoundManager : public BaseSoundManager
|
||||
{
|
||||
public:
|
||||
SdlSoundManager(shared_ptr<Console> console);
|
||||
~SdlSoundManager();
|
||||
|
||||
void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo);
|
||||
void Pause();
|
||||
void Stop();
|
||||
|
||||
void ProcessEndOfFrame();
|
||||
|
||||
string GetAvailableDevices();
|
||||
void SetAudioDevice(string deviceName);
|
||||
|
||||
private:
|
||||
vector<string> GetAvailableDeviceInfo();
|
||||
bool InitializeAudio(uint32_t sampleRate, bool isStereo);
|
||||
void Release();
|
||||
|
||||
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:
|
||||
shared_ptr<Console> _console;
|
||||
SDL_AudioDeviceID _audioDeviceID;
|
||||
string _deviceName;
|
||||
bool _needReset = false;
|
||||
|
||||
uint16_t _previousLatency = 0;
|
||||
|
||||
uint8_t* _buffer = nullptr;
|
||||
uint32_t _writePosition = 0;
|
||||
uint32_t _readPosition = 0;
|
||||
};
|
280
Linux/SpriteFont.cpp
Normal file
280
Linux/SpriteFont.cpp
Normal file
|
@ -0,0 +1,280 @@
|
|||
//--------------------------------------------------------------------------------------
|
||||
// This a heavily modified version of SpriteFont.cpp from DirectX Toolkit (MIT license)
|
||||
// It strips down a lot of options not needed for Mesen and implements the minimum
|
||||
// required to use .spritefont files in SDL.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: SpriteFont.cpp
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248929
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <climits>
|
||||
|
||||
#include "SpriteFont.h"
|
||||
|
||||
// Internal SpriteFont implementation class.
|
||||
class SpriteFont::Impl
|
||||
{
|
||||
public:
|
||||
Impl(SDL_Renderer* renderer, BinaryReader* reader);
|
||||
virtual ~Impl();
|
||||
|
||||
Glyph const* FindGlyph(wchar_t character) const;
|
||||
|
||||
void SetDefaultCharacter(wchar_t character);
|
||||
|
||||
template<typename TAction>
|
||||
void ForEachGlyph(wchar_t const* text, TAction action) const;
|
||||
|
||||
|
||||
// Fields.
|
||||
std::vector<uint8_t> textureData;
|
||||
SDL_Texture* texture;
|
||||
std::vector<Glyph> glyphs;
|
||||
Glyph const* defaultGlyph;
|
||||
float lineSpacing;
|
||||
};
|
||||
|
||||
|
||||
// Constants.
|
||||
const XMFLOAT2 SpriteFont::Float2Zero(0, 0);
|
||||
|
||||
static const char spriteFontMagic[] = "DXTKfont";
|
||||
|
||||
|
||||
// Comparison operators make our sorted glyph vector work with std::binary_search and lower_bound.
|
||||
static inline bool operator< (wchar_t left, SpriteFont::Glyph const& right)
|
||||
{
|
||||
return (uint32_t)left < right.Character;
|
||||
}
|
||||
|
||||
static inline bool operator< (SpriteFont::Glyph const& left, wchar_t right)
|
||||
{
|
||||
return left.Character < (uint32_t)right;
|
||||
}
|
||||
|
||||
// Reads a SpriteFont from the binary format created by the MakeSpriteFont utility.
|
||||
SpriteFont::Impl::Impl(SDL_Renderer* renderer, BinaryReader* reader) :
|
||||
defaultGlyph(nullptr)
|
||||
{
|
||||
// Validate the header.
|
||||
for (char const* magic = spriteFontMagic; *magic; magic++)
|
||||
{
|
||||
if (reader->Read<uint8_t>() != *magic)
|
||||
{
|
||||
throw std::runtime_error("Not a MakeSpriteFont output binary");
|
||||
}
|
||||
}
|
||||
|
||||
// Read the glyph data.
|
||||
auto glyphCount = reader->Read<uint32_t>();
|
||||
auto glyphData = reader->ReadArray<Glyph>(glyphCount);
|
||||
|
||||
glyphs.assign(glyphData, glyphData + glyphCount);
|
||||
|
||||
// Read font properties.
|
||||
lineSpacing = reader->Read<float>();
|
||||
|
||||
SetDefaultCharacter((wchar_t)reader->Read<uint32_t>());
|
||||
|
||||
// Read the texture data.
|
||||
auto textureWidth = reader->Read<uint32_t>();
|
||||
auto textureHeight = reader->Read<uint32_t>();
|
||||
reader->Read<uint32_t>(); //DXGI_FORMAT, ignored - assume 32-bit RBGA
|
||||
auto textureStride = reader->Read<uint32_t>();
|
||||
auto textureRows = reader->Read<uint32_t>();
|
||||
auto pixelData = reader->ReadArray<uint8_t>(textureStride * textureRows);
|
||||
|
||||
textureData.insert(textureData.end(), pixelData, pixelData+textureStride*textureHeight);
|
||||
|
||||
SDL_Surface* surf = SDL_CreateRGBSurfaceFrom((void*)textureData.data(), textureWidth, textureHeight, 32, textureStride, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
||||
texture = SDL_CreateTextureFromSurface(renderer, surf);
|
||||
SDL_FreeSurface(surf);
|
||||
}
|
||||
|
||||
SpriteFont::Impl::~Impl()
|
||||
{
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
|
||||
// Looks up the requested glyph, falling back to the default character if it is not in the font.
|
||||
SpriteFont::Glyph const* SpriteFont::Impl::FindGlyph(wchar_t character) const
|
||||
{
|
||||
auto glyph = std::lower_bound(glyphs.begin(), glyphs.end(), character);
|
||||
|
||||
if (glyph != glyphs.end() && glyph->Character == (uint32_t)character)
|
||||
{
|
||||
return &*glyph;
|
||||
}
|
||||
|
||||
if (defaultGlyph)
|
||||
{
|
||||
return defaultGlyph;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Character not in font");
|
||||
}
|
||||
|
||||
|
||||
// Sets the missing-character fallback glyph.
|
||||
void SpriteFont::Impl::SetDefaultCharacter(wchar_t character)
|
||||
{
|
||||
defaultGlyph = nullptr;
|
||||
|
||||
if (character)
|
||||
{
|
||||
defaultGlyph = FindGlyph(character);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The core glyph layout algorithm, shared between DrawString and MeasureString.
|
||||
template<typename TAction>
|
||||
void SpriteFont::Impl::ForEachGlyph(wchar_t const* text, TAction action) const
|
||||
{
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
for (; *text; text++)
|
||||
{
|
||||
wchar_t character = *text;
|
||||
|
||||
switch (character)
|
||||
{
|
||||
case '\r':
|
||||
// Skip carriage returns.
|
||||
continue;
|
||||
|
||||
case '\n':
|
||||
// New line.
|
||||
x = 0;
|
||||
y += lineSpacing;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Output this character.
|
||||
auto glyph = FindGlyph(character);
|
||||
|
||||
x += glyph->XOffset;
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
|
||||
float advance = glyph->Subrect.right - glyph->Subrect.left + glyph->XAdvance;
|
||||
|
||||
if(!std::iswspace(character) || (glyph->Subrect.right - glyph->Subrect.left) > 1 || (glyph->Subrect.bottom - glyph->Subrect.top ) > 1) {
|
||||
action(glyph, x, y, advance);
|
||||
}
|
||||
|
||||
x += advance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Construct from a binary file created by the MakeSpriteFont utility.
|
||||
SpriteFont::SpriteFont(SDL_Renderer* renderer, string fileName)
|
||||
{
|
||||
BinaryReader reader(fileName);
|
||||
|
||||
pImpl = std::make_unique<Impl>(renderer, &reader);
|
||||
}
|
||||
|
||||
// Move constructor.
|
||||
SpriteFont::SpriteFont(SpriteFont&& moveFrom)
|
||||
: pImpl(std::move(moveFrom.pImpl))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Move assignment.
|
||||
SpriteFont& SpriteFont::operator= (SpriteFont&& moveFrom)
|
||||
{
|
||||
pImpl = std::move(moveFrom.pImpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Public destructor.
|
||||
SpriteFont::~SpriteFont()
|
||||
{
|
||||
}
|
||||
|
||||
void SpriteFont::DrawString(SDL_Renderer *renderer, wchar_t const* text, int x, int y, uint8_t r, uint8_t g, uint8_t b) const
|
||||
{
|
||||
SDL_SetTextureColorMod(pImpl->texture, r, g, b);
|
||||
pImpl->ForEachGlyph(text, [&](Glyph const* glyph, float offsetX, float offsetY, float advance)
|
||||
{
|
||||
int width = (int)(glyph->Subrect.right - glyph->Subrect.left);
|
||||
int height = (int)(glyph->Subrect.bottom - glyph->Subrect.top);
|
||||
|
||||
SDL_Rect source = {(int)glyph->Subrect.left, (int)glyph->Subrect.top, width, height};
|
||||
SDL_Rect dest = {x + (int)offsetX, y + (int)(offsetY + glyph->YOffset), width, height};
|
||||
SDL_RenderCopy(renderer, pImpl->texture, &source, &dest);
|
||||
});
|
||||
}
|
||||
|
||||
XMFLOAT2 SpriteFont::MeasureString(wchar_t const* text) const
|
||||
{
|
||||
XMFLOAT2 result;
|
||||
|
||||
pImpl->ForEachGlyph(text, [&](Glyph const* glyph, float x, float y, float advance)
|
||||
{
|
||||
float w = (float)(glyph->Subrect.right - glyph->Subrect.left);
|
||||
float h = (float)(glyph->Subrect.bottom - glyph->Subrect.top) + glyph->YOffset;
|
||||
|
||||
h = std::max(h, pImpl->lineSpacing);
|
||||
|
||||
result.x = std::max(result.x, x + w);
|
||||
result.y = std::max(result.y, y + h);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Spacing properties
|
||||
float SpriteFont::GetLineSpacing() const
|
||||
{
|
||||
return pImpl->lineSpacing;
|
||||
}
|
||||
|
||||
void SpriteFont::SetLineSpacing(float spacing)
|
||||
{
|
||||
pImpl->lineSpacing = spacing;
|
||||
}
|
||||
|
||||
// Font properties
|
||||
wchar_t SpriteFont::GetDefaultCharacter() const
|
||||
{
|
||||
return pImpl->defaultGlyph ? (wchar_t)pImpl->defaultGlyph->Character : 0;
|
||||
}
|
||||
|
||||
void SpriteFont::SetDefaultCharacter(wchar_t character)
|
||||
{
|
||||
pImpl->SetDefaultCharacter(character);
|
||||
}
|
||||
|
||||
bool SpriteFont::ContainsCharacter(wchar_t character) const
|
||||
{
|
||||
return std::binary_search(pImpl->glyphs.begin(), pImpl->glyphs.end(), character);
|
||||
}
|
||||
|
||||
// Custom layout/rendering
|
||||
SpriteFont::Glyph const* SpriteFont::FindGlyph(wchar_t character) const
|
||||
{
|
||||
return pImpl->FindGlyph(character);
|
||||
}
|
172
Linux/SpriteFont.h
Normal file
172
Linux/SpriteFont.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
//--------------------------------------------------------------------------------------
|
||||
// This a heavily modified version of SpriteFont.h from DirectX Toolkit (MIT)
|
||||
// It strips down a lot of options not needed for Mesen and implements the minimum
|
||||
// required to use .spritefont files in SDL.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: SpriteFont.h
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248929
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
struct RECT
|
||||
{
|
||||
uint32_t left;
|
||||
uint32_t top;
|
||||
uint32_t right;
|
||||
uint32_t bottom;
|
||||
};
|
||||
|
||||
struct XMFLOAT2
|
||||
{
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
|
||||
XMFLOAT2() {}
|
||||
XMFLOAT2(float _x, float _y) : x(_x), y(_y) {}
|
||||
explicit XMFLOAT2(const float *pArray) : x(pArray[0]), y(pArray[1]) {}
|
||||
|
||||
XMFLOAT2& operator= (const XMFLOAT2& Float2) { x = Float2.x; y = Float2.y; return *this; }
|
||||
};
|
||||
|
||||
class SpriteFont
|
||||
{
|
||||
public:
|
||||
struct Glyph;
|
||||
|
||||
SpriteFont(SDL_Renderer* renderer, string fileName);
|
||||
|
||||
SpriteFont(SpriteFont&& moveFrom);
|
||||
SpriteFont& operator= (SpriteFont&& moveFrom);
|
||||
|
||||
SpriteFont(SpriteFont const&) = delete;
|
||||
SpriteFont& operator= (SpriteFont const&) = delete;
|
||||
|
||||
virtual ~SpriteFont();
|
||||
|
||||
void DrawString(SDL_Renderer *renderer, wchar_t const* text, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255) const;
|
||||
|
||||
XMFLOAT2 MeasureString(wchar_t const* text) const;
|
||||
|
||||
// Spacing properties
|
||||
float GetLineSpacing() const;
|
||||
void SetLineSpacing(float spacing);
|
||||
|
||||
// Font properties
|
||||
wchar_t GetDefaultCharacter() const;
|
||||
void SetDefaultCharacter(wchar_t character);
|
||||
|
||||
bool ContainsCharacter(wchar_t character) const;
|
||||
|
||||
// Custom layout/rendering
|
||||
Glyph const* FindGlyph(wchar_t character) const;
|
||||
|
||||
// Describes a single character glyph.
|
||||
struct Glyph
|
||||
{
|
||||
uint32_t Character;
|
||||
RECT Subrect;
|
||||
float XOffset;
|
||||
float YOffset;
|
||||
float XAdvance;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
// Private implementation.
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
|
||||
static const XMFLOAT2 Float2Zero;
|
||||
};
|
||||
|
||||
class BinaryReader
|
||||
{
|
||||
public:
|
||||
BinaryReader(string fileName) : mPos(nullptr), mEnd(nullptr)
|
||||
{
|
||||
size_t dataSize;
|
||||
|
||||
bool result = ReadEntireFile(fileName, mOwnedData, &dataSize);
|
||||
if(!result) {
|
||||
throw std::runtime_error( "BinaryReader" );
|
||||
}
|
||||
|
||||
mPos = mOwnedData.get();
|
||||
mEnd = mOwnedData.get() + dataSize;
|
||||
}
|
||||
|
||||
// Reads a single value.
|
||||
template<typename T> T const& Read()
|
||||
{
|
||||
return *ReadArray<T>(1);
|
||||
}
|
||||
|
||||
|
||||
// Reads an array of values.
|
||||
template<typename T> T const* ReadArray(size_t elementCount)
|
||||
{
|
||||
static_assert(std::is_pod<T>::value, "Can only read plain-old-data types");
|
||||
|
||||
uint8_t const* newPos = mPos + sizeof(T) * elementCount;
|
||||
|
||||
if (newPos < mPos)
|
||||
throw std::overflow_error("ReadArray");
|
||||
|
||||
if (newPos > mEnd)
|
||||
throw std::runtime_error("End of file");
|
||||
|
||||
auto result = reinterpret_cast<T const*>(mPos);
|
||||
|
||||
mPos = newPos;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Lower level helper reads directly from the filesystem into memory.
|
||||
static bool ReadEntireFile(string fileName, std::unique_ptr<uint8_t[]>& data, size_t* dataSize)
|
||||
{
|
||||
std::ifstream file(fileName, std::ios::binary | std::ios::in);
|
||||
file.seekg(0, std::ios::end);
|
||||
size_t filesize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Create enough space for the file data.
|
||||
data.reset(new uint8_t[filesize]);
|
||||
|
||||
// Read the data in.
|
||||
file.read((char*)data.get(), filesize);
|
||||
|
||||
*dataSize = filesize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// The data currently being read.
|
||||
uint8_t const* mPos;
|
||||
uint8_t const* mEnd;
|
||||
|
||||
std::unique_ptr<uint8_t[]> mOwnedData;
|
||||
};
|
1425
Linux/libevdev/event-names.h
Normal file
1425
Linux/libevdev/event-names.h
Normal file
File diff suppressed because it is too large
Load diff
341
Linux/libevdev/libevdev-int.h
Normal file
341
Linux/libevdev/libevdev-int.h
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright © 2013 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBEVDEV_INT_H
|
||||
#define LIBEVDEV_INT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "libevdev.h"
|
||||
#include "libevdev-util.h"
|
||||
|
||||
#define MAX_NAME 256
|
||||
#define ABS_MT_MIN ABS_MT_SLOT
|
||||
#define ABS_MT_MAX ABS_MT_TOOL_Y
|
||||
#define ABS_MT_CNT (ABS_MT_MAX - ABS_MT_MIN + 1)
|
||||
#define LIBEVDEV_EXPORT __attribute__((visibility("default")))
|
||||
#define ALIAS(_to) __attribute__((alias(#_to)))
|
||||
|
||||
/**
|
||||
* Sync state machine:
|
||||
* default state: SYNC_NONE
|
||||
*
|
||||
* SYNC_NONE → SYN_DROPPED or forced sync → SYNC_NEEDED
|
||||
* SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC) → SYNC_IN_PROGRESS
|
||||
* SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE
|
||||
* SYNC_IN_PROGRESS → libevdev_next_event(LIBEVDEV_READ_FLAG_SYNC_NONE) → SYNC_NONE
|
||||
* SYNC_IN_PROGRESS → no sync events left → SYNC_NONE
|
||||
*
|
||||
*/
|
||||
enum SyncState {
|
||||
SYNC_NONE,
|
||||
SYNC_NEEDED,
|
||||
SYNC_IN_PROGRESS,
|
||||
};
|
||||
|
||||
struct mt_sync_state {
|
||||
int code;
|
||||
int val[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal only: log data used to send messages to the respective log
|
||||
* handler. We re-use the same struct for a global and inside
|
||||
* struct libevdev.
|
||||
* For the global, device_handler is NULL, for per-device instance
|
||||
* global_handler is NULL.
|
||||
*/
|
||||
struct logdata {
|
||||
enum libevdev_log_priority priority; /** minimum logging priority */
|
||||
libevdev_log_func_t global_handler; /** global handler function */
|
||||
libevdev_device_log_func_t device_handler; /** per-device handler function */
|
||||
void *userdata; /** user-defined data pointer */
|
||||
};
|
||||
|
||||
struct libevdev {
|
||||
int fd;
|
||||
bool initialized;
|
||||
char *name;
|
||||
char *phys;
|
||||
char *uniq;
|
||||
struct input_id ids;
|
||||
int driver_version;
|
||||
unsigned long bits[NLONGS(EV_CNT)];
|
||||
unsigned long props[NLONGS(INPUT_PROP_CNT)];
|
||||
unsigned long key_bits[NLONGS(KEY_CNT)];
|
||||
unsigned long rel_bits[NLONGS(REL_CNT)];
|
||||
unsigned long abs_bits[NLONGS(ABS_CNT)];
|
||||
unsigned long led_bits[NLONGS(LED_CNT)];
|
||||
unsigned long msc_bits[NLONGS(MSC_CNT)];
|
||||
unsigned long sw_bits[NLONGS(SW_CNT)];
|
||||
unsigned long rep_bits[NLONGS(REP_CNT)]; /* convenience, always 1 */
|
||||
unsigned long ff_bits[NLONGS(FF_CNT)];
|
||||
unsigned long snd_bits[NLONGS(SND_CNT)];
|
||||
unsigned long key_values[NLONGS(KEY_CNT)];
|
||||
unsigned long led_values[NLONGS(LED_CNT)];
|
||||
unsigned long sw_values[NLONGS(SW_CNT)];
|
||||
struct input_absinfo abs_info[ABS_CNT];
|
||||
int *mt_slot_vals; /* [num_slots * ABS_MT_CNT] */
|
||||
int num_slots; /**< valid slots in mt_slot_vals */
|
||||
int current_slot;
|
||||
int rep_values[REP_CNT];
|
||||
|
||||
enum SyncState sync_state;
|
||||
enum libevdev_grab_mode grabbed;
|
||||
|
||||
struct input_event *queue;
|
||||
size_t queue_size; /**< size of queue in elements */
|
||||
size_t queue_next; /**< next event index */
|
||||
size_t queue_nsync; /**< number of sync events */
|
||||
|
||||
struct timeval last_event_time;
|
||||
|
||||
struct {
|
||||
struct mt_sync_state *mt_state;
|
||||
size_t mt_state_sz; /* in bytes */
|
||||
unsigned long *slot_update;
|
||||
size_t slot_update_sz; /* in bytes */
|
||||
unsigned long *tracking_id_changes;
|
||||
size_t tracking_id_changes_sz; /* in bytes */
|
||||
} mt_sync;
|
||||
|
||||
struct logdata log;
|
||||
};
|
||||
|
||||
#define log_msg_cond(dev, priority, ...) \
|
||||
do { \
|
||||
if (_libevdev_log_priority(dev) >= priority) \
|
||||
_libevdev_log_msg(dev, priority, __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define log_error(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, __VA_ARGS__)
|
||||
#define log_info(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_INFO, __VA_ARGS__)
|
||||
#define log_dbg(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_bug(dev, ...) log_msg_cond(dev, LIBEVDEV_LOG_ERROR, "BUG: "__VA_ARGS__)
|
||||
|
||||
extern void
|
||||
_libevdev_log_msg(const struct libevdev *dev,
|
||||
enum libevdev_log_priority priority,
|
||||
const char *file, int line, const char *func,
|
||||
const char *format, ...) LIBEVDEV_ATTRIBUTE_PRINTF(6, 7);
|
||||
extern enum libevdev_log_priority
|
||||
_libevdev_log_priority(const struct libevdev *dev);
|
||||
|
||||
/**
|
||||
* @return a pointer to the next element in the queue, or NULL if the queue
|
||||
* is full.
|
||||
*/
|
||||
static inline struct input_event*
|
||||
queue_push(struct libevdev *dev)
|
||||
{
|
||||
if (dev->queue_next >= dev->queue_size)
|
||||
return NULL;
|
||||
|
||||
return &dev->queue[dev->queue_next++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ev to the last element in the queue, removing it from the queue.
|
||||
*
|
||||
* @return 0 on success, 1 if the queue is empty.
|
||||
*/
|
||||
static inline int
|
||||
queue_pop(struct libevdev *dev, struct input_event *ev)
|
||||
{
|
||||
if (dev->queue_next == 0)
|
||||
return 1;
|
||||
|
||||
*ev = dev->queue[--dev->queue_next];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
queue_peek(struct libevdev *dev, size_t idx, struct input_event *ev)
|
||||
{
|
||||
if (dev->queue_next == 0 || idx > dev->queue_next)
|
||||
return 1;
|
||||
*ev = dev->queue[idx];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the first n elements into ev and return the number of elements
|
||||
* shifted.
|
||||
* ev must be large enough to store n elements.
|
||||
*
|
||||
* @param ev The buffer to copy into, or NULL
|
||||
* @return The number of elements in ev.
|
||||
*/
|
||||
static inline int
|
||||
queue_shift_multiple(struct libevdev *dev, size_t n, struct input_event *ev)
|
||||
{
|
||||
size_t remaining;
|
||||
|
||||
if (dev->queue_next == 0)
|
||||
return 0;
|
||||
|
||||
remaining = dev->queue_next;
|
||||
n = min(n, remaining);
|
||||
remaining -= n;
|
||||
|
||||
if (ev)
|
||||
memcpy(ev, dev->queue, n * sizeof(*ev));
|
||||
|
||||
memmove(dev->queue, &dev->queue[n], remaining * sizeof(*dev->queue));
|
||||
|
||||
dev->queue_next = remaining;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ev to the first element in the queue, shifting everything else
|
||||
* forward by one.
|
||||
*
|
||||
* @return 0 on success, 1 if the queue is empty.
|
||||
*/
|
||||
static inline int
|
||||
queue_shift(struct libevdev *dev, struct input_event *ev)
|
||||
{
|
||||
return queue_shift_multiple(dev, 1, ev) == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
queue_alloc(struct libevdev *dev, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->queue = calloc(size, sizeof(struct input_event));
|
||||
if (!dev->queue)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->queue_size = size;
|
||||
dev->queue_next = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
queue_free(struct libevdev *dev)
|
||||
{
|
||||
free(dev->queue);
|
||||
dev->queue_size = 0;
|
||||
dev->queue_next = 0;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
queue_num_elements(struct libevdev *dev)
|
||||
{
|
||||
return dev->queue_next;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
queue_size(struct libevdev *dev)
|
||||
{
|
||||
return dev->queue_size;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
queue_num_free_elements(struct libevdev *dev)
|
||||
{
|
||||
if (dev->queue_size == 0)
|
||||
return 0;
|
||||
|
||||
return dev->queue_size - dev->queue_next;
|
||||
}
|
||||
|
||||
static inline struct input_event *
|
||||
queue_next_element(struct libevdev *dev)
|
||||
{
|
||||
if (dev->queue_next == dev->queue_size)
|
||||
return NULL;
|
||||
|
||||
return &dev->queue[dev->queue_next];
|
||||
}
|
||||
|
||||
static inline int
|
||||
queue_set_num_elements(struct libevdev *dev, size_t nelem)
|
||||
{
|
||||
if (nelem > dev->queue_size)
|
||||
return 1;
|
||||
|
||||
dev->queue_next = nelem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define max_mask(uc, lc) \
|
||||
case EV_##uc: \
|
||||
*mask = dev->lc##_bits; \
|
||||
max = libevdev_event_type_get_max(type); \
|
||||
break;
|
||||
|
||||
static inline int
|
||||
type_to_mask_const(const struct libevdev *dev, unsigned int type, const unsigned long **mask)
|
||||
{
|
||||
int max;
|
||||
|
||||
switch(type) {
|
||||
max_mask(ABS, abs);
|
||||
max_mask(REL, rel);
|
||||
max_mask(KEY, key);
|
||||
max_mask(LED, led);
|
||||
max_mask(MSC, msc);
|
||||
max_mask(SW, sw);
|
||||
max_mask(FF, ff);
|
||||
max_mask(REP, rep);
|
||||
max_mask(SND, snd);
|
||||
default:
|
||||
max = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static inline int
|
||||
type_to_mask(struct libevdev *dev, unsigned int type, unsigned long **mask)
|
||||
{
|
||||
int max;
|
||||
|
||||
switch(type) {
|
||||
max_mask(ABS, abs);
|
||||
max_mask(REL, rel);
|
||||
max_mask(KEY, key);
|
||||
max_mask(LED, led);
|
||||
max_mask(MSC, msc);
|
||||
max_mask(SW, sw);
|
||||
max_mask(FF, ff);
|
||||
max_mask(REP, rep);
|
||||
max_mask(SND, snd);
|
||||
default:
|
||||
max = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
#undef max_mask
|
||||
#endif
|
80
Linux/libevdev/libevdev-util.h
Normal file
80
Linux/libevdev/libevdev-util.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright © 2013 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LONG_BITS (sizeof(long) * 8)
|
||||
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
|
||||
#define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0])))
|
||||
#define unlikely(x) (__builtin_expect(!!(x),0))
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
#define min(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _b : _a; \
|
||||
})
|
||||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
|
||||
static inline bool
|
||||
startswith(const char *str, size_t len, const char *prefix, size_t plen)
|
||||
{
|
||||
return len >= plen && !strncmp(str, prefix, plen);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bit_is_set(const unsigned long *array, int bit)
|
||||
{
|
||||
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_bit(unsigned long *array, int bit)
|
||||
{
|
||||
array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS));
|
||||
}
|
||||
|
||||
static inline void
|
||||
clear_bit(unsigned long *array, int bit)
|
||||
{
|
||||
array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS));
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_bit_state(unsigned long *array, int bit, int state)
|
||||
{
|
||||
if (state)
|
||||
set_bit(array, bit);
|
||||
else
|
||||
clear_bit(array, bit);
|
||||
}
|
||||
|
||||
#endif
|
1722
Linux/libevdev/libevdev.c
Normal file
1722
Linux/libevdev/libevdev.c
Normal file
File diff suppressed because it is too large
Load diff
2177
Linux/libevdev/libevdev.h
Normal file
2177
Linux/libevdev/libevdev.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -22,7 +22,7 @@ namespace Mesen.GUI.Config
|
|||
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesBeforeNmi = 0;
|
||||
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesAfterNmi = 0;
|
||||
|
||||
public RamPowerOnState RamPowerOnState;
|
||||
public RamState RamPowerOnState = RamState.AllZeros;
|
||||
|
||||
public void ApplyConfig()
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ namespace Mesen.GUI.Config
|
|||
Pal = 2
|
||||
}
|
||||
|
||||
public enum RamPowerOnState
|
||||
public enum RamState
|
||||
{
|
||||
AllZeros = 0,
|
||||
AllOnes = 1,
|
||||
|
|
|
@ -88,6 +88,11 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
base.OnFormClosing(e);
|
||||
|
||||
DebugApi.ResumeExecution();
|
||||
DebugWindowManager.CloseAll();
|
||||
|
||||
EmuApi.Stop();
|
||||
|
||||
if(_notifListener != null) {
|
||||
_notifListener.Dispose();
|
||||
_notifListener = null;
|
||||
|
@ -97,10 +102,6 @@ namespace Mesen.GUI.Forms
|
|||
ConfigManager.Config.WindowSize = this.WindowState == FormWindowState.Normal ? this.Size : this.RestoreBounds.Size;
|
||||
ConfigManager.ApplyChanges();
|
||||
|
||||
DebugApi.ResumeExecution();
|
||||
DebugWindowManager.CloseAll();
|
||||
|
||||
EmuApi.Stop();
|
||||
EmuApi.Release();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Mesen.GUI</RootNamespace>
|
||||
<AssemblyName>MesenS</AssemblyName>
|
||||
<AssemblyName>Mesen-S</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
|
||||
#include "UTF8Util.h"
|
||||
|
||||
|
|
7
build.sh
7
build.sh
|
@ -6,12 +6,7 @@
|
|||
if [ "$1" = libretro ]; then
|
||||
MESENPLATFORM=x64 make clean
|
||||
LTO=true MESENPLATFORM=x64 make libretro -j 16
|
||||
|
||||
MESENPLATFORM=x86 make clean
|
||||
LTO=true MESENPLATFORM=x86 make libretro -j 16
|
||||
else
|
||||
MESENPLATFORM=x64 BUILDTARGET=core ./buildPGO.sh
|
||||
MESENPLATFORM=x86 BUILDTARGET=core ./buildPGO.sh
|
||||
cp ./InteropDLL/obj.x64/libMesenCore.x64.dll ./bin/Any\ CPU/PGO\ Profile/Dependencies
|
||||
cp ./InteropDLL/obj.x86/libMesenCore.x86.dll ./bin/Any\ CPU/PGO\ Profile/Dependencies
|
||||
cp ./InteropDLL/obj.x64/libMesenSCore.x64.dll ./bin/Any\ CPU/PGO\ Profile/Dependencies
|
||||
fi
|
||||
|
|
22
makefile
22
makefile
|
@ -62,8 +62,8 @@ ifeq ($(PGO),optimize)
|
|||
endif
|
||||
|
||||
OBJFOLDER=obj.$(MESENPLATFORM)
|
||||
SHAREDLIB=libMesenCore.$(MESENPLATFORM).dll
|
||||
LIBRETROLIB=mesen_libretro.$(MESENPLATFORM).so
|
||||
SHAREDLIB=libMesenSCore.$(MESENPLATFORM).dll
|
||||
LIBRETROLIB=mesens_libretro.$(MESENPLATFORM).so
|
||||
RELEASEFOLDER=bin/$(MESENPLATFORM)/Release
|
||||
|
||||
COREOBJ=$(patsubst Core/%.cpp,Core/$(OBJFOLDER)/%.o,$(wildcard Core/*.cpp))
|
||||
|
@ -71,6 +71,7 @@ UTILOBJ=$(patsubst Utilities/%.cpp,Utilities/$(OBJFOLDER)/%.o,$(wildcard Utiliti
|
|||
LINUXOBJ=$(patsubst Linux/%.cpp,Linux/$(OBJFOLDER)/%.o,$(wildcard Linux/*.cpp))
|
||||
SEVENZIPOBJ=$(patsubst SevenZip/%.c,SevenZip/$(OBJFOLDER)/%.o,$(wildcard SevenZip/*.c))
|
||||
LUAOBJ=$(patsubst Lua/%.c,Lua/$(OBJFOLDER)/%.o,$(wildcard Lua/*.c))
|
||||
DLLOBJ=$(patsubst InteropDLL/%.cpp,InteropDLL/$(OBJFOLDER)/%.o,$(wildcard InteropDLL/*.cpp))
|
||||
|
||||
ifeq ($(SYSTEM_LIBEVDEV), true)
|
||||
LIBEVDEVLIB=$(shell pkg-config --libs libevdev)
|
||||
|
@ -90,10 +91,10 @@ ui: InteropDLL/$(OBJFOLDER)/$(SHAREDLIB)
|
|||
rm -fr $(RELEASEFOLDER)/Dependencies/*
|
||||
cd UpdateHelper && msbuild /property:Configuration="Release" /property:Platform="AnyCPU"
|
||||
cp "bin/Any CPU/Release/MesenUpdater.exe" $(RELEASEFOLDER)/Dependencies/
|
||||
cp -r GUI.NET/Dependencies/* $(RELEASEFOLDER)/Dependencies/
|
||||
cp -r UI/Dependencies/* $(RELEASEFOLDER)/Dependencies/
|
||||
cp InteropDLL/$(OBJFOLDER)/$(SHAREDLIB) $(RELEASEFOLDER)/Dependencies/$(SHAREDLIB)
|
||||
cd $(RELEASEFOLDER)/Dependencies && zip -r ../Dependencies.zip *
|
||||
cd GUI.NET && msbuild /property:Configuration="Release" /property:Platform="$(MESENPLATFORM)" /property:PreBuildEvent="" '/property:DefineConstants="HIDETESTMENU;DISABLEAUTOUPDATE"' /property:CodeAnalysisRuleSet=""
|
||||
cd UI && msbuild /property:Configuration="Release" /property:Platform="$(MESENPLATFORM)" /property:PreBuildEvent="" '/property:DefineConstants="HIDETESTMENU;DISABLEAUTOUPDATE"' /property:CodeAnalysisRuleSet=""
|
||||
|
||||
libretro: Libretro/$(OBJFOLDER)/$(LIBRETROLIB)
|
||||
mkdir -p bin
|
||||
|
@ -104,9 +105,6 @@ core: InteropDLL/$(OBJFOLDER)/$(SHAREDLIB)
|
|||
runtests:
|
||||
cd TestHelper/$(OBJFOLDER) && ./testhelper
|
||||
|
||||
rungametests:
|
||||
cd TestHelper/$(OBJFOLDER) && ./testhelper ~/Mesen/TestGames
|
||||
|
||||
testhelper: InteropDLL/$(OBJFOLDER)/$(SHAREDLIB)
|
||||
mkdir -p TestHelper/$(OBJFOLDER)
|
||||
$(CPPC) $(GCCOPTIONS) -Wl,-z,defs -o testhelper TestHelper/*.cpp InteropDLL/ConsoleWrapper.cpp $(SEVENZIPOBJ) $(LUAOBJ) $(LINUXOBJ) $(LIBEVDEVOBJ) $(UTILOBJ) $(COREOBJ) -pthread $(FSLIB) $(SDL2LIB) $(LIBEVDEVLIB)
|
||||
|
@ -135,10 +133,12 @@ Linux/$(OBJFOLDER)/%.o: Linux/%.cpp
|
|||
mkdir -p Linux/$(OBJFOLDER) && cd Linux/$(OBJFOLDER) && $(CPPC) $(GCCOPTIONS) -c $(patsubst Linux/%, ../%, $<) $(SDL2INC) $(LIBEVDEVINC)
|
||||
Linux/$(OBJFOLDER)/%.o: Linux/libevdev/%.c
|
||||
mkdir -p Linux/$(OBJFOLDER) && cd Linux/$(OBJFOLDER) && $(CC) $(CCOPTIONS) -c $(patsubst Linux/%, ../%, $<)
|
||||
InteropDLL/$(OBJFOLDER)/%.o: InteropDLL/%.cpp
|
||||
mkdir -p InteropDLL/$(OBJFOLDER) && cd InteropDLL/$(OBJFOLDER) && $(CPPC) $(GCCOPTIONS) -c $(patsubst InteropDLL/%, ../%, $<)
|
||||
|
||||
InteropDLL/$(OBJFOLDER)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(COREOBJ) $(LIBEVDEVOBJ) $(LINUXOBJ) InteropDLL/ConsoleWrapper.cpp InteropDLL/DebugWrapper.cpp
|
||||
InteropDLL/$(OBJFOLDER)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(COREOBJ) $(LIBEVDEVOBJ) $(LINUXOBJ) $(DLLOBJ)
|
||||
mkdir -p InteropDLL/$(OBJFOLDER)
|
||||
$(CPPC) $(GCCOPTIONS) -Wl,-z,defs -shared -o $(SHAREDLIB) InteropDLL/*.cpp $(SEVENZIPOBJ) $(LUAOBJ) $(LINUXOBJ) $(LIBEVDEVOBJ) $(UTILOBJ) $(COREOBJ) $(SDL2INC) -pthread $(FSLIB) $(SDL2LIB) $(LIBEVDEVLIB)
|
||||
$(CPPC) $(GCCOPTIONS) -Wl,-z,defs -shared -o $(SHAREDLIB) $(DLLOBJ) $(SEVENZIPOBJ) $(LUAOBJ) $(LINUXOBJ) $(LIBEVDEVOBJ) $(UTILOBJ) $(COREOBJ) $(SDL2INC) -pthread $(FSLIB) $(SDL2LIB) $(LIBEVDEVLIB)
|
||||
cp $(SHAREDLIB) bin/pgohelperlib.so
|
||||
mv $(SHAREDLIB) InteropDLL/$(OBJFOLDER)
|
||||
|
||||
|
@ -155,10 +155,10 @@ official:
|
|||
./build.sh
|
||||
|
||||
debug:
|
||||
MONO_LOG_LEVEL=debug mono $(RELEASEFOLDER)/Mesen.exe
|
||||
MONO_LOG_LEVEL=debug mono $(RELEASEFOLDER)/Mesen-S.exe
|
||||
|
||||
run:
|
||||
mono $(RELEASEFOLDER)/Mesen.exe
|
||||
mono $(RELEASEFOLDER)/Mesen-S.exe
|
||||
|
||||
clean:
|
||||
rm -rf Lua/$(OBJFOLDER)
|
||||
|
|
Loading…
Add table
Reference in a new issue