Linux: Fixed build/makefile and compilation errors/warnings (and add missing files to git)

This commit is contained in:
Sour 2019-03-31 14:50:12 -04:00
parent ace5321598
commit e1c7e7b9c4
51 changed files with 7569 additions and 137 deletions

2
.gitignore vendored
View file

@ -182,8 +182,6 @@ packages/*
!Libretro/hakchi/bin
Dependencies/*
Linux/*
Libretro/*
Docs/*
Lua/*

View file

@ -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()) {

View file

@ -44,7 +44,7 @@ private:
void DisplayCartInfo();
public:
~BaseCartridge();
virtual ~BaseCartridge();
static shared_ptr<BaseCartridge> CreateCartridge(VirtualFile &romFile, VirtualFile &patchFile);

View file

@ -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;
}

View file

@ -37,7 +37,7 @@ protected:
public:
ControlManager(shared_ptr<Console> console);
~ControlManager();
virtual ~ControlManager();
void UpdateControlDevices();
void UpdateInputState();

View file

@ -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);

View file

@ -43,10 +43,8 @@ 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];
}
for(int i = 0; i < 60; i++) {
totalDuration += _frameDurations[i];
}
ss = std::stringstream();

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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++;

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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]);

View file

@ -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]);

View file

@ -4,7 +4,7 @@
class Console;
class InternalRegisters : public ISerializable
class InternalRegisters final : public ISerializable
{
private:
shared_ptr<Console> _console;

View file

@ -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)

View file

@ -39,7 +39,7 @@ private:
public:
void Initialize(shared_ptr<Console> console);
~MemoryManager();
virtual ~MemoryManager();
void Reset();

View file

@ -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;

View file

@ -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();

View file

@ -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;
};

View file

@ -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);
}*/

View file

@ -238,7 +238,7 @@ private:
public:
Spc(shared_ptr<Console> console, vector<uint8_t> &spcRomData);
~Spc();
virtual ~Spc();
void Run();
void Reset();

View file

@ -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

View file

@ -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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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)

View 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;
}
*/

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

View 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

View 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

File diff suppressed because it is too large Load diff

2177
Linux/libevdev/libevdev.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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();
}

View file

@ -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>

View file

@ -7,6 +7,7 @@
#include <memory>
#include <vector>
#include <atomic>
#include <cstring>
#include "UTF8Util.h"

View file

@ -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

View file

@ -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)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(COREOBJ) $(LIBEVDEVOBJ) $(LINUXOBJ) InteropDLL/ConsoleWrapper.cpp InteropDLL/DebugWrapper.cpp
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) $(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)