modernize camera_betterer
This commit is contained in:
parent
4ec22dda9e
commit
e63c2985fc
|
@ -1,26 +0,0 @@
|
||||||
trigger:
|
|
||||||
- master
|
|
||||||
|
|
||||||
pool:
|
|
||||||
name: Default
|
|
||||||
demands:
|
|
||||||
- agent.name -equals MacStadium-ARM64-Mac
|
|
||||||
|
|
||||||
workspace:
|
|
||||||
clean: all
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- script: mkdir $(Pipeline.Workspace)/build
|
|
||||||
displayName: 'Create build environment'
|
|
||||||
|
|
||||||
- script: arch -arm64 cmake $(Build.SourcesDirectory) -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DMACOS_BUNDLE_LIBS=ON -DMACOS_BUILD_DMG=ON -DUSE_QT6=ON
|
|
||||||
displayName: 'Configure'
|
|
||||||
workingDirectory: $(Pipeline.Workspace)/build
|
|
||||||
|
|
||||||
- script: arch -arm64 make -j$(sysctl -n hw.logicalcpu)
|
|
||||||
displayName: 'Make'
|
|
||||||
workingDirectory: $(Pipeline.Workspace)/build
|
|
||||||
|
|
||||||
- publish: $(Pipeline.Workspace)/build/melonDS.dmg
|
|
||||||
artifact: melonDS.dmg
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
trigger:
|
|
||||||
- master
|
|
||||||
|
|
||||||
pool:
|
|
||||||
vmImage: macOS-10.15
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- script: brew install llvm sdl2 qt@6 libslirp libarchive libepoxy
|
|
||||||
displayName: 'Install dependencies'
|
|
||||||
|
|
||||||
- script: mkdir $(Pipeline.Workspace)/build
|
|
||||||
displayName: 'Create build environment'
|
|
||||||
|
|
||||||
- script: cmake $(Build.SourcesDirectory) -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DMACOS_BUNDLE_LIBS=ON -DMACOS_BUILD_DMG=ON -DUSE_QT6=ON
|
|
||||||
displayName: 'Configure'
|
|
||||||
workingDirectory: $(Pipeline.Workspace)/build
|
|
||||||
|
|
||||||
- script: make -j$(sysctl -n hw.logicalcpu)
|
|
||||||
displayName: 'Make'
|
|
||||||
workingDirectory: $(Pipeline.Workspace)/build
|
|
||||||
|
|
||||||
- publish: $(Pipeline.Workspace)/build/melonDS.dmg
|
|
||||||
artifact: melonDS.dmg
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
name: CMake Build (macOS Universal)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
prepare:
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clean workspace
|
||||||
|
run: rm -rf ${{runner.workspace}}/build
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
|
||||||
|
build-arm64:
|
||||||
|
needs: prepare
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
env:
|
||||||
|
homebrew_prefix: /opt/homebrew
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Create build directory
|
||||||
|
run: mkdir -p ${{runner.workspace}}/build/arm64
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
working-directory: ${{runner.workspace}}/build/arm64
|
||||||
|
run: arch -arm64 ${{env.homebrew_prefix}}/bin/cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="${{env.homebrew_prefix}}/opt/qt@6;${{env.homebrew_prefix}}/opt/libarchive" -DPKG_CONFIG_EXECUTABLE=${{env.homebrew_prefix}}/bin/pkg-config -DMACOS_BUNDLE_LIBS=ON -DUSE_QT6=ON
|
||||||
|
|
||||||
|
- name: Make
|
||||||
|
working-directory: ${{runner.workspace}}/build/arm64
|
||||||
|
run: arch -arm64 make -j$(sysctl -n hw.logicalcpu)
|
||||||
|
|
||||||
|
build-x86_64:
|
||||||
|
needs: prepare
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
env:
|
||||||
|
homebrew_prefix: /usr/local
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Create build directory
|
||||||
|
run: mkdir -p ${{runner.workspace}}/build/x86_64
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
working-directory: ${{runner.workspace}}/build/x86_64
|
||||||
|
run: arch -x86_64 ${{env.homebrew_prefix}}/bin/cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH="${{env.homebrew_prefix}}/opt/qt@6;${{env.homebrew_prefix}}/opt/libarchive" -DPKG_CONFIG_EXECUTABLE=${{env.homebrew_prefix}}/bin/pkg-config -DMACOS_BUNDLE_LIBS=ON -DUSE_QT6=ON
|
||||||
|
|
||||||
|
- name: Make
|
||||||
|
working-directory: ${{runner.workspace}}/build/x86_64
|
||||||
|
run: arch -x86_64 make -j$(sysctl -n hw.logicalcpu)
|
||||||
|
|
||||||
|
universal-binary:
|
||||||
|
needs: [build-arm64, build-x86_64]
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Merge binaries
|
||||||
|
run: $GITHUB_WORKSPACE/tools/mac-universal.py ${{runner.workspace}}/build/arm64/melonDS.app ${{runner.workspace}}/build/x86_64/melonDS.app ${{runner.workspace}}/build/universal/melonDS.app
|
||||||
|
|
||||||
|
- name: Create DMG
|
||||||
|
run: hdiutil create -fs HFS+ -volname melonDS -srcfolder ${{runner.workspace}}/build/universal/melonDS.app -ov -format UDBZ ${{runner.workspace}}/build/universal/melonDS.dmg
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: macOS-universal
|
||||||
|
path: ${{runner.workspace}}/build/universal/melonDS.dmg
|
||||||
|
|
|
@ -35,7 +35,7 @@ jobs:
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake $GITHUB_WORKSPACE -G 'MSYS Makefiles' -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC=ON -DQT5_STATIC_DIR=C:/tools/msys64/mingw64/qt5-static
|
run: cmake $GITHUB_WORKSPACE -G 'MSYS Makefiles' -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=C:/tools/msys64/mingw64/qt5-static
|
||||||
|
|
||||||
- name: Make
|
- name: Make
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
|
126
CMakeLists.txt
126
CMakeLists.txt
|
@ -1,43 +1,38 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
cmake_policy(VERSION 3.15)
|
||||||
include(CheckLibraryExists)
|
|
||||||
|
|
||||||
cmake_policy(VERSION 3.13)
|
|
||||||
if (POLICY CMP0076)
|
if (POLICY CMP0076)
|
||||||
cmake_policy(SET CMP0076 NEW)
|
cmake_policy(SET CMP0076 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
project(melonDS
|
||||||
|
VERSION 0.9.4
|
||||||
|
DESCRIPTION "DS emulator, sorta"
|
||||||
|
HOMEPAGE_URL "https://melonds.kuribo64.net"
|
||||||
|
LANGUAGES C CXX)
|
||||||
|
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
include(CMakeDependentOption)
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
|
||||||
project(melonDS CXX)
|
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
set(MELONDS_VERSION "0.9.4")
|
add_compile_definitions(MELONDS_VERSION="${melonDS_VERSION}")
|
||||||
add_compile_definitions(MELONDS_VERSION="${MELONDS_VERSION}")
|
|
||||||
string(REPLACE "." ";" VERSION_LIST ${MELONDS_VERSION})
|
|
||||||
# For the melon.rc file used on Windows
|
|
||||||
list(GET VERSION_LIST 0 MELONDS_VERSION_MAJOR)
|
|
||||||
list(GET VERSION_LIST 1 MELONDS_VERSION_MINOR)
|
|
||||||
# Check if melonDS version is three digits or two digits
|
|
||||||
list(LENGTH VERSION_LIST MELONDS_VER_LEN)
|
|
||||||
if (${MELONDS_VER_LEN} GREATER 2)
|
|
||||||
list(GET VERSION_LIST 2 MELONDS_VERSION_PATCH)
|
|
||||||
else()
|
|
||||||
set(MELONDS_VERSION_PATCH 0)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
check_library_exists(m pow "" LIBM)
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||||
if(LIBM)
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||||
link_libraries(m)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT CMAKE_BUILD_TYPE)
|
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
function(detect_architecture symbol arch)
|
function(detect_architecture symbol arch)
|
||||||
|
@ -61,74 +56,41 @@ detect_architecture("__i386__" x86)
|
||||||
detect_architecture("__arm__" ARM)
|
detect_architecture("__arm__" ARM)
|
||||||
detect_architecture("__aarch64__" ARM64)
|
detect_architecture("__aarch64__" ARM64)
|
||||||
|
|
||||||
if (ARCHITECTURE STREQUAL x86_64 OR ARCHITECTURE STREQUAL ARM64)
|
cmake_dependent_option(ENABLE_JIT "Enable JIT recompiler" ON
|
||||||
option(ENABLE_JIT "Enable x64 JIT recompiler" ON)
|
"ARCHITECTURE STREQUAL x86_64 OR ARCHITECTURE STREQUAL ARM64" OFF)
|
||||||
endif()
|
cmake_dependent_option(ENABLE_JIT_PROFILING "Enable JIT profiling with VTune" OFF "ENABLE_JIT" OFF)
|
||||||
|
|
||||||
if (ENABLE_JIT)
|
|
||||||
add_definitions(-DJIT_ENABLED)
|
|
||||||
|
|
||||||
option(ENABLE_JIT_PROFILING "Enable JIT profiling with VTune" OFF)
|
|
||||||
|
|
||||||
if (ENABLE_JIT_PROFILING)
|
|
||||||
include(cmake/FindVTune.cmake)
|
|
||||||
add_definitions(-DJIT_PROFILING_ENABLED)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL Release)
|
|
||||||
option(ENABLE_LTO "Enable link-time optimization" ON)
|
|
||||||
else()
|
|
||||||
option(ENABLE_LTO "Enable link-time optimization" OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(ENABLE_OGLRENDERER "Enable OpenGL renderer" ON)
|
option(ENABLE_OGLRENDERER "Enable OpenGL renderer" ON)
|
||||||
|
|
||||||
if (ENABLE_OGLRENDERER)
|
check_ipo_supported(RESULT IPO_SUPPORTED)
|
||||||
add_definitions(-DOGLRENDERER_ENABLED)
|
cmake_dependent_option(ENABLE_LTO_RELEASE "Enable link-time optimizations for release builds" ON "IPO_SUPPORTED" OFF)
|
||||||
|
cmake_dependent_option(ENABLE_LTO "Enable link-time optimizations" OFF "IPO_SUPPORTED" OFF)
|
||||||
|
|
||||||
|
if (ENABLE_LTO_RELEASE)
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL Debug)
|
if (ENABLE_LTO)
|
||||||
add_compile_options(-Og)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL Release)
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
|
||||||
add_compile_options(-O3)
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
|
||||||
if (NOT APPLE)
|
set(CMAKE_C_FLAGS_RELEASE "-O3")
|
||||||
add_link_options(-s)
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||||
endif()
|
|
||||||
|
if (NOT APPLE)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
option(BUILD_STATIC "Statically link dependencies" OFF)
|
option(BUILD_STATIC "Statically link dependencies" OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_STATIC AND WIN32)
|
if (BUILD_STATIC AND WIN32)
|
||||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LTO)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
if (WIN32 OR APPLE)
|
|
||||||
add_compile_options(-flto)
|
|
||||||
add_link_options(-flto)
|
|
||||||
else()
|
|
||||||
add_compile_options(-flto -fPIC)
|
|
||||||
add_link_options(-flto -fuse-linker-plugin -pie)
|
|
||||||
endif()
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
||||||
set(CMAKE_AR "gcc-ar")
|
|
||||||
set(CMAKE_RANLIB "gcc-ranlib")
|
|
||||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
||||||
find_program(LLD NAMES ld.lld ld64.lld lld-link)
|
|
||||||
if (NOT LLD STREQUAL "LLD-NOTFOUND")
|
|
||||||
add_link_options(-fuse-ld=lld)
|
|
||||||
endif()
|
|
||||||
if (NOT APPLE)
|
|
||||||
set(CMAKE_AR "llvm-ar")
|
|
||||||
set(CMAKE_RANLIB "llvm-ranlib")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_program(CCACHE "ccache")
|
find_program(CCACHE "ccache")
|
||||||
if (CCACHE)
|
if (CCACHE)
|
||||||
|
@ -142,5 +104,5 @@ option(BUILD_QT_SDL "Build Qt/SDL frontend" ON)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
if (BUILD_QT_SDL)
|
if (BUILD_QT_SDL)
|
||||||
add_subdirectory(src/frontend/qt_sdl)
|
add_subdirectory(src/frontend/qt_sdl)
|
||||||
endif()
|
endif()
|
||||||
|
|
90
README.md
90
README.md
|
@ -1,4 +1,4 @@
|
||||||
<p align="center"><img src="https://raw.githubusercontent.com/Arisotura/melonDS/master/res/icon/melon_128x128.png"></p>
|
<p align="center"><img src="https://raw.githubusercontent.com/melonDS-emu/melonDS/master/res/icon/melon_128x128.png"></p>
|
||||||
<h2 align="center"><b>melonDS</b></h2>
|
<h2 align="center"><b>melonDS</b></h2>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a>
|
<a href="http://melonds.kuribo64.net/" alt="melonDS website"><img src="https://img.shields.io/badge/website-melonds.kuribo64.net-%2331352e.svg"></a>
|
||||||
|
@ -6,9 +6,9 @@
|
||||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a>
|
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-%23ff554d.svg"></a>
|
||||||
<a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a>
|
<a href="https://kiwiirc.com/client/irc.badnik.net/?nick=IRC-Source_?#melonds" alt="IRC channel: #melonds"><img src="https://img.shields.io/badge/IRC%20chat-%23melonds-%23dd2e44.svg"></a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/Arisotura/melonDS/actions?query=workflow%3A%22CMake+Build+%28Windows+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/Arisotura/melonDS/CMake%20Build%20(Windows%20x86-64)?label=Windows%20x86-64&logo=GitHub"></img></a>
|
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Windows+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/melonDS-emu/melonDS/CMake%20Build%20(Windows%20x86-64)?label=Windows%20x86-64&logo=GitHub"></img></a>
|
||||||
<a href="https://github.com/Arisotura/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/Arisotura/melonDS/CMake%20Build%20(Ubuntu%20x86-64)?label=Linux%20x86-64&logo=GitHub"></img></a>
|
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+x86-64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/melonDS-emu/melonDS/CMake%20Build%20(Ubuntu%20x86-64)?label=Linux%20x86-64&logo=GitHub"></img></a>
|
||||||
<a href="https://github.com/Arisotura/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+aarch64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/Arisotura/melonDS/CMake%20Build%20(Ubuntu%20aarch64)?label=Linux%20ARM64&logo=GitHub"></img></a>
|
<a href="https://github.com/melonDS-emu/melonDS/actions?query=workflow%3A%22CMake+Build+%28Ubuntu+aarch64%29%22+event%3Apush"><img src="https://img.shields.io/github/workflow/status/melonDS-emu/melonDS/CMake%20Build%20(Ubuntu%20aarch64)?label=Linux%20ARM64&logo=GitHub"></img></a>
|
||||||
<a href="https://dev.azure.com/melonDS/melonDS/_build?definitionId=1&repositoryFilter=1&branchFilter=2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2"><img src="https://img.shields.io/azure-devops/build/melonDS/7c9c08a1-669f-42a4-bef4-a6c74eadf723/1/master?label=macOS%20x86-64&logo=Azure%20Pipelines"></img></a>
|
<a href="https://dev.azure.com/melonDS/melonDS/_build?definitionId=1&repositoryFilter=1&branchFilter=2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2%2C2"><img src="https://img.shields.io/azure-devops/build/melonDS/7c9c08a1-669f-42a4-bef4-a6c74eadf723/1/master?label=macOS%20x86-64&logo=Azure%20Pipelines"></img></a>
|
||||||
<a href="https://dev.azure.com/melonDS/melonDS/_build?definitionId=2&_a=summary&repositoryFilter=1&branchFilter=2%2C2%2C2%2C2%2C2"><img src="https://img.shields.io/azure-devops/build/melonDS/7c9c08a1-669f-42a4-bef4-a6c74eadf723/2/master?label=macOS%20ARM64&logo=Azure%20Pipelines"></img></a>
|
<a href="https://dev.azure.com/melonDS/melonDS/_build?definitionId=2&_a=summary&repositoryFilter=1&branchFilter=2%2C2%2C2%2C2%2C2"><img src="https://img.shields.io/azure-devops/build/melonDS/7c9c08a1-669f-42a4-bef4-a6c74eadf723/2/master?label=macOS%20ARM64&logo=Azure%20Pipelines"></img></a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -34,69 +34,75 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
|
|
||||||
### Linux:
|
### Linux
|
||||||
|
1. Install dependencies:
|
||||||
|
* Ubuntu 22.04: `sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev libslirp-dev libarchive-dev libepoxy-dev`
|
||||||
|
* Older Ubuntu: `sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default libslirp-dev libarchive-dev libepoxy-dev`
|
||||||
|
* Arch Linux: `sudo pacman -S base-devel cmake git libpcap sdl2 qt5-base libslirp libarchive libepoxy`
|
||||||
|
3. Download the melonDS repository and prepare:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/melonDS-emu/melonDS
|
||||||
|
cd melonDS
|
||||||
|
```
|
||||||
|
|
||||||
1. Install dependencies: `sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default libslirp-dev libarchive-dev libepoxy-dev`
|
|
||||||
2. Download the melonDS repository and prepare:
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/Arisotura/melonDS
|
|
||||||
cd melonDS
|
|
||||||
mkdir build && cd build
|
|
||||||
```
|
|
||||||
3. Compile:
|
3. Compile:
|
||||||
```bash
|
```bash
|
||||||
cmake ..
|
cmake -B build
|
||||||
make -j$(nproc --all)
|
cmake --build build -j$(nproc --all)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Windows:
|
|
||||||
|
|
||||||
|
### Windows
|
||||||
1. Install [MSYS2](https://www.msys2.org/)
|
1. Install [MSYS2](https://www.msys2.org/)
|
||||||
2. Open the **MSYS2 MinGW 64-bit** terminal
|
2. Open the **MSYS2 MinGW 64-bit** terminal
|
||||||
3. Update the packages using `pacman -Syu` and reopen the terminal if it asks you to
|
3. Update the packages using `pacman -Syu` and reopen the terminal if it asks you to
|
||||||
4. Download the melonDS repository and prepare:
|
4. Install git to clone the repository
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Arisotura/melonDS
|
pacman -S git
|
||||||
cd melonDS
|
```
|
||||||
mkdir build && cd build
|
5. Download the melonDS repository and prepare:
|
||||||
```
|
```bash
|
||||||
|
git clone https://github.com/melonDS-emu/melonDS
|
||||||
|
cd melonDS
|
||||||
|
```
|
||||||
#### Dynamic builds (with DLLs)
|
#### Dynamic builds (with DLLs)
|
||||||
5. Install dependencies: `pacman -S git make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5,libslirp,libarchive,libepoxy}`
|
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5,libslirp,libarchive,libepoxy}`
|
||||||
6. Compile:
|
6. Compile:
|
||||||
```bash
|
```bash
|
||||||
cmake .. -G "MSYS Makefiles"
|
cmake -B build -G "MSYS Makefiles"
|
||||||
make -j$(nproc --all)
|
cmake --build build -j$(nproc --all)
|
||||||
|
cd build
|
||||||
../tools/msys-dist.sh
|
../tools/msys-dist.sh
|
||||||
```
|
```
|
||||||
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
||||||
|
|
||||||
#### Static builds (without DLLs, standalone executable)
|
#### Static builds (without DLLs, standalone executable)
|
||||||
5. Install dependencies: `pacman -S git make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-static,libslirp,libarchive,libepoxy}`
|
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-static,libslirp,libarchive,libepoxy}`
|
||||||
6. Compile:
|
6. Compile:
|
||||||
```bash
|
```bash
|
||||||
cmake .. -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DQT5_STATIC_DIR=/mingw64/qt5-static
|
cmake -B build -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=/mingw64/qt5-static
|
||||||
make -j$(nproc --all)
|
cmake --build build -j$(nproc --all)
|
||||||
mkdir dist && cp melonDS.exe dist
|
|
||||||
```
|
```
|
||||||
If everything went well, melonDS should now be in the `dist` folder.
|
If everything went well, melonDS should now be in the `build` folder.
|
||||||
|
|
||||||
### macOS:
|
### macOS
|
||||||
1. Install the [Homebrew Package Manager](https://brew.sh)
|
1. Install the [Homebrew Package Manager](https://brew.sh)
|
||||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive libepoxy`
|
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive libepoxy`
|
||||||
3. Download the melonDS repository and prepare:
|
3. Download the melonDS repository and prepare:
|
||||||
```zsh
|
```zsh
|
||||||
git clone https://github.com/Arisotura/melonDS
|
git clone https://github.com/melonDS-emu/melonDS
|
||||||
cd melonDS
|
cd melonDS
|
||||||
mkdir build && cd build
|
```
|
||||||
```
|
|
||||||
4. Compile:
|
4. Compile:
|
||||||
```zsh
|
```zsh
|
||||||
cmake .. -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DUSE_QT6=ON -DMACOS_BUNDLE_LIBS=ON
|
cmake -B build -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6);$(brew --prefix libarchive)" -DUSE_QT6=ON
|
||||||
make -j$(sysctl -n hw.logicalcpu)
|
cmake --build build -j$(sysctl -n hw.logicalcpu)
|
||||||
```
|
```
|
||||||
If everything went well, melonDS.app should now be in the current directory.
|
If everything went well, melonDS.app should now be in the `build` directory.
|
||||||
|
|
||||||
|
#### Self-contained app bundle
|
||||||
|
If you want an app bundle that can be distributed to other computers without needing to install dependencies through Homebrew, you can additionally run `
|
||||||
|
../tools/mac-bundle.rb melonDS.app` after the build is completed, or add `-DMACOS_BUNDLE_LIBS=ON` to the first CMake command.
|
||||||
|
|
||||||
|
|
||||||
## TODO LIST
|
## TODO LIST
|
||||||
|
|
||||||
* better DSi emulation
|
* better DSi emulation
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# The entire codebase quite reasonably does things like #include <SDL2/SDL.h> or <epoxy/gl.h>
|
||||||
|
# CMake apparently doesn't think you should be doing this, so just includes $PREFIX/include/packagename for a given
|
||||||
|
# package as include directories when using `target_link_libraries` with an imported target, this hacky function fixes
|
||||||
|
# that up so includes can keep working as they always did but we can still use fancy imported targets.
|
||||||
|
# This is stupid.
|
||||||
|
|
||||||
|
function(fix_interface_includes)
|
||||||
|
foreach (target ${ARGN})
|
||||||
|
set(NEW_DIRS)
|
||||||
|
get_target_property(DIRS "${target}" INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
|
||||||
|
if (NOT DIRS)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach (DIR ${DIRS})
|
||||||
|
get_filename_component(PARENT_DIR "${DIR}" DIRECTORY)
|
||||||
|
|
||||||
|
if (PARENT_DIR MATCHES "include$")
|
||||||
|
list(APPEND NEW_DIRS "${PARENT_DIR}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
list(APPEND DIRS ${NEW_DIRS})
|
||||||
|
set_target_properties("${target}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${DIRS}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>${MELONDS_VERSION}</string>
|
<string>${melonDS_VERSION}</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>${MELONDS_VERSION}</string>
|
<string>${melonDS_VERSION}</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Licensed under GPLv3</string>
|
<string>Licensed under GPLv3</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
//include version information in .exe, modify these values to match your needs
|
//include version information in .exe, modify these values to match your needs
|
||||||
1 VERSIONINFO
|
1 VERSIONINFO
|
||||||
FILEVERSION ${MELONDS_VERSION_MAJOR},${MELONDS_VERSION_MINOR},${MELONDS_VERSION_PATCH},0
|
FILEVERSION ${melonDS_VERSION_MAJOR},${melonDS_VERSION_MINOR},${melonDS_VERSION_PATCH},0
|
||||||
PRODUCTVERSION ${MELONDS_VERSION_MAJOR},${MELONDS_VERSION_MINOR},${MELONDS_VERSION_PATCH},0
|
PRODUCTVERSION ${melonDS_VERSION_MAJOR},${melonDS_VERSION_MINOR},${melonDS_VERSION_PATCH},0
|
||||||
FILETYPE VFT_APP
|
FILETYPE VFT_APP
|
||||||
{
|
{
|
||||||
BLOCK "StringFileInfo"
|
BLOCK "StringFileInfo"
|
||||||
|
@ -15,14 +15,14 @@ FILETYPE VFT_APP
|
||||||
BLOCK "040904E4"
|
BLOCK "040904E4"
|
||||||
{
|
{
|
||||||
VALUE "CompanyName", "Melon Factory of Kuribo64"
|
VALUE "CompanyName", "Melon Factory of Kuribo64"
|
||||||
VALUE "FileVersion", "${MELONDS_VERSION}"
|
VALUE "FileVersion", "${melonDS_VERSION}"
|
||||||
VALUE "FileDescription", "melonDS emulator"
|
VALUE "FileDescription", "melonDS emulator"
|
||||||
VALUE "InternalName", "SDnolem"
|
VALUE "InternalName", "SDnolem"
|
||||||
VALUE "LegalCopyright", "2016-2022 melonDS team"
|
VALUE "LegalCopyright", "2016-2022 melonDS team"
|
||||||
VALUE "LegalTrademarks", ""
|
VALUE "LegalTrademarks", ""
|
||||||
VALUE "OriginalFilename", "zafkflzdasd.exe"
|
VALUE "OriginalFilename", "zafkflzdasd.exe"
|
||||||
VALUE "ProductName", "melonDS"
|
VALUE "ProductName", "melonDS"
|
||||||
VALUE "ProductVersion", "${MELONDS_VERSION}"
|
VALUE "ProductVersion", "${melonDS_VERSION}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -1086,11 +1086,34 @@ void InvalidateByAddr(u32 localAddr)
|
||||||
|
|
||||||
void CheckAndInvalidateITCM()
|
void CheckAndInvalidateITCM()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < ITCMPhysicalSize; i+=16)
|
for (u32 i = 0; i < ITCMPhysicalSize; i+=512)
|
||||||
{
|
{
|
||||||
if (CodeIndexITCM[i / 512].Code & (1 << ((i & 0x1FF) / 16)))
|
if (CodeIndexITCM[i / 512].Code)
|
||||||
{
|
{
|
||||||
InvalidateByAddr(i | (ARMJIT_Memory::memregion_ITCM << 27));
|
// maybe using bitscan would be better here?
|
||||||
|
// The thing is that in densely populated sets
|
||||||
|
// The old fashioned way can actually be faster
|
||||||
|
for (u32 j = 0; j < 512; j += 16)
|
||||||
|
{
|
||||||
|
if (CodeIndexITCM[i / 512].Code & (1 << ((j & 0x1FF) / 16)))
|
||||||
|
InvalidateByAddr((i+j) | (ARMJIT_Memory::memregion_ITCM << 27));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckAndInvalidateWVRAM(int bank)
|
||||||
|
{
|
||||||
|
u32 start = bank == 1 ? 0x20000 : 0;
|
||||||
|
for (u32 i = start; i < start+0x20000; i+=512)
|
||||||
|
{
|
||||||
|
if (CodeIndexARM7WVRAM[i / 512].Code)
|
||||||
|
{
|
||||||
|
for (u32 j = 0; j < 512; j += 16)
|
||||||
|
{
|
||||||
|
if (CodeIndexARM7WVRAM[i / 512].Code & (1 << ((j & 0x1FF) / 16)))
|
||||||
|
InvalidateByAddr((i+j) | (ARMJIT_Memory::memregion_VWRAM << 27));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void CheckAndInvalidateITCM();
|
void CheckAndInvalidateITCM();
|
||||||
|
void CheckAndInvalidateWVRAM(int bank);
|
||||||
|
|
||||||
void InvalidateByAddr(u32 pseudoPhysical);
|
void InvalidateByAddr(u32 pseudoPhysical);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define ARMJIT_REGCACHE_H
|
#define ARMJIT_REGCACHE_H
|
||||||
|
|
||||||
#include "ARMJIT.h"
|
#include "ARMJIT.h"
|
||||||
|
#include "ARMJIT_Internal.h"
|
||||||
|
|
||||||
// TODO: replace this in the future
|
// TODO: replace this in the future
|
||||||
#include "dolphin/BitSet.h"
|
#include "dolphin/BitSet.h"
|
||||||
|
@ -41,7 +42,7 @@ public:
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
Mapping[i] = (Reg)-1;
|
Mapping[i] = (Reg)-1;
|
||||||
|
|
||||||
PCAllocatableAsSrc = ~(pcAllocatableAsSrc
|
PCAllocatableAsSrc = ~(pcAllocatableAsSrc
|
||||||
? 0
|
? 0
|
||||||
: (1 << 15));
|
: (1 << 15));
|
||||||
|
|
|
@ -1,141 +1,145 @@
|
||||||
project(core)
|
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 17)
|
set (CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
add_library(core STATIC
|
include(FixInterfaceIncludes)
|
||||||
ARCodeFile.cpp
|
|
||||||
AREngine.cpp
|
|
||||||
ARM.cpp
|
|
||||||
ARM_InstrTable.h
|
|
||||||
ARMInterpreter.cpp
|
|
||||||
ARMInterpreter_ALU.cpp
|
|
||||||
ARMInterpreter_Branch.cpp
|
|
||||||
ARMInterpreter_LoadStore.cpp
|
|
||||||
CP15.cpp
|
|
||||||
CRC32.cpp
|
|
||||||
DMA.cpp
|
|
||||||
DMA_Timings.h
|
|
||||||
DSi.cpp
|
|
||||||
DSi_AES.cpp
|
|
||||||
DSi_Camera.cpp
|
|
||||||
DSi_DSP.cpp
|
|
||||||
DSi_I2C.cpp
|
|
||||||
DSi_NAND.cpp
|
|
||||||
DSi_NDMA.cpp
|
|
||||||
DSi_NWifi.cpp
|
|
||||||
DSi_SD.cpp
|
|
||||||
DSi_SPI_TSC.cpp
|
|
||||||
FATStorage.cpp
|
|
||||||
FIFO.h
|
|
||||||
GBACart.cpp
|
|
||||||
GPU.cpp
|
|
||||||
GPU2D.cpp
|
|
||||||
GPU2D_Soft.cpp
|
|
||||||
GPU3D.cpp
|
|
||||||
GPU3D_Soft.cpp
|
|
||||||
melonDLDI.h
|
|
||||||
NDS.cpp
|
|
||||||
NDSCart.cpp
|
|
||||||
Platform.h
|
|
||||||
ROMList.h
|
|
||||||
FreeBIOS.h
|
|
||||||
RTC.cpp
|
|
||||||
Savestate.cpp
|
|
||||||
SPI.cpp
|
|
||||||
SPU.cpp
|
|
||||||
types.h
|
|
||||||
version.h
|
|
||||||
Wifi.cpp
|
|
||||||
WifiAP.cpp
|
|
||||||
|
|
||||||
fatfs/diskio.c
|
add_library(core STATIC
|
||||||
fatfs/ff.c
|
ARCodeFile.cpp
|
||||||
fatfs/ffsystem.c
|
AREngine.cpp
|
||||||
fatfs/ffunicode.c
|
ARM.cpp
|
||||||
fatfs/ffconf.h
|
ARM_InstrTable.h
|
||||||
|
ARMInterpreter.cpp
|
||||||
sha1/sha1.c
|
ARMInterpreter_ALU.cpp
|
||||||
tiny-AES-c/aes.c
|
ARMInterpreter_Branch.cpp
|
||||||
xxhash/xxhash.c
|
ARMInterpreter_LoadStore.cpp
|
||||||
)
|
CP15.cpp
|
||||||
|
CRC32.cpp
|
||||||
|
DMA.cpp
|
||||||
|
DMA_Timings.h
|
||||||
|
DSi.cpp
|
||||||
|
DSi_AES.cpp
|
||||||
|
DSi_Camera.cpp
|
||||||
|
DSi_DSP.cpp
|
||||||
|
DSi_I2C.cpp
|
||||||
|
DSi_NAND.cpp
|
||||||
|
DSi_NDMA.cpp
|
||||||
|
DSi_NWifi.cpp
|
||||||
|
DSi_SD.cpp
|
||||||
|
DSi_SPI_TSC.cpp
|
||||||
|
FATStorage.cpp
|
||||||
|
FIFO.h
|
||||||
|
GBACart.cpp
|
||||||
|
GPU.cpp
|
||||||
|
GPU2D.cpp
|
||||||
|
GPU2D_Soft.cpp
|
||||||
|
GPU3D.cpp
|
||||||
|
GPU3D_Soft.cpp
|
||||||
|
melonDLDI.h
|
||||||
|
NDS.cpp
|
||||||
|
NDSCart.cpp
|
||||||
|
Platform.h
|
||||||
|
ROMList.h
|
||||||
|
FreeBIOS.h
|
||||||
|
RTC.cpp
|
||||||
|
Savestate.cpp
|
||||||
|
SPI.cpp
|
||||||
|
SPU.cpp
|
||||||
|
types.h
|
||||||
|
version.h
|
||||||
|
Wifi.cpp
|
||||||
|
WifiAP.cpp
|
||||||
|
|
||||||
|
fatfs/diskio.c
|
||||||
|
fatfs/ff.c
|
||||||
|
fatfs/ffsystem.c
|
||||||
|
fatfs/ffunicode.c
|
||||||
|
fatfs/ffconf.h
|
||||||
|
|
||||||
|
sha1/sha1.c
|
||||||
|
tiny-AES-c/aes.c
|
||||||
|
xxhash/xxhash.c)
|
||||||
|
|
||||||
if (ENABLE_OGLRENDERER)
|
if (ENABLE_OGLRENDERER)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
GPU_OpenGL.cpp
|
GPU_OpenGL.cpp
|
||||||
GPU_OpenGL_shaders.h
|
GPU_OpenGL_shaders.h
|
||||||
GPU3D_OpenGL.cpp
|
GPU3D_OpenGL.cpp
|
||||||
GPU3D_OpenGL_shaders.h
|
GPU3D_OpenGL_shaders.h
|
||||||
OpenGLSupport.cpp
|
OpenGLSupport.cpp)
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_JIT)
|
if (ENABLE_JIT)
|
||||||
enable_language(ASM)
|
enable_language(ASM)
|
||||||
|
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
ARM_InstrInfo.cpp
|
ARM_InstrInfo.cpp
|
||||||
|
|
||||||
ARMJIT.cpp
|
ARMJIT.cpp
|
||||||
ARMJIT_Memory.cpp
|
ARMJIT_Memory.cpp
|
||||||
|
|
||||||
dolphin/CommonFuncs.cpp
|
dolphin/CommonFuncs.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
if (ARCHITECTURE STREQUAL x86_64)
|
if (ARCHITECTURE STREQUAL x86_64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
dolphin/x64ABI.cpp
|
dolphin/x64ABI.cpp
|
||||||
dolphin/x64CPUDetect.cpp
|
dolphin/x64CPUDetect.cpp
|
||||||
dolphin/x64Emitter.cpp
|
dolphin/x64Emitter.cpp
|
||||||
|
|
||||||
ARMJIT_x64/ARMJIT_Compiler.cpp
|
ARMJIT_x64/ARMJIT_Compiler.cpp
|
||||||
ARMJIT_x64/ARMJIT_ALU.cpp
|
ARMJIT_x64/ARMJIT_ALU.cpp
|
||||||
ARMJIT_x64/ARMJIT_LoadStore.cpp
|
ARMJIT_x64/ARMJIT_LoadStore.cpp
|
||||||
ARMJIT_x64/ARMJIT_Branch.cpp
|
ARMJIT_x64/ARMJIT_Branch.cpp
|
||||||
|
|
||||||
ARMJIT_x64/ARMJIT_Linkage.S
|
ARMJIT_x64/ARMJIT_Linkage.S)
|
||||||
)
|
endif()
|
||||||
endif()
|
if (ARCHITECTURE STREQUAL ARM64)
|
||||||
if (ARCHITECTURE STREQUAL ARM64)
|
target_sources(core PRIVATE
|
||||||
target_sources(core PRIVATE
|
dolphin/Arm64Emitter.cpp
|
||||||
dolphin/Arm64Emitter.cpp
|
dolphin/MathUtil.cpp
|
||||||
dolphin/MathUtil.cpp
|
|
||||||
|
|
||||||
ARMJIT_A64/ARMJIT_Compiler.cpp
|
ARMJIT_A64/ARMJIT_Compiler.cpp
|
||||||
ARMJIT_A64/ARMJIT_ALU.cpp
|
ARMJIT_A64/ARMJIT_ALU.cpp
|
||||||
ARMJIT_A64/ARMJIT_LoadStore.cpp
|
ARMJIT_A64/ARMJIT_LoadStore.cpp
|
||||||
ARMJIT_A64/ARMJIT_Branch.cpp
|
ARMJIT_A64/ARMJIT_Branch.cpp
|
||||||
|
|
||||||
ARMJIT_A64/ARMJIT_Linkage.S
|
ARMJIT_A64/ARMJIT_Linkage.S)
|
||||||
)
|
endif()
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(teakra EXCLUDE_FROM_ALL)
|
add_subdirectory(teakra EXCLUDE_FROM_ALL)
|
||||||
target_link_libraries(core teakra)
|
target_link_libraries(core PRIVATE teakra)
|
||||||
|
|
||||||
|
find_library(m MATH_LIBRARY)
|
||||||
|
|
||||||
|
if (MATH_LIBRARY)
|
||||||
|
target_link_libraries(core PRIVATE ${MATH_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ENABLE_OGLRENDERER)
|
if (ENABLE_OGLRENDERER)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(EPOXY REQUIRED epoxy)
|
pkg_check_modules(Epoxy REQUIRED IMPORTED_TARGET epoxy)
|
||||||
|
fix_interface_includes(PkgConfig::Epoxy)
|
||||||
|
|
||||||
target_include_directories(core PRIVATE ${EPOXY_INCLUDE_DIRS})
|
target_link_libraries(core PUBLIC PkgConfig::Epoxy)
|
||||||
if (WIN32)
|
|
||||||
target_link_libraries(core ole32 comctl32 ws2_32 ${EPOXY_LIBRARIES})
|
target_compile_definitions(core PUBLIC OGLRENDERER_ENABLED)
|
||||||
elseif (APPLE)
|
endif()
|
||||||
target_link_libraries(core ${EPOXY_LIBRARIES})
|
|
||||||
else()
|
if (ENABLE_JIT)
|
||||||
target_link_libraries(core rt ${EPOXY_LIBRARIES})
|
target_compile_definitions(core PUBLIC JIT_ENABLED)
|
||||||
|
|
||||||
|
|
||||||
|
if (ENABLE_JIT_PROFILING)
|
||||||
|
include(cmake/FindVTune.cmake)
|
||||||
|
add_definitions(-DJIT_PROFILING_ENABLED)
|
||||||
endif()
|
endif()
|
||||||
else()
|
endif()
|
||||||
if (WIN32)
|
|
||||||
target_link_libraries(core ole32 comctl32 ws2_32)
|
if (WIN32)
|
||||||
elseif (APPLE)
|
target_link_libraries(core PRIVATE ole32 comctl32 ws2_32)
|
||||||
target_link_libraries(core)
|
elseif(NOT APPLE)
|
||||||
else()
|
target_link_libraries(core PRIVATE rt)
|
||||||
target_link_libraries(core rt)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_JIT_PROFILING)
|
if (ENABLE_JIT_PROFILING)
|
||||||
target_link_libraries(core jitprofiling)
|
target_link_libraries(core PRIVATE jitprofiling)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -134,6 +134,9 @@ void ARMv5::UpdateITCMSetting()
|
||||||
if (CP15Control & (1<<18))
|
if (CP15Control & (1<<18))
|
||||||
{
|
{
|
||||||
ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F);
|
ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F);
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
FastBlockLookupSize = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define DMA_H
|
#define DMA_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
class DMA
|
class DMA
|
||||||
{
|
{
|
||||||
|
@ -96,7 +97,7 @@ private:
|
||||||
bool IsGXFIFODMA;
|
bool IsGXFIFODMA;
|
||||||
|
|
||||||
u32 MRAMBurstCount;
|
u32 MRAMBurstCount;
|
||||||
u8* MRAMBurstTable;
|
const u8* MRAMBurstTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef DMA_TIMINGS_H
|
#ifndef DMA_TIMINGS_H
|
||||||
#define DMA_TIMINGS_H
|
#define DMA_TIMINGS_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace DMATiming
|
namespace DMATiming
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -43,9 +45,9 @@ namespace DMATiming
|
||||||
// setting. Timings are such that the nonseq setting only matters for the first
|
// setting. Timings are such that the nonseq setting only matters for the first
|
||||||
// access, and minor edge cases (like the last of a 0x20000-byte block).
|
// access, and minor edge cases (like the last of a 0x20000-byte block).
|
||||||
|
|
||||||
u8 MRAMDummy[1] = {0};
|
constexpr u8 MRAMDummy[1] = {0};
|
||||||
|
|
||||||
u8 MRAMRead16Bursts[][256] =
|
constexpr u8 MRAMRead16Bursts[][256] =
|
||||||
{
|
{
|
||||||
// main RAM to regular 16bit or 32bit bus (similar)
|
// main RAM to regular 16bit or 32bit bus (similar)
|
||||||
{7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
{7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
@ -119,7 +121,7 @@ u8 MRAMRead16Bursts[][256] =
|
||||||
0},
|
0},
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 MRAMRead32Bursts[][256] =
|
constexpr u8 MRAMRead32Bursts[][256] =
|
||||||
{
|
{
|
||||||
// main RAM to regular 16bit bus
|
// main RAM to regular 16bit bus
|
||||||
{9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
|
{9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
@ -178,7 +180,7 @@ u8 MRAMRead32Bursts[][256] =
|
||||||
0},
|
0},
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 MRAMWrite16Bursts[][256] =
|
constexpr u8 MRAMWrite16Bursts[][256] =
|
||||||
{
|
{
|
||||||
// regular 16bit or 32bit bus to main RAM (similar)
|
// regular 16bit or 32bit bus to main RAM (similar)
|
||||||
{8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
{8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
@ -209,7 +211,7 @@ u8 MRAMWrite16Bursts[][256] =
|
||||||
0},
|
0},
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 MRAMWrite32Bursts[][256] =
|
constexpr u8 MRAMWrite32Bursts[][256] =
|
||||||
{
|
{
|
||||||
// regular 16bit bus to main RAM
|
// regular 16bit bus to main RAM
|
||||||
{9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
{9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
|
156
src/DSi.cpp
156
src/DSi.cpp
|
@ -162,7 +162,7 @@ void Reset()
|
||||||
SCFG_Clock7 = 0x0187;
|
SCFG_Clock7 = 0x0187;
|
||||||
SCFG_EXT[0] = 0x8307F100;
|
SCFG_EXT[0] = 0x8307F100;
|
||||||
SCFG_EXT[1] = 0x93FFFB06;
|
SCFG_EXT[1] = 0x93FFFB06;
|
||||||
SCFG_MC = 0x0010;//0x0011;
|
SCFG_MC = 0x0010 | (~((u32)NDSCart::CartInserted)&1);//0x0011;
|
||||||
SCFG_RST = 0;
|
SCFG_RST = 0;
|
||||||
|
|
||||||
DSi_DSP::SetRstLine(false);
|
DSi_DSP::SetRstLine(false);
|
||||||
|
@ -251,6 +251,14 @@ void DoSavestate(Savestate* file)
|
||||||
SDIO->DoSavestate(file);
|
SDIO->DoSavestate(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetCartInserted(bool inserted)
|
||||||
|
{
|
||||||
|
if (inserted)
|
||||||
|
SCFG_MC &= ~1;
|
||||||
|
else
|
||||||
|
SCFG_MC |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
|
void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
|
||||||
{
|
{
|
||||||
AES_ctx ctx;
|
AES_ctx ctx;
|
||||||
|
@ -506,30 +514,24 @@ void SetupDirectBoot()
|
||||||
ARM9Write32(0x02FFE000+i, tmp);
|
ARM9Write32(0x02FFE000+i, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* nand = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_NANDPath), "r+b");
|
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
|
||||||
if (nand)
|
|
||||||
{
|
{
|
||||||
if (DSi_NAND::Init(nand, &DSi::ARM7iBIOS[0x8308]))
|
u8 userdata[0x1B0];
|
||||||
{
|
DSi_NAND::ReadUserData(userdata);
|
||||||
u8 userdata[0x1B0];
|
for (u32 i = 0; i < 0x128; i+=4)
|
||||||
DSi_NAND::ReadUserData(userdata);
|
ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
|
||||||
for (u32 i = 0; i < 0x128; i+=4)
|
|
||||||
ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
|
|
||||||
|
|
||||||
u8 hwinfoS[0xA4];
|
u8 hwinfoS[0xA4];
|
||||||
u8 hwinfoN[0x9C];
|
u8 hwinfoN[0x9C];
|
||||||
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x14; i+=4)
|
for (u32 i = 0; i < 0x14; i+=4)
|
||||||
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x18; i+=4)
|
for (u32 i = 0; i < 0x18; i+=4)
|
||||||
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
|
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
|
||||||
|
|
||||||
DSi_NAND::DeInit();
|
DSi_NAND::DeInit();
|
||||||
}
|
|
||||||
|
|
||||||
fclose(nand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 nwifiver = SPI_Firmware::GetNWifiVersion();
|
u8 nwifiver = SPI_Firmware::GetNWifiVersion();
|
||||||
|
@ -702,19 +704,14 @@ bool LoadNAND()
|
||||||
{
|
{
|
||||||
printf("Loading DSi NAND\n");
|
printf("Loading DSi NAND\n");
|
||||||
|
|
||||||
FILE* nand = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_NANDPath), "r+b");
|
if (!DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
|
||||||
if (!nand)
|
|
||||||
{
|
|
||||||
printf("Failed to open DSi NAND\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DSi_NAND::Init(nand, &DSi::ARM7iBIOS[0x8308]))
|
|
||||||
{
|
{
|
||||||
printf("Failed to load DSi NAND\n");
|
printf("Failed to load DSi NAND\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE* nand = DSi_NAND::GetFile();
|
||||||
|
|
||||||
// Make sure NWRAM is accessible.
|
// Make sure NWRAM is accessible.
|
||||||
// The Bits are set to the startup values in Reset() and we might
|
// The Bits are set to the startup values in Reset() and we might
|
||||||
// still have them on default (0) or some bits cleared by the previous
|
// still have them on default (0) or some bits cleared by the previous
|
||||||
|
@ -2641,6 +2638,9 @@ u8 ARM7IORead8(u32 addr)
|
||||||
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 48) & 0xFF;
|
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 48) & 0xFF;
|
||||||
case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 56;
|
case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 56;
|
||||||
case 0x04004D08: return 0;
|
case 0x04004D08: return 0;
|
||||||
|
|
||||||
|
case 0x4004700: return DSi_DSP::SNDExCnt;
|
||||||
|
case 0x4004701: return DSi_DSP::SNDExCnt >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NDS::ARM7IORead8(addr);
|
return NDS::ARM7IORead8(addr);
|
||||||
|
@ -2673,6 +2673,8 @@ u16 ARM7IORead16(u32 addr)
|
||||||
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFFFF;
|
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFFFF;
|
||||||
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 48;
|
case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 48;
|
||||||
case 0x04004D08: return 0;
|
case 0x04004D08: return 0;
|
||||||
|
|
||||||
|
case 0x4004700: return DSi_DSP::SNDExCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x04004800 && addr < 0x04004A00)
|
if (addr >= 0x04004800 && addr < 0x04004A00)
|
||||||
|
@ -2744,6 +2746,10 @@ u32 ARM7IORead32(u32 addr)
|
||||||
case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFFFFFF;
|
case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFFFFFF;
|
||||||
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 32;
|
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 32;
|
||||||
case 0x04004D08: return 0;
|
case 0x04004D08: return 0;
|
||||||
|
|
||||||
|
case 0x4004700:
|
||||||
|
printf("32-Bit SNDExCnt read? %08X\n", NDS::ARM7->R[15]);
|
||||||
|
return DSi_DSP::SNDExCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x04004800 && addr < 0x04004A00)
|
if (addr >= 0x04004800 && addr < 0x04004A00)
|
||||||
|
@ -2791,6 +2797,46 @@ void ARM7IOWrite8(u32 addr, u8 val)
|
||||||
|
|
||||||
case 0x04004500: DSi_I2C::WriteData(val); return;
|
case 0x04004500: DSi_I2C::WriteData(val); return;
|
||||||
case 0x04004501: DSi_I2C::WriteCnt(val); return;
|
case 0x04004501: DSi_I2C::WriteCnt(val); return;
|
||||||
|
|
||||||
|
case 0x4004700:
|
||||||
|
DSi_DSP::WriteSNDExCnt((u16)val | (DSi_DSP::SNDExCnt & 0xFF00));
|
||||||
|
return;
|
||||||
|
case 0x4004701:
|
||||||
|
DSi_DSP::WriteSNDExCnt(((u16)val << 8) | (DSi_DSP::SNDExCnt & 0x00FF));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr >= 0x04004420 && addr < 0x04004430)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&3)*8;
|
||||||
|
addr -= 0x04004420;
|
||||||
|
addr &= ~3;
|
||||||
|
DSi_AES::WriteIV(addr, (u32)val << shift, 0xFF << shift);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addr >= 0x04004430 && addr < 0x04004440)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&3)*8;
|
||||||
|
addr -= 0x04004430;
|
||||||
|
addr &= ~3;
|
||||||
|
DSi_AES::WriteMAC(addr, (u32)val << shift, 0xFF << shift);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addr >= 0x04004440 && addr < 0x04004500)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&3)*8;
|
||||||
|
addr -= 0x04004440;
|
||||||
|
addr &= ~3;
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
while (addr >= 0x30) { addr -= 0x30; n++; }
|
||||||
|
|
||||||
|
switch (addr >> 4)
|
||||||
|
{
|
||||||
|
case 0: DSi_AES::WriteKeyNormal(n, addr&0xF, (u32)val << shift, 0xFF << shift); return;
|
||||||
|
case 1: DSi_AES::WriteKeyX(n, addr&0xF, (u32)val << shift, 0xFF << shift); return;
|
||||||
|
case 2: DSi_AES::WriteKeyY(n, addr&0xF, (u32)val << shift, 0xFF << shift); return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NDS::ARM7IOWrite8(addr, val);
|
return NDS::ARM7IOWrite8(addr, val);
|
||||||
|
@ -2822,12 +2868,51 @@ void ARM7IOWrite16(u32 addr, u16 val)
|
||||||
case 0x04004062:
|
case 0x04004062:
|
||||||
if (!(SCFG_EXT[1] & (1 << 31))) /* no access to SCFG Registers if disabled*/
|
if (!(SCFG_EXT[1] & (1 << 31))) /* no access to SCFG Registers if disabled*/
|
||||||
return;
|
return;
|
||||||
u32 tmp = MBK[0][8];
|
{
|
||||||
tmp &= ~(0xffff << ((addr % 4) * 8));
|
u32 tmp = MBK[0][8];
|
||||||
tmp |= (val << ((addr % 4) * 8));
|
tmp &= ~(0xffff << ((addr % 4) * 8));
|
||||||
MBK[0][8] = tmp & 0x00FFFF0F;
|
tmp |= (val << ((addr % 4) * 8));
|
||||||
MBK[1][8] = MBK[0][8];
|
MBK[0][8] = tmp & 0x00FFFF0F;
|
||||||
|
MBK[1][8] = MBK[0][8];
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 0x4004700:
|
||||||
|
DSi_DSP::WriteSNDExCnt(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr >= 0x04004420 && addr < 0x04004430)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&1)*16;
|
||||||
|
addr -= 0x04004420;
|
||||||
|
addr &= ~1;
|
||||||
|
DSi_AES::WriteIV(addr, (u32)val << shift, 0xFFFF << shift);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addr >= 0x04004430 && addr < 0x04004440)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&1)*16;
|
||||||
|
addr -= 0x04004430;
|
||||||
|
addr &= ~1;
|
||||||
|
DSi_AES::WriteMAC(addr, (u32)val << shift, 0xFFFF << shift);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addr >= 0x04004440 && addr < 0x04004500)
|
||||||
|
{
|
||||||
|
u32 shift = (addr&1)*16;
|
||||||
|
addr -= 0x04004440;
|
||||||
|
addr &= ~1;
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
while (addr >= 0x30) { addr -= 0x30; n++; }
|
||||||
|
|
||||||
|
switch (addr >> 4)
|
||||||
|
{
|
||||||
|
case 0: DSi_AES::WriteKeyNormal(n, addr&0xF, (u32)val << shift, 0xFFFF << shift); return;
|
||||||
|
case 1: DSi_AES::WriteKeyX(n, addr&0xF, (u32)val << shift, 0xFFFF << shift); return;
|
||||||
|
case 2: DSi_AES::WriteKeyY(n, addr&0xF, (u32)val << shift, 0xFFFF << shift); return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x04004800 && addr < 0x04004A00)
|
if (addr >= 0x04004800 && addr < 0x04004A00)
|
||||||
|
@ -2927,6 +3012,11 @@ void ARM7IOWrite32(u32 addr, u32 val)
|
||||||
case 0x04004400: DSi_AES::WriteCnt(val); return;
|
case 0x04004400: DSi_AES::WriteCnt(val); return;
|
||||||
case 0x04004404: DSi_AES::WriteBlkCnt(val); return;
|
case 0x04004404: DSi_AES::WriteBlkCnt(val); return;
|
||||||
case 0x04004408: DSi_AES::WriteInputFIFO(val); return;
|
case 0x04004408: DSi_AES::WriteInputFIFO(val); return;
|
||||||
|
|
||||||
|
case 0x4004700:
|
||||||
|
printf("32-Bit SNDExCnt write? %08X %08X\n", val, NDS::ARM7->R[15]);
|
||||||
|
DSi_DSP::WriteSNDExCnt(val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x04004420 && addr < 0x04004430)
|
if (addr >= 0x04004420 && addr < 0x04004430)
|
||||||
|
|
|
@ -59,6 +59,8 @@ void Reset();
|
||||||
|
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
|
void SetCartInserted(bool inserted);
|
||||||
|
|
||||||
void SetupDirectBoot();
|
void SetupDirectBoot();
|
||||||
void SoftReset();
|
void SoftReset();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define DSI_AES_H
|
#define DSI_AES_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
namespace DSi_AES
|
namespace DSi_AES
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define DSI_CAMERA_H
|
#define DSI_CAMERA_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
namespace DSi_CamModule
|
namespace DSi_CamModule
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
namespace DSi_DSP
|
namespace DSi_DSP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// not sure whether to not rather put it somewhere else
|
||||||
|
u16 SNDExCnt;
|
||||||
|
|
||||||
Teakra::Teakra* TeakraCore;
|
Teakra::Teakra* TeakraCore;
|
||||||
|
|
||||||
bool SCFG_RST;
|
bool SCFG_RST;
|
||||||
|
@ -151,6 +154,8 @@ void Reset()
|
||||||
TeakraCore->Reset();
|
TeakraCore->Reset();
|
||||||
|
|
||||||
NDS::CancelEvent(NDS::Event_DSi_DSP);
|
NDS::CancelEvent(NDS::Event_DSi_DSP);
|
||||||
|
|
||||||
|
SNDExCnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRstReleased()
|
bool IsRstReleased()
|
||||||
|
@ -548,6 +553,21 @@ void Write32(u32 addr, u32 val)
|
||||||
Write16(addr, val & 0xFFFF);
|
Write16(addr, val & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteSNDExCnt(u16 val)
|
||||||
|
{
|
||||||
|
// it can be written even in NDS mode
|
||||||
|
|
||||||
|
// mic frequency can only be changed if it was disabled
|
||||||
|
// before the write
|
||||||
|
if (SNDExCnt & 0x8000)
|
||||||
|
{
|
||||||
|
val &= ~0x2000;
|
||||||
|
val |= SNDExCnt & 0x2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
SNDExCnt = val & 0xE00F;
|
||||||
|
}
|
||||||
|
|
||||||
void Run(u32 cycles)
|
void Run(u32 cycles)
|
||||||
{
|
{
|
||||||
if (!IsDSPCoreEnabled())
|
if (!IsDSPCoreEnabled())
|
||||||
|
|
|
@ -19,13 +19,17 @@
|
||||||
#ifndef DSI_DSP_H
|
#ifndef DSI_DSP_H
|
||||||
#define DSI_DSP_H
|
#define DSI_DSP_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
// TODO: for actual sound output
|
// TODO: for actual sound output
|
||||||
// * audio callbacks
|
// * audio callbacks
|
||||||
// * SNDEXCNT
|
|
||||||
|
|
||||||
namespace DSi_DSP
|
namespace DSi_DSP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
extern u16 SNDExCnt;
|
||||||
|
|
||||||
extern u16 DSP_PDATA;
|
extern u16 DSP_PDATA;
|
||||||
extern u16 DSP_PADR;
|
extern u16 DSP_PADR;
|
||||||
extern u16 DSP_PCFG;
|
extern u16 DSP_PCFG;
|
||||||
|
@ -62,6 +66,8 @@ void Write16(u32 addr, u16 val);
|
||||||
u32 Read32(u32 addr);
|
u32 Read32(u32 addr);
|
||||||
void Write32(u32 addr, u32 val);
|
void Write32(u32 addr, u32 val);
|
||||||
|
|
||||||
|
void WriteSNDExCnt(u16 val);
|
||||||
|
|
||||||
// NOTE: checks SCFG_CLK9
|
// NOTE: checks SCFG_CLK9
|
||||||
void Run(u32 cycles);
|
void Run(u32 cycles);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define DSI_I2C_H
|
#define DSI_I2C_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
namespace DSi_BPTWL
|
namespace DSi_BPTWL
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,8 +49,48 @@ UINT FF_ReadNAND(BYTE* buf, LBA_t sector, UINT num);
|
||||||
UINT FF_WriteNAND(BYTE* buf, LBA_t sector, UINT num);
|
UINT FF_WriteNAND(BYTE* buf, LBA_t sector, UINT num);
|
||||||
|
|
||||||
|
|
||||||
bool Init(FILE* nandfile, u8* es_keyY)
|
bool Init(u8* es_keyY)
|
||||||
{
|
{
|
||||||
|
CurFile = nullptr;
|
||||||
|
|
||||||
|
std::string nandpath = Platform::GetConfigString(Platform::DSi_NANDPath);
|
||||||
|
std::string instnand = nandpath + Platform::InstanceFileSuffix();
|
||||||
|
|
||||||
|
FILE* nandfile = Platform::OpenLocalFile(instnand, "r+b");
|
||||||
|
if ((!nandfile) && (Platform::InstanceID() > 0))
|
||||||
|
{
|
||||||
|
FILE* orig = Platform::OpenLocalFile(nandpath, "rb");
|
||||||
|
if (!orig)
|
||||||
|
{
|
||||||
|
printf("Failed to open DSi NAND\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(orig, 0, SEEK_END);
|
||||||
|
long len = ftell(orig);
|
||||||
|
fseek(orig, 0, SEEK_SET);
|
||||||
|
|
||||||
|
nandfile = Platform::OpenLocalFile(instnand, "w+b");
|
||||||
|
if (nandfile)
|
||||||
|
{
|
||||||
|
u8* tmpbuf = new u8[0x10000];
|
||||||
|
for (long i = 0; i < len; i+=0x10000)
|
||||||
|
{
|
||||||
|
long blklen = 0x10000;
|
||||||
|
if ((i+blklen) > len) blklen = len-i;
|
||||||
|
|
||||||
|
fread(tmpbuf, blklen, 1, orig);
|
||||||
|
fwrite(tmpbuf, blklen, 1, nandfile);
|
||||||
|
}
|
||||||
|
delete[] tmpbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(orig);
|
||||||
|
fclose(nandfile);
|
||||||
|
|
||||||
|
nandfile = Platform::OpenLocalFile(instnand, "r+b");
|
||||||
|
}
|
||||||
|
|
||||||
if (!nandfile)
|
if (!nandfile)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -138,10 +178,17 @@ void DeInit()
|
||||||
f_unmount("0:");
|
f_unmount("0:");
|
||||||
ff_disk_close();
|
ff_disk_close();
|
||||||
|
|
||||||
|
if (CurFile) fclose(CurFile);
|
||||||
CurFile = nullptr;
|
CurFile = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FILE* GetFile()
|
||||||
|
{
|
||||||
|
return CurFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GetIDs(u8* emmc_cid, u64& consoleid)
|
void GetIDs(u8* emmc_cid, u64& consoleid)
|
||||||
{
|
{
|
||||||
memcpy(emmc_cid, eMMC_CID, 16);
|
memcpy(emmc_cid, eMMC_CID, 16);
|
||||||
|
|
|
@ -34,9 +34,11 @@ enum
|
||||||
TitleData_BannerSav,
|
TitleData_BannerSav,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Init(FILE* nand, u8* es_keyY);
|
bool Init(u8* es_keyY);
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
|
FILE* GetFile();
|
||||||
|
|
||||||
void GetIDs(u8* emmc_cid, u64& consoleid);
|
void GetIDs(u8* emmc_cid, u64& consoleid);
|
||||||
|
|
||||||
void ReadHardwareInfo(u8* dataS, u8* dataN);
|
void ReadHardwareInfo(u8* dataS, u8* dataN);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define DSI_NDMA_H
|
#define DSI_NDMA_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
class DSi_NDMA
|
class DSi_NDMA
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "DSi_SD.h"
|
#include "DSi_SD.h"
|
||||||
#include "FIFO.h"
|
#include "FIFO.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
class DSi_NWifi : public DSi_SDDevice
|
class DSi_NWifi : public DSi_SDDevice
|
||||||
{
|
{
|
||||||
|
|
|
@ -136,7 +136,10 @@ void DSi_SDHost::Reset()
|
||||||
else
|
else
|
||||||
sd = nullptr;
|
sd = nullptr;
|
||||||
|
|
||||||
mmc = new DSi_MMCStorage(this, true, Platform::GetConfigString(Platform::DSi_NANDPath));
|
std::string nandpath = Platform::GetConfigString(Platform::DSi_NANDPath);
|
||||||
|
std::string instnand = nandpath + Platform::InstanceFileSuffix();
|
||||||
|
|
||||||
|
mmc = new DSi_MMCStorage(this, true, instnand);
|
||||||
mmc->SetCID(DSi::eMMC_CID);
|
mmc->SetCID(DSi::eMMC_CID);
|
||||||
|
|
||||||
Ports[0] = sd;
|
Ports[0] = sd;
|
||||||
|
@ -477,16 +480,14 @@ u16 DSi_SDHost::Read(u32 addr)
|
||||||
{
|
{
|
||||||
if (Ports[0]) // basic check of whether the SD card is inserted
|
if (Ports[0]) // basic check of whether the SD card is inserted
|
||||||
{
|
{
|
||||||
ret |= 0x0030;
|
ret |= 0x0020;
|
||||||
if (!Ports[0]->ReadOnly) ret |= 0x0080;
|
if (!Ports[0]->ReadOnly) ret |= 0x0080;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
ret |= 0x0008;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// SDIO wifi is always inserted, I guess
|
// SDIO wifi is always inserted, I guess
|
||||||
ret |= 0x00B0;
|
ret |= 0x00A0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
#ifndef DSI_SD_H
|
#ifndef DSI_SD_H
|
||||||
#define DSI_SD_H
|
#define DSI_SD_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
#include "FIFO.h"
|
#include "FIFO.h"
|
||||||
#include "FATStorage.h"
|
#include "FATStorage.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
class DSi_SDDevice;
|
class DSi_SDDevice;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
#ifndef DSI_SPI_TSC
|
#ifndef DSI_SPI_TSC
|
||||||
#define DSI_SPI_TSC
|
#define DSI_SPI_TSC
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
namespace DSi_SPI_TSC
|
namespace DSi_SPI_TSC
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define FIFO_H
|
#define FIFO_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
|
|
||||||
template<typename T, u32 NumEntries>
|
template<typename T, u32 NumEntries>
|
||||||
class FIFO
|
class FIFO
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "GPU.h"
|
#include "GPU.h"
|
||||||
|
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
#include "ARMJIT.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "GPU2D_Soft.h"
|
#include "GPU2D_Soft.h"
|
||||||
|
|
||||||
namespace GPU
|
namespace GPU
|
||||||
|
@ -653,6 +657,9 @@ void MapVRAM_CD(u32 bank, u8 cnt)
|
||||||
VRAMMap_ARM7[ofs] |= bankmask;
|
VRAMMap_ARM7[ofs] |= bankmask;
|
||||||
memset(VRAMDirty[bank].Data, 0xFF, sizeof(VRAMDirty[bank].Data));
|
memset(VRAMDirty[bank].Data, 0xFF, sizeof(VRAMDirty[bank].Data));
|
||||||
VRAMSTAT |= (1 << (bank-2));
|
VRAMSTAT |= (1 << (bank-2));
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
ARMJIT::CheckAndInvalidateWVRAM(ofs);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // texture
|
case 3: // texture
|
||||||
|
|
|
@ -153,14 +153,14 @@ void GLCompositor::SetRenderSettings(RenderSettings& settings)
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]);
|
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
// fill the padding
|
// fill the padding
|
||||||
u8 zeroPixels[ScreenW*2*scale*4];
|
u8* zeroPixels = (u8*) calloc(1, ScreenW*2*scale*4);
|
||||||
memset(zeroPixels, 0, sizeof(zeroPixels));
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192*scale, ScreenW, 2*scale, GL_RGBA, GL_UNSIGNED_BYTE, zeroPixels);
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192*scale, ScreenW, 2*scale, GL_RGBA, GL_UNSIGNED_BYTE, zeroPixels);
|
||||||
|
|
||||||
GLenum fbassign[] = {GL_COLOR_ATTACHMENT0};
|
GLenum fbassign[] = {GL_COLOR_ATTACHMENT0};
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB[i]);
|
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB[i]);
|
||||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex[i], 0);
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex[i], 0);
|
||||||
glDrawBuffers(1, fbassign);
|
glDrawBuffers(1, fbassign);
|
||||||
|
free(zeroPixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
123
src/NDS.cpp
123
src/NDS.cpp
|
@ -176,6 +176,7 @@ bool RunningGame;
|
||||||
void DivDone(u32 param);
|
void DivDone(u32 param);
|
||||||
void SqrtDone(u32 param);
|
void SqrtDone(u32 param);
|
||||||
void RunTimer(u32 tid, s32 cycles);
|
void RunTimer(u32 tid, s32 cycles);
|
||||||
|
void UpdateWifiTimings();
|
||||||
void SetWifiWaitCnt(u16 val);
|
void SetWifiWaitCnt(u16 val);
|
||||||
void SetGBASlotTimings();
|
void SetGBASlotTimings();
|
||||||
|
|
||||||
|
@ -892,9 +893,7 @@ bool DoSavestate(Savestate* file)
|
||||||
InitTimings();
|
InitTimings();
|
||||||
SetGBASlotTimings();
|
SetGBASlotTimings();
|
||||||
|
|
||||||
u16 tmp = WifiWaitCnt;
|
UpdateWifiTimings();
|
||||||
WifiWaitCnt = 0xFFFF;
|
|
||||||
SetWifiWaitCnt(tmp); // force timing table update
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
|
@ -918,6 +917,9 @@ bool DoSavestate(Savestate* file)
|
||||||
if (!file->Saving)
|
if (!file->Saving)
|
||||||
{
|
{
|
||||||
GPU::SetPowerCnt(PowerControl9);
|
GPU::SetPowerCnt(PowerControl9);
|
||||||
|
|
||||||
|
SPU::SetPowerCnt(PowerControl7 & 0x0001);
|
||||||
|
Wifi::SetPowerCnt(PowerControl7 & 0x0002);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
|
@ -1198,6 +1200,25 @@ void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 para
|
||||||
Reschedule(evt->Timestamp);
|
Reschedule(evt->Timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduleEvent(u32 id, u64 timestamp, void (*func)(u32), u32 param)
|
||||||
|
{
|
||||||
|
if (SchedListMask & (1<<id))
|
||||||
|
{
|
||||||
|
printf("!! EVENT %d ALREADY SCHEDULED\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SchedEvent* evt = &SchedList[id];
|
||||||
|
|
||||||
|
evt->Timestamp = timestamp;
|
||||||
|
evt->Func = func;
|
||||||
|
evt->Param = param;
|
||||||
|
|
||||||
|
SchedListMask |= (1<<id);
|
||||||
|
|
||||||
|
Reschedule(evt->Timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
void CancelEvent(u32 id)
|
void CancelEvent(u32 id)
|
||||||
{
|
{
|
||||||
SchedListMask &= ~(1<<id);
|
SchedListMask &= ~(1<<id);
|
||||||
|
@ -1338,15 +1359,29 @@ void MapSharedWRAM(u8 val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateWifiTimings()
|
||||||
|
{
|
||||||
|
if (PowerControl7 & 0x0002)
|
||||||
|
{
|
||||||
|
const int ntimings[4] = {10, 8, 6, 18};
|
||||||
|
u16 val = WifiWaitCnt;
|
||||||
|
|
||||||
|
SetARM7RegionTimings(0x04800, 0x04808, Mem7_Wifi0, 16, ntimings[val & 0x3], (val & 0x4) ? 4 : 6);
|
||||||
|
SetARM7RegionTimings(0x04808, 0x04810, Mem7_Wifi1, 16, ntimings[(val>>3) & 0x3], (val & 0x20) ? 4 : 10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetARM7RegionTimings(0x04800, 0x04808, Mem7_Wifi0, 32, 1, 1);
|
||||||
|
SetARM7RegionTimings(0x04808, 0x04810, Mem7_Wifi1, 32, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetWifiWaitCnt(u16 val)
|
void SetWifiWaitCnt(u16 val)
|
||||||
{
|
{
|
||||||
if (WifiWaitCnt == val) return;
|
if (WifiWaitCnt == val) return;
|
||||||
|
|
||||||
WifiWaitCnt = val;
|
WifiWaitCnt = val;
|
||||||
|
UpdateWifiTimings();
|
||||||
const int ntimings[4] = {10, 8, 6, 18};
|
|
||||||
SetARM7RegionTimings(0x04800, 0x04808, Mem7_Wifi0, 16, ntimings[val & 0x3], (val & 0x4) ? 4 : 6);
|
|
||||||
SetARM7RegionTimings(0x04808, 0x04810, Mem7_Wifi1, 16, ntimings[(val>>3) & 0x3], (val & 0x20) ? 4 : 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGBASlotTimings()
|
void SetGBASlotTimings()
|
||||||
|
@ -1956,8 +1991,8 @@ void debug(u32 param)
|
||||||
//for (int i = 0; i < 9; i++)
|
//for (int i = 0; i < 9; i++)
|
||||||
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
|
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
|
||||||
|
|
||||||
/*FILE*
|
FILE*
|
||||||
shit = fopen("debug/construct.bin", "wb");
|
shit = fopen("debug/inazuma.bin", "wb");
|
||||||
fwrite(ARM9->ITCM, 0x8000, 1, shit);
|
fwrite(ARM9->ITCM, 0x8000, 1, shit);
|
||||||
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
|
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
|
||||||
{
|
{
|
||||||
|
@ -1969,9 +2004,14 @@ void debug(u32 param)
|
||||||
u32 val = ARM7Read32(i);
|
u32 val = ARM7Read32(i);
|
||||||
fwrite(&val, 4, 1, shit);
|
fwrite(&val, 4, 1, shit);
|
||||||
}
|
}
|
||||||
fclose(shit);*/
|
for (u32 i = 0x06000000; i < 0x06040000; i+=4)
|
||||||
|
{
|
||||||
|
u32 val = ARM7Read32(i);
|
||||||
|
fwrite(&val, 4, 1, shit);
|
||||||
|
}
|
||||||
|
fclose(shit);
|
||||||
|
|
||||||
FILE*
|
/*FILE*
|
||||||
shit = fopen("debug/camera9.bin", "wb");
|
shit = fopen("debug/camera9.bin", "wb");
|
||||||
for (u32 i = 0x02000000; i < 0x04000000; i+=4)
|
for (u32 i = 0x02000000; i < 0x04000000; i+=4)
|
||||||
{
|
{
|
||||||
|
@ -1985,7 +2025,7 @@ void debug(u32 param)
|
||||||
u32 val = DSi::ARM7Read32(i);
|
u32 val = DSi::ARM7Read32(i);
|
||||||
fwrite(&val, 4, 1, shit);
|
fwrite(&val, 4, 1, shit);
|
||||||
}
|
}
|
||||||
fclose(shit);
|
fclose(shit);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2411,6 +2451,7 @@ u8 ARM7Read8(u32 addr)
|
||||||
case 0x04800000:
|
case 0x04800000:
|
||||||
if (addr < 0x04810000)
|
if (addr < 0x04810000)
|
||||||
{
|
{
|
||||||
|
if (!(PowerControl7 & (1<<1))) return 0;
|
||||||
if (addr & 0x1) return Wifi::Read(addr-1) >> 8;
|
if (addr & 0x1) return Wifi::Read(addr-1) >> 8;
|
||||||
return Wifi::Read(addr) & 0xFF;
|
return Wifi::Read(addr) & 0xFF;
|
||||||
}
|
}
|
||||||
|
@ -2475,6 +2516,7 @@ u16 ARM7Read16(u32 addr)
|
||||||
case 0x04800000:
|
case 0x04800000:
|
||||||
if (addr < 0x04810000)
|
if (addr < 0x04810000)
|
||||||
{
|
{
|
||||||
|
if (!(PowerControl7 & (1<<1))) return 0;
|
||||||
return Wifi::Read(addr);
|
return Wifi::Read(addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2538,6 +2580,7 @@ u32 ARM7Read32(u32 addr)
|
||||||
case 0x04800000:
|
case 0x04800000:
|
||||||
if (addr < 0x04810000)
|
if (addr < 0x04810000)
|
||||||
{
|
{
|
||||||
|
if (!(PowerControl7 & (1<<1))) return 0;
|
||||||
return Wifi::Read(addr) | (Wifi::Read(addr+2) << 16);
|
return Wifi::Read(addr) | (Wifi::Read(addr+2) << 16);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2629,7 +2672,8 @@ void ARM7Write8(u32 addr, u8 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARM7->R[15] > 0x00002F30) // ARM7 BIOS bug
|
//if (ARM7->R[15] > 0x00002F30) // ARM7 BIOS bug
|
||||||
|
if (addr >= 0x01000000)
|
||||||
printf("unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]);
|
printf("unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2677,6 +2721,7 @@ void ARM7Write16(u32 addr, u16 val)
|
||||||
case 0x04800000:
|
case 0x04800000:
|
||||||
if (addr < 0x04810000)
|
if (addr < 0x04810000)
|
||||||
{
|
{
|
||||||
|
if (!(PowerControl7 & (1<<1))) return;
|
||||||
Wifi::Write(addr, val);
|
Wifi::Write(addr, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2706,7 +2751,8 @@ void ARM7Write16(u32 addr, u16 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown arm7 write16 %08X %04X @ %08X\n", addr, val, ARM7->R[15]);
|
if (addr >= 0x01000000)
|
||||||
|
printf("unknown arm7 write16 %08X %04X @ %08X\n", addr, val, ARM7->R[15]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM7Write32(u32 addr, u32 val)
|
void ARM7Write32(u32 addr, u32 val)
|
||||||
|
@ -2753,6 +2799,7 @@ void ARM7Write32(u32 addr, u32 val)
|
||||||
case 0x04800000:
|
case 0x04800000:
|
||||||
if (addr < 0x04810000)
|
if (addr < 0x04810000)
|
||||||
{
|
{
|
||||||
|
if (!(PowerControl7 & (1<<1))) return;
|
||||||
Wifi::Write(addr, val & 0xFFFF);
|
Wifi::Write(addr, val & 0xFFFF);
|
||||||
Wifi::Write(addr+2, val >> 16);
|
Wifi::Write(addr+2, val >> 16);
|
||||||
return;
|
return;
|
||||||
|
@ -2786,7 +2833,8 @@ void ARM7Write32(u32 addr, u32 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]);
|
if (addr >= 0x01000000)
|
||||||
|
printf("unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
|
bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
|
||||||
|
@ -2946,7 +2994,8 @@ u8 ARM9IORead8(u32 addr)
|
||||||
return (u8)(emuID[idx]);
|
return (u8)(emuID[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3092,7 +3141,8 @@ u16 ARM9IORead16(u32 addr)
|
||||||
return GPU3D::Read16(addr);
|
return GPU3D::Read16(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM9 IO read16 %08X %08X\n", addr, ARM9->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM9 IO read16 %08X %08X\n", addr, ARM9->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3235,7 +3285,8 @@ u32 ARM9IORead32(u32 addr)
|
||||||
return GPU3D::Read32(addr);
|
return GPU3D::Read32(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM9 IO read32 %08X %08X\n", addr, ARM9->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM9 IO read32 %08X %08X\n", addr, ARM9->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3763,6 +3814,7 @@ u8 ARM7IORead8(u32 addr)
|
||||||
case 0x04000241: return WRAMCnt;
|
case 0x04000241: return WRAMCnt;
|
||||||
|
|
||||||
case 0x04000300: return PostFlag7;
|
case 0x04000300: return PostFlag7;
|
||||||
|
case 0x04000304: return PowerControl7;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x04000400 && addr < 0x04000520)
|
if (addr >= 0x04000400 && addr < 0x04000520)
|
||||||
|
@ -3770,7 +3822,8 @@ u8 ARM7IORead8(u32 addr)
|
||||||
return SPU::Read8(addr);
|
return SPU::Read8(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM7 IO read8 %08X %08X\n", addr, ARM7->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM7 IO read8 %08X %08X\n", addr, ARM7->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3845,7 +3898,9 @@ u16 ARM7IORead16(u32 addr)
|
||||||
case 0x040001C2: return SPI::ReadData();
|
case 0x040001C2: return SPI::ReadData();
|
||||||
|
|
||||||
case 0x04000204: return ExMemCnt[1];
|
case 0x04000204: return ExMemCnt[1];
|
||||||
case 0x04000206: return WifiWaitCnt;
|
case 0x04000206:
|
||||||
|
if (!(PowerControl7 & (1<<1))) return 0;
|
||||||
|
return WifiWaitCnt;
|
||||||
|
|
||||||
case 0x04000208: return IME[1];
|
case 0x04000208: return IME[1];
|
||||||
case 0x04000210: return IE[1] & 0xFFFF;
|
case 0x04000210: return IE[1] & 0xFFFF;
|
||||||
|
@ -3861,7 +3916,8 @@ u16 ARM7IORead16(u32 addr)
|
||||||
return SPU::Read16(addr);
|
return SPU::Read16(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM7->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM7->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3927,6 +3983,7 @@ u32 ARM7IORead32(u32 addr)
|
||||||
case 0x04000210: return IE[1];
|
case 0x04000210: return IE[1];
|
||||||
case 0x04000214: return IF[1];
|
case 0x04000214: return IF[1];
|
||||||
|
|
||||||
|
case 0x04000304: return PowerControl7;
|
||||||
case 0x04000308: return ARM7BIOSProt;
|
case 0x04000308: return ARM7BIOSProt;
|
||||||
|
|
||||||
case 0x04100000:
|
case 0x04100000:
|
||||||
|
@ -3960,7 +4017,8 @@ u32 ARM7IORead32(u32 addr)
|
||||||
return SPU::Read32(addr);
|
return SPU::Read32(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("unknown ARM7 IO read32 %08X %08X\n", addr, ARM7->R[15]);
|
if ((addr & 0xFFFFF000) != 0x04004000)
|
||||||
|
printf("unknown ARM7 IO read32 %08X %08X\n", addr, ARM7->R[15]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4155,6 +4213,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 0x04000206:
|
case 0x04000206:
|
||||||
|
if (!(PowerControl7 & (1<<1))) return;
|
||||||
SetWifiWaitCnt(val);
|
SetWifiWaitCnt(val);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -4170,7 +4229,15 @@ void ARM7IOWrite16(u32 addr, u16 val)
|
||||||
PostFlag7 = val & 0x01;
|
PostFlag7 = val & 0x01;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x04000304: PowerControl7 = val; return;
|
case 0x04000304:
|
||||||
|
{
|
||||||
|
u16 change = PowerControl7 ^ val;
|
||||||
|
PowerControl7 = val & 0x0003;
|
||||||
|
SPU::SetPowerCnt(val & 0x0001);
|
||||||
|
Wifi::SetPowerCnt(val & 0x0002);
|
||||||
|
if (change & 0x0002) UpdateWifiTimings();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x04000308:
|
case 0x04000308:
|
||||||
if (ARM7BIOSProt == 0)
|
if (ARM7BIOSProt == 0)
|
||||||
|
@ -4292,7 +4359,15 @@ void ARM7IOWrite32(u32 addr, u32 val)
|
||||||
case 0x04000210: IE[1] = val; UpdateIRQ(1); return;
|
case 0x04000210: IE[1] = val; UpdateIRQ(1); return;
|
||||||
case 0x04000214: IF[1] &= ~val; UpdateIRQ(1); return;
|
case 0x04000214: IF[1] &= ~val; UpdateIRQ(1); return;
|
||||||
|
|
||||||
case 0x04000304: PowerControl7 = val & 0xFFFF; return;
|
case 0x04000304:
|
||||||
|
{
|
||||||
|
u16 change = PowerControl7 ^ val;
|
||||||
|
PowerControl7 = val & 0x0003;
|
||||||
|
SPU::SetPowerCnt(val & 0x0001);
|
||||||
|
Wifi::SetPowerCnt(val & 0x0002);
|
||||||
|
if (change & 0x0002) UpdateWifiTimings();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
case 0x04000308:
|
case 0x04000308:
|
||||||
if (ARM7BIOSProt == 0)
|
if (ARM7BIOSProt == 0)
|
||||||
|
|
|
@ -264,6 +264,7 @@ void CamInputFrame(int cam, u32* data, int width, int height, bool rgb);
|
||||||
void MicInputFrame(s16* data, int samples);
|
void MicInputFrame(s16* data, int samples);
|
||||||
|
|
||||||
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
|
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
|
||||||
|
void ScheduleEvent(u32 id, u64 timestamp, void (*func)(u32), u32 param);
|
||||||
void CancelEvent(u32 id);
|
void CancelEvent(u32 id);
|
||||||
|
|
||||||
void debug(u32 p);
|
void debug(u32 p);
|
||||||
|
|
|
@ -1584,6 +1584,9 @@ bool LoadROM(const u8* romdata, u32 romlen)
|
||||||
if (CartInserted)
|
if (CartInserted)
|
||||||
EjectCart();
|
EjectCart();
|
||||||
|
|
||||||
|
memset(&Header, 0, sizeof(Header));
|
||||||
|
memset(&Banner, 0, sizeof(Banner));
|
||||||
|
|
||||||
CartROMSize = 0x200;
|
CartROMSize = 0x200;
|
||||||
while (CartROMSize < romlen)
|
while (CartROMSize < romlen)
|
||||||
CartROMSize <<= 1;
|
CartROMSize <<= 1;
|
||||||
|
@ -1602,7 +1605,15 @@ bool LoadROM(const u8* romdata, u32 romlen)
|
||||||
memcpy(CartROM, romdata, romlen);
|
memcpy(CartROM, romdata, romlen);
|
||||||
|
|
||||||
memcpy(&Header, CartROM, sizeof(Header));
|
memcpy(&Header, CartROM, sizeof(Header));
|
||||||
memcpy(&Banner, CartROM + Header.BannerOffset, sizeof(Banner));
|
|
||||||
|
u8 unitcode = Header.UnitCode;
|
||||||
|
bool dsi = (unitcode & 0x02) != 0;
|
||||||
|
|
||||||
|
size_t bannersize = dsi ? 0x23C0 : 0xA40;
|
||||||
|
if (Header.BannerOffset >= 0x200 && Header.BannerOffset < (CartROMSize - bannersize))
|
||||||
|
{
|
||||||
|
memcpy(&Banner, CartROM + Header.BannerOffset, bannersize);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Game code: %.4s\n", Header.GameCode);
|
printf("Game code: %.4s\n", Header.GameCode);
|
||||||
|
|
||||||
|
@ -1611,9 +1622,6 @@ bool LoadROM(const u8* romdata, u32 romlen)
|
||||||
(u32)Header.GameCode[1] << 8 |
|
(u32)Header.GameCode[1] << 8 |
|
||||||
(u32)Header.GameCode[0];
|
(u32)Header.GameCode[0];
|
||||||
|
|
||||||
u8 unitcode = Header.UnitCode;
|
|
||||||
bool dsi = (unitcode & 0x02) != 0;
|
|
||||||
|
|
||||||
u32 arm9base = Header.ARM9ROMOffset;
|
u32 arm9base = Header.ARM9ROMOffset;
|
||||||
bool homebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
|
bool homebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
|
||||||
|
|
||||||
|
@ -1679,6 +1687,7 @@ bool LoadROM(const u8* romdata, u32 romlen)
|
||||||
}
|
}
|
||||||
|
|
||||||
CartInserted = true;
|
CartInserted = true;
|
||||||
|
DSi::SetCartInserted(true);
|
||||||
|
|
||||||
u32 irversion = 0;
|
u32 irversion = 0;
|
||||||
if ((gamecode & 0xFF) == 'I')
|
if ((gamecode & 0xFF) == 'I')
|
||||||
|
@ -1738,6 +1747,8 @@ void EjectCart()
|
||||||
CartROMSize = 0;
|
CartROMSize = 0;
|
||||||
CartID = 0;
|
CartID = 0;
|
||||||
|
|
||||||
|
DSi::SetCartInserted(false);
|
||||||
|
|
||||||
// CHECKME: does an eject imply anything for the ROM/SPI transfer registers?
|
// CHECKME: does an eject imply anything for the ROM/SPI transfer registers?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Savestate.h"
|
||||||
#include "NDS_Header.h"
|
#include "NDS_Header.h"
|
||||||
#include "FATStorage.h"
|
#include "FATStorage.h"
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,10 @@ void DeInit();
|
||||||
|
|
||||||
void StopEmu();
|
void StopEmu();
|
||||||
|
|
||||||
|
// instance ID, for local multiplayer
|
||||||
|
int InstanceID();
|
||||||
|
std::string InstanceFileSuffix();
|
||||||
|
|
||||||
// configuration values
|
// configuration values
|
||||||
|
|
||||||
enum ConfigEntry
|
enum ConfigEntry
|
||||||
|
@ -77,7 +81,6 @@ enum ConfigEntry
|
||||||
Firm_Color,
|
Firm_Color,
|
||||||
Firm_Message,
|
Firm_Message,
|
||||||
Firm_MAC,
|
Firm_MAC,
|
||||||
Firm_RandomizeMAC,
|
|
||||||
|
|
||||||
AudioBitrate,
|
AudioBitrate,
|
||||||
};
|
};
|
||||||
|
@ -158,8 +161,16 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
|
||||||
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
|
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
|
||||||
bool MP_Init();
|
bool MP_Init();
|
||||||
void MP_DeInit();
|
void MP_DeInit();
|
||||||
int MP_SendPacket(u8* data, int len);
|
void MP_Begin();
|
||||||
int MP_RecvPacket(u8* data, bool block);
|
void MP_End();
|
||||||
|
int MP_SendPacket(u8* data, int len, u64 timestamp);
|
||||||
|
int MP_RecvPacket(u8* data, u64* timestamp);
|
||||||
|
int MP_SendCmd(u8* data, int len, u64 timestamp);
|
||||||
|
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid);
|
||||||
|
int MP_SendAck(u8* data, int len, u64 timestamp);
|
||||||
|
int MP_RecvHostPacket(u8* data, u64* timestamp);
|
||||||
|
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask);
|
||||||
|
|
||||||
|
|
||||||
// LAN comm interface
|
// LAN comm interface
|
||||||
// packet type: Ethernet (802.3)
|
// packet type: Ethernet (802.3)
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef ROMLIST_H
|
#ifndef ROMLIST_H
|
||||||
#define ROMLIST_H
|
#define ROMLIST_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
struct ROMListEntry
|
struct ROMListEntry
|
||||||
{
|
{
|
||||||
u32 GameCode;
|
u32 GameCode;
|
||||||
|
|
55
src/SPI.cpp
55
src/SPI.cpp
|
@ -215,7 +215,8 @@ void LoadDefaultFirmware()
|
||||||
// wifi access points
|
// wifi access points
|
||||||
// TODO: WFC ID??
|
// TODO: WFC ID??
|
||||||
|
|
||||||
FILE* f = Platform::OpenLocalFile("wfcsettings.bin", "rb");
|
FILE* f = Platform::OpenLocalFile("wfcsettings.bin"+Platform::InstanceFileSuffix(), "rb");
|
||||||
|
if (!f) f = Platform::OpenLocalFile("wfcsettings.bin", "rb");
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
u32 apdata = userdata - 0xA00;
|
u32 apdata = userdata - 0xA00;
|
||||||
|
@ -259,7 +260,7 @@ void LoadDefaultFirmware()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFirmwareFromFile(FILE* f)
|
void LoadFirmwareFromFile(FILE* f, bool makecopy)
|
||||||
{
|
{
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
|
|
||||||
|
@ -271,7 +272,9 @@ void LoadFirmwareFromFile(FILE* f)
|
||||||
fread(Firmware, 1, FirmwareLength, f);
|
fread(Firmware, 1, FirmwareLength, f);
|
||||||
|
|
||||||
// take a backup
|
// take a backup
|
||||||
std::string fwBackupPath = FirmwarePath + ".bak";
|
std::string fwBackupPath;
|
||||||
|
if (!makecopy) fwBackupPath = FirmwarePath + ".bak";
|
||||||
|
else fwBackupPath = FirmwarePath;
|
||||||
FILE* bf = Platform::OpenLocalFile(fwBackupPath, "rb");
|
FILE* bf = Platform::OpenLocalFile(fwBackupPath, "rb");
|
||||||
if (!bf)
|
if (!bf)
|
||||||
{
|
{
|
||||||
|
@ -333,15 +336,24 @@ void Reset()
|
||||||
else
|
else
|
||||||
FirmwarePath = Platform::GetConfigString(Platform::FirmwarePath);
|
FirmwarePath = Platform::GetConfigString(Platform::FirmwarePath);
|
||||||
|
|
||||||
|
bool makecopy = false;
|
||||||
|
std::string origpath = FirmwarePath;
|
||||||
|
FirmwarePath += Platform::InstanceFileSuffix();
|
||||||
|
|
||||||
FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb");
|
FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb");
|
||||||
if (!f)
|
if (!f)
|
||||||
|
{
|
||||||
|
f = Platform::OpenLocalFile(origpath, "rb");
|
||||||
|
makecopy = true;
|
||||||
|
}
|
||||||
|
if (!f)
|
||||||
{
|
{
|
||||||
printf("Firmware not found! Generating default firmware.\n");
|
printf("Firmware not found! Generating default firmware.\n");
|
||||||
FirmwarePath = "";
|
FirmwarePath = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoadFirmwareFromFile(f);
|
LoadFirmwareFromFile(f, makecopy);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,28 +397,28 @@ void Reset()
|
||||||
|
|
||||||
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
|
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
|
||||||
|
|
||||||
if (firmoverride)
|
//if (firmoverride)
|
||||||
{
|
{
|
||||||
u8 mac[6];
|
u8 mac[6];
|
||||||
bool rep;
|
bool rep = false;
|
||||||
|
|
||||||
if (Platform::GetConfigBool(Platform::Firm_RandomizeMAC))
|
memcpy(mac, &Firmware[0x36], 6);
|
||||||
{
|
|
||||||
mac[0] = 0x00;
|
if (firmoverride)
|
||||||
mac[1] = 0x09;
|
|
||||||
mac[2] = 0xBF;
|
|
||||||
mac[3] = rand()&0xFF;
|
|
||||||
mac[4] = rand()&0xFF;
|
|
||||||
mac[5] = rand()&0xFF;
|
|
||||||
rep = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rep = Platform::GetConfigArray(Platform::Firm_MAC, mac);
|
rep = Platform::GetConfigArray(Platform::Firm_MAC, mac);
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
{
|
||||||
|
rep = true;
|
||||||
|
mac[3] += inst;
|
||||||
|
mac[4] += inst*0x44;
|
||||||
|
mac[5] += inst*0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep)
|
if (rep)
|
||||||
{
|
{
|
||||||
|
mac[0] &= 0xFC; // ensure the MAC isn't a broadcast MAC
|
||||||
memcpy(&Firmware[0x36], mac, 6);
|
memcpy(&Firmware[0x36], mac, 6);
|
||||||
|
|
||||||
*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
|
*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
|
||||||
|
@ -593,7 +605,12 @@ void Write(u8 val, u32 hold)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FILE* f = Platform::OpenLocalFile("wfcsettings.bin", "wb");
|
char wfcfile[50] = {0};
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0) snprintf(wfcfile, 49, "wfcsettings.bin", Platform::InstanceID());
|
||||||
|
else strncpy(wfcfile, "wfcsettings.bin", 49);
|
||||||
|
|
||||||
|
FILE* f = Platform::OpenLocalFile(wfcfile, "wb");
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
u32 cutoff = 0x7F400 & FirmwareMask;
|
u32 cutoff = 0x7F400 & FirmwareMask;
|
||||||
|
|
|
@ -184,6 +184,12 @@ void DoSavestate(Savestate* file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetPowerCnt(u32 val)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetInterpolation(int type)
|
void SetInterpolation(int type)
|
||||||
{
|
{
|
||||||
InterpType = type;
|
InterpType = type;
|
||||||
|
|
|
@ -31,6 +31,8 @@ void Stop();
|
||||||
|
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
|
void SetPowerCnt(u32 val);
|
||||||
|
|
||||||
// 0=none 1=linear 2=cosine 3=cubic
|
// 0=none 1=linear 2=cosine 3=cubic
|
||||||
void SetInterpolation(int type);
|
void SetInterpolation(int type);
|
||||||
|
|
||||||
|
|
1434
src/Wifi.cpp
1434
src/Wifi.cpp
File diff suppressed because it is too large
Load Diff
34
src/Wifi.h
34
src/Wifi.h
|
@ -93,6 +93,7 @@ enum
|
||||||
W_CmdTotalTime = 0x0C0,
|
W_CmdTotalTime = 0x0C0,
|
||||||
W_CmdReplyTime = 0x0C4,
|
W_CmdReplyTime = 0x0C4,
|
||||||
W_RXFilter = 0x0D0,
|
W_RXFilter = 0x0D0,
|
||||||
|
W_RXLenCrop = 0x0DA,
|
||||||
W_RXFilter2 = 0x0E0,
|
W_RXFilter2 = 0x0E0,
|
||||||
|
|
||||||
W_USCountCnt = 0x0E8,
|
W_USCountCnt = 0x0E8,
|
||||||
|
@ -136,12 +137,43 @@ enum
|
||||||
W_TXErrorCount = 0x1C0,
|
W_TXErrorCount = 0x1C0,
|
||||||
W_RXCount = 0x1C4,
|
W_RXCount = 0x1C4,
|
||||||
|
|
||||||
|
W_CMDStat0 = 0x1D0,
|
||||||
|
W_CMDStat1 = 0x1D2,
|
||||||
|
W_CMDStat2 = 0x1D4,
|
||||||
|
W_CMDStat3 = 0x1D6,
|
||||||
|
W_CMDStat4 = 0x1D8,
|
||||||
|
W_CMDStat5 = 0x1DA,
|
||||||
|
W_CMDStat6 = 0x1DC,
|
||||||
|
W_CMDStat7 = 0x1DE,
|
||||||
|
|
||||||
W_TXSeqNo = 0x210,
|
W_TXSeqNo = 0x210,
|
||||||
W_RFStatus = 0x214,
|
W_RFStatus = 0x214,
|
||||||
W_IFSet = 0x21C,
|
W_IFSet = 0x21C,
|
||||||
W_RXTXAddr = 0x268,
|
W_RXTXAddr = 0x268,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Event_RXCheck = 0,
|
||||||
|
Event_IRQ15,
|
||||||
|
Event_MSTimer,
|
||||||
|
Event_RFWakeup,
|
||||||
|
Event_RX,
|
||||||
|
Event_TX,
|
||||||
|
Event_MPClientSync,
|
||||||
|
Event_RF,
|
||||||
|
Event_BB,
|
||||||
|
|
||||||
|
Event_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SchedEvent
|
||||||
|
{
|
||||||
|
void (*Func)(u32 param);
|
||||||
|
u64 Timestamp;
|
||||||
|
u32 Param;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
extern bool MPInited;
|
extern bool MPInited;
|
||||||
|
|
||||||
|
@ -151,7 +183,7 @@ void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void StartTX_Beacon();
|
void SetPowerCnt(u32 val);
|
||||||
|
|
||||||
void USTimer(u32 param);
|
void USTimer(u32 param);
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ void DeInit()
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
// random starting point for the counter
|
// random starting point for the counter
|
||||||
USCounter = 0x428888017ULL;
|
USCounter = 0x428888000ULL;
|
||||||
SeqNo = 0x0120;
|
SeqNo = 0x0120;
|
||||||
|
|
||||||
BeaconDue = false;
|
BeaconDue = false;
|
||||||
|
@ -115,18 +115,6 @@ bool MACIsBroadcast(u8* a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void USTimer()
|
|
||||||
{
|
|
||||||
USCounter++;
|
|
||||||
|
|
||||||
u32 chk = (u32)USCounter;
|
|
||||||
if (!(chk & 0x1FFFF))
|
|
||||||
{
|
|
||||||
// send beacon every 128ms
|
|
||||||
BeaconDue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MSTimer()
|
void MSTimer()
|
||||||
{
|
{
|
||||||
USCounter += 0x400;
|
USCounter += 0x400;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef WIFIAP_H
|
#ifndef WIFIAP_H
|
||||||
#define WIFIAP_H
|
#define WIFIAP_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace WifiAP
|
namespace WifiAP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -31,7 +33,6 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void USTimer();
|
|
||||||
void MSTimer();
|
void MSTimer();
|
||||||
|
|
||||||
// packet format: 12-byte TX header + original 802.11 frame
|
// packet format: 12-byte TX header + original 802.11 frame
|
||||||
|
|
|
@ -67,6 +67,20 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(
|
||||||
bool iswav = (Config::MicInputType == 3);
|
bool iswav = (Config::MicInputType == 3);
|
||||||
ui->txtMicWavPath->setEnabled(iswav);
|
ui->txtMicWavPath->setEnabled(iswav);
|
||||||
ui->btnMicWavBrowse->setEnabled(iswav);
|
ui->btnMicWavBrowse->setEnabled(iswav);
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
{
|
||||||
|
ui->lblInstanceNum->setText(QString("Configuring settings for instance %1").arg(inst+1));
|
||||||
|
ui->cbInterpolation->setEnabled(false);
|
||||||
|
ui->cbBitrate->setEnabled(false);
|
||||||
|
for (QAbstractButton* btn : grpMicMode->buttons())
|
||||||
|
btn->setEnabled(false);
|
||||||
|
ui->txtMicWavPath->setEnabled(false);
|
||||||
|
ui->btnMicWavBrowse->setEnabled(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ui->lblInstanceNum->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSettingsDialog::~AudioSettingsDialog()
|
AudioSettingsDialog::~AudioSettingsDialog()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>482</width>
|
<width>482</width>
|
||||||
<height>256</height>
|
<height>301</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -23,6 +23,13 @@
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
<enum>QLayout::SetFixedSize</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblInstanceNum">
|
||||||
|
<property name="text">
|
||||||
|
<string>Configuring settings for instance X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
@ -76,7 +83,7 @@
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QComboBox" name="cbBitrate">
|
<widget class="QComboBox" name="cbBitrate">
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>The bitrate of audio playback. If set to "Automatic" this will be 10-bit for DS mode and 16-bit for DSi mode.</p></body></html></string>
|
<string><html><head/><body><p>The bitrate of audio playback. If set to "Automatic" this will be 10-bit for DS mode and 16-bit for DSi mode.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
project(qt_sdl)
|
include(CMakeDependentOption)
|
||||||
|
|
||||||
SET(SOURCES_QT_SDL
|
include(FixInterfaceIncludes)
|
||||||
|
|
||||||
|
set(SOURCES_QT_SDL
|
||||||
main.cpp
|
main.cpp
|
||||||
main_shaders.h
|
main_shaders.h
|
||||||
CheatsDialog.cpp
|
CheatsDialog.cpp
|
||||||
Config.cpp
|
Config.cpp
|
||||||
EmuSettingsDialog.cpp
|
EmuSettingsDialog.cpp
|
||||||
PowerManagement/PowerManagementDialog.cpp
|
PowerManagement/PowerManagementDialog.cpp
|
||||||
PowerManagement/resources/battery.qrc
|
PowerManagement/resources/battery.qrc
|
||||||
|
@ -16,6 +18,7 @@ SET(SOURCES_QT_SDL
|
||||||
AudioSettingsDialog.cpp
|
AudioSettingsDialog.cpp
|
||||||
FirmwareSettingsDialog.cpp
|
FirmwareSettingsDialog.cpp
|
||||||
PathSettingsDialog.cpp
|
PathSettingsDialog.cpp
|
||||||
|
MPSettingsDialog.cpp
|
||||||
WifiSettingsDialog.cpp
|
WifiSettingsDialog.cpp
|
||||||
InterfaceSettingsDialog.cpp
|
InterfaceSettingsDialog.cpp
|
||||||
ROMInfoDialog.cpp
|
ROMInfoDialog.cpp
|
||||||
|
@ -24,13 +27,13 @@ SET(SOURCES_QT_SDL
|
||||||
Input.cpp
|
Input.cpp
|
||||||
LAN_PCap.cpp
|
LAN_PCap.cpp
|
||||||
LAN_Socket.cpp
|
LAN_Socket.cpp
|
||||||
|
LocalMP.cpp
|
||||||
OSD.cpp
|
OSD.cpp
|
||||||
OSD_shaders.h
|
OSD_shaders.h
|
||||||
font.h
|
font.h
|
||||||
Platform.cpp
|
Platform.cpp
|
||||||
QPathInput.h
|
QPathInput.h
|
||||||
ROMManager.cpp
|
|
||||||
SaveManager.cpp
|
|
||||||
CameraManager.cpp
|
CameraManager.cpp
|
||||||
|
|
||||||
ArchiveUtil.h
|
ArchiveUtil.h
|
||||||
|
@ -42,7 +45,7 @@ SET(SOURCES_QT_SDL
|
||||||
../mic_blow.h
|
../mic_blow.h
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
option(USE_QT6 "Build using Qt 6 instead of 5" ON)
|
option(USE_QT6 "Build using Qt 6 instead of 5" ON)
|
||||||
|
@ -56,29 +59,11 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (USE_QT6)
|
if (USE_QT6)
|
||||||
if (BUILD_STATIC AND QT6_STATIC_DIR)
|
|
||||||
set(QT6_STATIC_BASE ${QT6_STATIC_DIR}/lib/cmake/Qt6)
|
|
||||||
set(Qt6_DIR ${QT6_STATIC_BASE})
|
|
||||||
set(Qt6Core_DIR ${QT6_STATIC_BASE}Core)
|
|
||||||
set(Qt6Gui_DIR ${QT6_STATIC_BASE}Gui)
|
|
||||||
set(Qt6Widgets_DIR ${QT6_STATIC_BASE}Widgets)
|
|
||||||
set(Qt6Network_DIR ${QT6_STATIC_BASE}Network)
|
|
||||||
set(Qt6Multimedia_DIR ${QT6_STATIC_BASE}Multimedia)
|
set(Qt6Multimedia_DIR ${QT6_STATIC_BASE}Multimedia)
|
||||||
set(Qt6OpenGL_DIR ${QT6_STATIC_BASE}OpenGL)
|
|
||||||
set(Qt6OpenGLWidgets_DIR ${QT6_STATIC_BASE}OpenGLWidgets)
|
|
||||||
endif()
|
|
||||||
find_package(Qt6 COMPONENTS Core Gui Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED)
|
find_package(Qt6 COMPONENTS Core Gui Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED)
|
||||||
set(QT_LINK_LIBS Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::Multimedia Qt6::OpenGL Qt6::OpenGLWidgets)
|
set(QT_LINK_LIBS Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::Multimedia Qt6::OpenGL Qt6::OpenGLWidgets)
|
||||||
else()
|
else()
|
||||||
if (BUILD_STATIC AND QT5_STATIC_DIR)
|
|
||||||
set(QT5_STATIC_BASE ${QT5_STATIC_DIR}/lib/cmake/Qt5)
|
|
||||||
set(Qt5_DIR ${QT5_STATIC_BASE})
|
|
||||||
set(Qt5Core_DIR ${QT5_STATIC_BASE}Core)
|
|
||||||
set(Qt5Gui_DIR ${QT5_STATIC_BASE}Gui)
|
|
||||||
set(Qt5Widgets_DIR ${QT5_STATIC_BASE}Widgets)
|
|
||||||
set(Qt5Network_DIR ${QT5_STATIC_BASE}Network)
|
|
||||||
set(Qt5Multimedia_DIR ${QT5_STATIC_BASE}Multimedia)
|
set(Qt5Multimedia_DIR ${QT5_STATIC_BASE}Multimedia)
|
||||||
endif()
|
|
||||||
find_package(Qt5 COMPONENTS Core Gui Widgets Network Multimedia REQUIRED)
|
find_package(Qt5 COMPONENTS Core Gui Widgets Network Multimedia REQUIRED)
|
||||||
set(QT_LINK_LIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network Qt5::Multimedia)
|
set(QT_LINK_LIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network Qt5::Multimedia)
|
||||||
endif()
|
endif()
|
||||||
|
@ -87,66 +72,53 @@ set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
if (BUILD_STATIC)
|
||||||
find_package(PkgConfig REQUIRED)
|
list(APPEND PKG_CONFIG_EXECUTABLE "--static")
|
||||||
find_package(Iconv REQUIRED)
|
|
||||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
|
||||||
pkg_check_modules(SLIRP REQUIRED slirp)
|
|
||||||
pkg_check_modules(LIBARCHIVE REQUIRED libarchive)
|
|
||||||
add_compile_definitions(ARCHIVE_SUPPORT_ENABLED)
|
|
||||||
|
|
||||||
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL Release))
|
|
||||||
add_executable(melonDS WIN32 ${SOURCES_QT_SDL})
|
|
||||||
else()
|
|
||||||
add_executable(melonDS ${SOURCES_QT_SDL})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(melonDS ${CMAKE_THREAD_LIBS_INIT})
|
find_package(Threads REQUIRED)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
||||||
|
pkg_check_modules(Slirp REQUIRED IMPORTED_TARGET slirp)
|
||||||
|
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
|
||||||
|
|
||||||
target_include_directories(melonDS PRIVATE ${SDL2_INCLUDE_DIRS} ${SDL2_PREFIX}/include ${SLIRP_INCLUDE_DIRS} ${LIBARCHIVE_INCLUDE_DIRS})
|
fix_interface_includes(PkgConfig::SDL2 PkgConfig::Slirp PkgConfig::LibArchive)
|
||||||
target_link_directories(melonDS PRIVATE ${SDL2_LIBRARY_DIRS} ${SLIRP_LIBRARY_DIRS})
|
|
||||||
target_link_directories(melonDS PRIVATE ${LIBARCHIVE_LIBRARY_DIRS})
|
add_compile_definitions(ARCHIVE_SUPPORT_ENABLED)
|
||||||
|
|
||||||
|
add_executable(melonDS ${SOURCES_QT_SDL})
|
||||||
|
|
||||||
|
if (BUILD_STATIC)
|
||||||
|
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
|
||||||
|
target_link_options(melonDS PRIVATE -static)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||||
target_link_libraries(melonDS core)
|
target_link_libraries(melonDS PRIVATE core)
|
||||||
|
target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::Slirp PkgConfig::LibArchive)
|
||||||
if (BUILD_STATIC)
|
target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS})
|
||||||
target_link_libraries(melonDS -static ${SDL2_STATIC_LIBRARIES} ${SLIRP_STATIC_LIBRARIES} ${LIBARCHIVE_STATIC_LIBRARIES})
|
|
||||||
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
|
|
||||||
else()
|
|
||||||
target_link_libraries(melonDS ${SDL2_LIBRARIES} ${SLIRP_LIBRARIES} ${LIBARCHIVE_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT Iconv_IS_BUILT_IN)
|
|
||||||
target_link_libraries(melonDS ${Iconv_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
option(PORTABLE "Make a portable build that looks for its configuration in the current directory" OFF)
|
option(PORTABLE "Make a portable build that looks for its configuration in the current directory" OFF)
|
||||||
target_link_libraries(melonDS ${QT_LINK_LIBS})
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
||||||
target_link_libraries(melonDS dl)
|
|
||||||
endif()
|
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
option(PORTABLE "Make a portable build that looks for its configuration in the current directory" ON)
|
option(PORTABLE "Make a portable build that looks for its configuration in the current directory" ON)
|
||||||
|
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/res/melon.rc.in" "${CMAKE_SOURCE_DIR}/melon.rc")
|
configure_file("${CMAKE_SOURCE_DIR}/res/melon.rc.in" "${CMAKE_SOURCE_DIR}/melon.rc")
|
||||||
target_sources(melonDS PUBLIC "${CMAKE_SOURCE_DIR}/melon.rc")
|
target_sources(melonDS PUBLIC "${CMAKE_SOURCE_DIR}/melon.rc")
|
||||||
|
|
||||||
target_link_libraries(melonDS comctl32 d2d1 dwrite uxtheme ws2_32 iphlpapi gdi32)
|
target_link_libraries(melonDS PRIVATE ws2_32 iphlpapi)
|
||||||
if (BUILD_STATIC)
|
set_target_properties(melonDS PROPERTIES LINK_FLAGS_DEBUG "-mconsole")
|
||||||
target_link_libraries(melonDS imm32 winmm version setupapi -static z zstd ${QT_LINK_LIBS})
|
|
||||||
else()
|
|
||||||
target_link_libraries(melonDS ${QT_LINK_LIBS})
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (PORTABLE)
|
if (PORTABLE)
|
||||||
add_definitions(-DPORTABLE)
|
target_compile_definitions(melonDS PRIVATE PORTABLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
target_sources(melonDS PRIVATE sem_timedwait.cpp)
|
||||||
|
|
||||||
# Copy icon into the bundle
|
# Copy icon into the bundle
|
||||||
set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/res/melon.icns")
|
set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/res/melon.icns")
|
||||||
target_sources(melonDS PUBLIC "${RESOURCE_FILES}")
|
target_sources(melonDS PUBLIC "${RESOURCE_FILES}")
|
||||||
|
@ -156,7 +128,7 @@ if (APPLE)
|
||||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/melon.plist.in
|
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/melon.plist.in
|
||||||
OUTPUT_NAME melonDS
|
OUTPUT_NAME melonDS
|
||||||
RESOURCE "${RESOURCE_FILES}")
|
RESOURCE "${RESOURCE_FILES}")
|
||||||
|
|
||||||
|
|
||||||
option(MACOS_BUNDLE_LIBS "Bundle libraries with the app on macOS" OFF)
|
option(MACOS_BUNDLE_LIBS "Bundle libraries with the app on macOS" OFF)
|
||||||
option(MACOS_BUILD_DMG "Build DMG image of the macOS application bundle" OFF)
|
option(MACOS_BUILD_DMG "Build DMG image of the macOS application bundle" OFF)
|
||||||
|
@ -174,8 +146,8 @@ endif()
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
foreach(SIZE 16 32 48 64 128 256)
|
foreach(SIZE 16 32 48 64 128 256)
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/res/icon/melon_${SIZE}x${SIZE}.png
|
install(FILES ${CMAKE_SOURCE_DIR}/res/icon/melon_${SIZE}x${SIZE}.png
|
||||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/${SIZE}x${SIZE}/apps
|
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/${SIZE}x${SIZE}/apps
|
||||||
RENAME net.kuribo64.melonDS.png)
|
RENAME net.kuribo64.melonDS.png)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/res/net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
install(FILES ${CMAKE_SOURCE_DIR}/res/net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||||
|
|
|
@ -106,9 +106,10 @@ int FirmwareBirthdayDay;
|
||||||
int FirmwareFavouriteColour;
|
int FirmwareFavouriteColour;
|
||||||
std::string FirmwareMessage;
|
std::string FirmwareMessage;
|
||||||
std::string FirmwareMAC;
|
std::string FirmwareMAC;
|
||||||
bool RandomizeMAC;
|
|
||||||
|
|
||||||
bool SocketBindAnyAddr;
|
int MPAudioMode;
|
||||||
|
int MPRecvTimeout;
|
||||||
|
|
||||||
std::string LANDevice;
|
std::string LANDevice;
|
||||||
bool DirectLAN;
|
bool DirectLAN;
|
||||||
|
|
||||||
|
@ -143,211 +144,206 @@ CameraConfig Camera[2];
|
||||||
|
|
||||||
|
|
||||||
const char* kConfigFile = "melonDS.ini";
|
const char* kConfigFile = "melonDS.ini";
|
||||||
|
const char* kUniqueConfigFile = "melonDS.%d.ini";
|
||||||
|
|
||||||
ConfigEntry ConfigFile[] =
|
ConfigEntry ConfigFile[] =
|
||||||
{
|
{
|
||||||
{"Key_A", 0, &KeyMapping[0], -1},
|
{"Key_A", 0, &KeyMapping[0], -1, true},
|
||||||
{"Key_B", 0, &KeyMapping[1], -1},
|
{"Key_B", 0, &KeyMapping[1], -1, true},
|
||||||
{"Key_Select", 0, &KeyMapping[2], -1},
|
{"Key_Select", 0, &KeyMapping[2], -1, true},
|
||||||
{"Key_Start", 0, &KeyMapping[3], -1},
|
{"Key_Start", 0, &KeyMapping[3], -1, true},
|
||||||
{"Key_Right", 0, &KeyMapping[4], -1},
|
{"Key_Right", 0, &KeyMapping[4], -1, true},
|
||||||
{"Key_Left", 0, &KeyMapping[5], -1},
|
{"Key_Left", 0, &KeyMapping[5], -1, true},
|
||||||
{"Key_Up", 0, &KeyMapping[6], -1},
|
{"Key_Up", 0, &KeyMapping[6], -1, true},
|
||||||
{"Key_Down", 0, &KeyMapping[7], -1},
|
{"Key_Down", 0, &KeyMapping[7], -1, true},
|
||||||
{"Key_R", 0, &KeyMapping[8], -1},
|
{"Key_R", 0, &KeyMapping[8], -1, true},
|
||||||
{"Key_L", 0, &KeyMapping[9], -1},
|
{"Key_L", 0, &KeyMapping[9], -1, true},
|
||||||
{"Key_X", 0, &KeyMapping[10], -1},
|
{"Key_X", 0, &KeyMapping[10], -1, true},
|
||||||
{"Key_Y", 0, &KeyMapping[11], -1},
|
{"Key_Y", 0, &KeyMapping[11], -1, true},
|
||||||
|
|
||||||
{"Joy_A", 0, &JoyMapping[0], -1},
|
{"Joy_A", 0, &JoyMapping[0], -1, true},
|
||||||
{"Joy_B", 0, &JoyMapping[1], -1},
|
{"Joy_B", 0, &JoyMapping[1], -1, true},
|
||||||
{"Joy_Select", 0, &JoyMapping[2], -1},
|
{"Joy_Select", 0, &JoyMapping[2], -1, true},
|
||||||
{"Joy_Start", 0, &JoyMapping[3], -1},
|
{"Joy_Start", 0, &JoyMapping[3], -1, true},
|
||||||
{"Joy_Right", 0, &JoyMapping[4], -1},
|
{"Joy_Right", 0, &JoyMapping[4], -1, true},
|
||||||
{"Joy_Left", 0, &JoyMapping[5], -1},
|
{"Joy_Left", 0, &JoyMapping[5], -1, true},
|
||||||
{"Joy_Up", 0, &JoyMapping[6], -1},
|
{"Joy_Up", 0, &JoyMapping[6], -1, true},
|
||||||
{"Joy_Down", 0, &JoyMapping[7], -1},
|
{"Joy_Down", 0, &JoyMapping[7], -1, true},
|
||||||
{"Joy_R", 0, &JoyMapping[8], -1},
|
{"Joy_R", 0, &JoyMapping[8], -1, true},
|
||||||
{"Joy_L", 0, &JoyMapping[9], -1},
|
{"Joy_L", 0, &JoyMapping[9], -1, true},
|
||||||
{"Joy_X", 0, &JoyMapping[10], -1},
|
{"Joy_X", 0, &JoyMapping[10], -1, true},
|
||||||
{"Joy_Y", 0, &JoyMapping[11], -1},
|
{"Joy_Y", 0, &JoyMapping[11], -1, true},
|
||||||
|
|
||||||
{"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1},
|
{"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1, true},
|
||||||
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1},
|
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1, true},
|
||||||
{"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1},
|
{"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1, true},
|
||||||
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1},
|
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, true},
|
||||||
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1},
|
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, true},
|
||||||
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1},
|
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, true},
|
||||||
{"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1},
|
{"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1, true},
|
||||||
{"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1},
|
{"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1, true},
|
||||||
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1},
|
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, true},
|
||||||
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1},
|
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, true},
|
||||||
{"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1},
|
{"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1, true},
|
||||||
|
|
||||||
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1},
|
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, true},
|
||||||
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1},
|
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, true},
|
||||||
{"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1},
|
{"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1, true},
|
||||||
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1},
|
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, true},
|
||||||
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1},
|
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, true},
|
||||||
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1},
|
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, true},
|
||||||
{"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1},
|
{"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, true},
|
||||||
{"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1},
|
{"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1, true},
|
||||||
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1},
|
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, true},
|
||||||
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1},
|
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, true},
|
||||||
{"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1},
|
{"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1, true},
|
||||||
|
|
||||||
{"JoystickID", 0, &JoystickID, 0},
|
{"JoystickID", 0, &JoystickID, 0, true},
|
||||||
|
|
||||||
{"WindowWidth", 0, &WindowWidth, 256},
|
{"WindowWidth", 0, &WindowWidth, 256, true},
|
||||||
{"WindowHeight", 0, &WindowHeight, 384},
|
{"WindowHeight", 0, &WindowHeight, 384, true},
|
||||||
{"WindowMax", 1, &WindowMaximized, false},
|
{"WindowMax", 1, &WindowMaximized, false, true},
|
||||||
|
|
||||||
{"ScreenRotation", 0, &ScreenRotation, 0},
|
{"ScreenRotation", 0, &ScreenRotation, 0, true},
|
||||||
{"ScreenGap", 0, &ScreenGap, 0},
|
{"ScreenGap", 0, &ScreenGap, 0, true},
|
||||||
{"ScreenLayout", 0, &ScreenLayout, 0},
|
{"ScreenLayout", 0, &ScreenLayout, 0, true},
|
||||||
{"ScreenSwap", 1, &ScreenSwap, false},
|
{"ScreenSwap", 1, &ScreenSwap, false, true},
|
||||||
{"ScreenSizing", 0, &ScreenSizing, 0},
|
{"ScreenSizing", 0, &ScreenSizing, 0, true},
|
||||||
{"IntegerScaling", 1, &IntegerScaling, false},
|
{"IntegerScaling", 1, &IntegerScaling, false, true},
|
||||||
{"ScreenAspectTop",0, &ScreenAspectTop,0},
|
{"ScreenAspectTop",0, &ScreenAspectTop,0, true},
|
||||||
{"ScreenAspectBot",0, &ScreenAspectBot,0},
|
{"ScreenAspectBot",0, &ScreenAspectBot,0, true},
|
||||||
{"ScreenFilter", 1, &ScreenFilter, true},
|
{"ScreenFilter", 1, &ScreenFilter, true, true},
|
||||||
|
|
||||||
{"ScreenUseGL", 1, &ScreenUseGL, false},
|
{"ScreenUseGL", 1, &ScreenUseGL, false, false},
|
||||||
{"ScreenVSync", 1, &ScreenVSync, false},
|
{"ScreenVSync", 1, &ScreenVSync, false, false},
|
||||||
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1},
|
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, false},
|
||||||
|
|
||||||
{"3DRenderer", 0, &_3DRenderer, 0},
|
{"3DRenderer", 0, &_3DRenderer, 0, false},
|
||||||
{"Threaded3D", 1, &Threaded3D, true},
|
{"Threaded3D", 1, &Threaded3D, true, false},
|
||||||
|
|
||||||
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1},
|
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, false},
|
||||||
{"GL_BetterPolygons", 1, &GL_BetterPolygons, false},
|
{"GL_BetterPolygons", 1, &GL_BetterPolygons, false, false},
|
||||||
|
|
||||||
{"LimitFPS", 1, &LimitFPS, true},
|
{"LimitFPS", 1, &LimitFPS, true, false},
|
||||||
{"AudioSync", 1, &AudioSync, false},
|
{"AudioSync", 1, &AudioSync, false},
|
||||||
{"ShowOSD", 1, &ShowOSD, true},
|
{"ShowOSD", 1, &ShowOSD, true, false},
|
||||||
|
|
||||||
{"ConsoleType", 0, &ConsoleType, 0},
|
{"ConsoleType", 0, &ConsoleType, 0, false},
|
||||||
{"DirectBoot", 1, &DirectBoot, true},
|
{"DirectBoot", 1, &DirectBoot, true, false},
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
{"JIT_Enable", 1, &JIT_Enable, false},
|
{"JIT_Enable", 1, &JIT_Enable, false, false},
|
||||||
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32},
|
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, false},
|
||||||
{"JIT_BranchOptimisations", 1, &JIT_BranchOptimisations, true},
|
{"JIT_BranchOptimisations", 1, &JIT_BranchOptimisations, true, false},
|
||||||
{"JIT_LiteralOptimisations", 1, &JIT_LiteralOptimisations, true},
|
{"JIT_LiteralOptimisations", 1, &JIT_LiteralOptimisations, true, false},
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
{"JIT_FastMemory", 1, &JIT_FastMemory, false},
|
{"JIT_FastMemory", 1, &JIT_FastMemory, false, false},
|
||||||
#else
|
#else
|
||||||
{"JIT_FastMemory", 1, &JIT_FastMemory, true},
|
{"JIT_FastMemory", 1, &JIT_FastMemory, true, false},
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{"ExternalBIOSEnable", 1, &ExternalBIOSEnable, false},
|
{"ExternalBIOSEnable", 1, &ExternalBIOSEnable, false, false},
|
||||||
|
|
||||||
{"BIOS9Path", 2, &BIOS9Path, (std::string)""},
|
{"BIOS9Path", 2, &BIOS9Path, (std::string)"", false},
|
||||||
{"BIOS7Path", 2, &BIOS7Path, (std::string)""},
|
{"BIOS7Path", 2, &BIOS7Path, (std::string)"", false},
|
||||||
{"FirmwarePath", 2, &FirmwarePath, (std::string)""},
|
{"FirmwarePath", 2, &FirmwarePath, (std::string)"", false},
|
||||||
|
|
||||||
{"DSiBIOS9Path", 2, &DSiBIOS9Path, (std::string)""},
|
{"DSiBIOS9Path", 2, &DSiBIOS9Path, (std::string)"", false},
|
||||||
{"DSiBIOS7Path", 2, &DSiBIOS7Path, (std::string)""},
|
{"DSiBIOS7Path", 2, &DSiBIOS7Path, (std::string)"", false},
|
||||||
{"DSiFirmwarePath", 2, &DSiFirmwarePath, (std::string)""},
|
{"DSiFirmwarePath", 2, &DSiFirmwarePath, (std::string)"", false},
|
||||||
{"DSiNANDPath", 2, &DSiNANDPath, (std::string)""},
|
{"DSiNANDPath", 2, &DSiNANDPath, (std::string)"", false},
|
||||||
|
|
||||||
{"DLDIEnable", 1, &DLDIEnable, false},
|
{"DLDIEnable", 1, &DLDIEnable, false, false},
|
||||||
{"DLDISDPath", 2, &DLDISDPath, (std::string)"dldi.bin"},
|
{"DLDISDPath", 2, &DLDISDPath, (std::string)"dldi.bin", false},
|
||||||
{"DLDISize", 0, &DLDISize, 0},
|
{"DLDISize", 0, &DLDISize, 0, false},
|
||||||
{"DLDIReadOnly", 1, &DLDIReadOnly, false},
|
{"DLDIReadOnly", 1, &DLDIReadOnly, false, false},
|
||||||
{"DLDIFolderSync", 1, &DLDIFolderSync, false},
|
{"DLDIFolderSync", 1, &DLDIFolderSync, false, false},
|
||||||
{"DLDIFolderPath", 2, &DLDIFolderPath, (std::string)""},
|
{"DLDIFolderPath", 2, &DLDIFolderPath, (std::string)"", false},
|
||||||
|
|
||||||
{"DSiSDEnable", 1, &DSiSDEnable, false},
|
{"DSiSDEnable", 1, &DSiSDEnable, false, false},
|
||||||
{"DSiSDPath", 2, &DSiSDPath, (std::string)"dsisd.bin"},
|
{"DSiSDPath", 2, &DSiSDPath, (std::string)"dsisd.bin", false},
|
||||||
{"DSiSDSize", 0, &DSiSDSize, 0},
|
{"DSiSDSize", 0, &DSiSDSize, 0, false},
|
||||||
{"DSiSDReadOnly", 1, &DSiSDReadOnly, false},
|
{"DSiSDReadOnly", 1, &DSiSDReadOnly, false, false},
|
||||||
{"DSiSDFolderSync", 1, &DSiSDFolderSync, false},
|
{"DSiSDFolderSync", 1, &DSiSDFolderSync, false, false},
|
||||||
{"DSiSDFolderPath", 2, &DSiSDFolderPath, (std::string)""},
|
{"DSiSDFolderPath", 2, &DSiSDFolderPath, (std::string)"", false},
|
||||||
|
|
||||||
{"FirmwareOverrideSettings", 1, &FirmwareOverrideSettings, false},
|
{"FirmwareOverrideSettings", 1, &FirmwareOverrideSettings, false, true},
|
||||||
{"FirmwareUsername", 2, &FirmwareUsername, (std::string)"melonDS"},
|
{"FirmwareUsername", 2, &FirmwareUsername, (std::string)"melonDS", true},
|
||||||
{"FirmwareLanguage", 0, &FirmwareLanguage, 1},
|
{"FirmwareLanguage", 0, &FirmwareLanguage, 1, true},
|
||||||
{"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 1},
|
{"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 1, true},
|
||||||
{"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 1},
|
{"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 1, true},
|
||||||
{"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0},
|
{"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0, true},
|
||||||
{"FirmwareMessage", 2, &FirmwareMessage, (std::string)""},
|
{"FirmwareMessage", 2, &FirmwareMessage, (std::string)"", true},
|
||||||
{"FirmwareMAC", 2, &FirmwareMAC, (std::string)""},
|
{"FirmwareMAC", 2, &FirmwareMAC, (std::string)"", true},
|
||||||
{"RandomizeMAC", 1, &RandomizeMAC, false},
|
|
||||||
|
|
||||||
{"SockBindAnyAddr", 1, &SocketBindAnyAddr, false},
|
{"MPAudioMode", 0, &MPAudioMode, 1, false},
|
||||||
{"LANDevice", 2, &LANDevice, (std::string)""},
|
{"MPRecvTimeout", 0, &MPRecvTimeout, 25, false},
|
||||||
{"DirectLAN", 1, &DirectLAN, false},
|
|
||||||
|
|
||||||
{"SavStaRelocSRAM", 1, &SavestateRelocSRAM, false},
|
{"LANDevice", 2, &LANDevice, (std::string)"", false},
|
||||||
|
{"DirectLAN", 1, &DirectLAN, false, false},
|
||||||
|
|
||||||
{"AudioInterp", 0, &AudioInterp, 0},
|
{"SavStaRelocSRAM", 1, &SavestateRelocSRAM, false, false},
|
||||||
{"AudioBitrate", 0, &AudioBitrate, 0},
|
|
||||||
{"AudioVolume", 0, &AudioVolume, 256},
|
|
||||||
{"MicInputType", 0, &MicInputType, 1},
|
|
||||||
{"MicWavPath", 2, &MicWavPath, (std::string)""},
|
|
||||||
|
|
||||||
{"LastROMFolder", 2, &LastROMFolder, (std::string)""},
|
{"AudioInterp", 0, &AudioInterp, 0, false},
|
||||||
|
{"AudioBitrate", 0, &AudioBitrate, 0, false},
|
||||||
|
{"AudioVolume", 0, &AudioVolume, 256, true},
|
||||||
|
{"MicInputType", 0, &MicInputType, 1, false},
|
||||||
|
{"MicWavPath", 2, &MicWavPath, (std::string)"", false},
|
||||||
|
|
||||||
{"RecentROM_0", 2, &RecentROMList[0], (std::string)""},
|
{"LastROMFolder", 2, &LastROMFolder, (std::string)"", true},
|
||||||
{"RecentROM_1", 2, &RecentROMList[1], (std::string)""},
|
|
||||||
{"RecentROM_2", 2, &RecentROMList[2], (std::string)""},
|
|
||||||
{"RecentROM_3", 2, &RecentROMList[3], (std::string)""},
|
|
||||||
{"RecentROM_4", 2, &RecentROMList[4], (std::string)""},
|
|
||||||
{"RecentROM_5", 2, &RecentROMList[5], (std::string)""},
|
|
||||||
{"RecentROM_6", 2, &RecentROMList[6], (std::string)""},
|
|
||||||
{"RecentROM_7", 2, &RecentROMList[7], (std::string)""},
|
|
||||||
{"RecentROM_8", 2, &RecentROMList[8], (std::string)""},
|
|
||||||
{"RecentROM_9", 2, &RecentROMList[9], (std::string)""},
|
|
||||||
|
|
||||||
{"SaveFilePath", 2, &SaveFilePath, (std::string)""},
|
{"RecentROM_0", 2, &RecentROMList[0], (std::string)"", true},
|
||||||
{"SavestatePath", 2, &SavestatePath, (std::string)""},
|
{"RecentROM_1", 2, &RecentROMList[1], (std::string)"", true},
|
||||||
{"CheatFilePath", 2, &CheatFilePath, (std::string)""},
|
{"RecentROM_2", 2, &RecentROMList[2], (std::string)"", true},
|
||||||
|
{"RecentROM_3", 2, &RecentROMList[3], (std::string)"", true},
|
||||||
|
{"RecentROM_4", 2, &RecentROMList[4], (std::string)"", true},
|
||||||
|
{"RecentROM_5", 2, &RecentROMList[5], (std::string)"", true},
|
||||||
|
{"RecentROM_6", 2, &RecentROMList[6], (std::string)"", true},
|
||||||
|
{"RecentROM_7", 2, &RecentROMList[7], (std::string)"", true},
|
||||||
|
{"RecentROM_8", 2, &RecentROMList[8], (std::string)"", true},
|
||||||
|
{"RecentROM_9", 2, &RecentROMList[9], (std::string)"", true},
|
||||||
|
|
||||||
{"EnableCheats", 1, &EnableCheats, false},
|
{"SaveFilePath", 2, &SaveFilePath, (std::string)"", true},
|
||||||
|
{"SavestatePath", 2, &SavestatePath, (std::string)"", true},
|
||||||
|
{"CheatFilePath", 2, &CheatFilePath, (std::string)"", true},
|
||||||
|
|
||||||
{"MouseHide", 1, &MouseHide, false},
|
{"EnableCheats", 1, &EnableCheats, false, true},
|
||||||
{"MouseHideSeconds", 0, &MouseHideSeconds, 5},
|
|
||||||
{"PauseLostFocus", 1, &PauseLostFocus, false},
|
|
||||||
|
|
||||||
{"DSBatteryLevelOkay", 1, &DSBatteryLevelOkay, true},
|
{"MouseHide", 1, &MouseHide, false, false},
|
||||||
{"DSiBatteryLevel", 0, &DSiBatteryLevel, 0xF},
|
{"MouseHideSeconds", 0, &MouseHideSeconds, 5, false},
|
||||||
{"DSiBatteryCharging", 1, &DSiBatteryCharging, true},
|
{"PauseLostFocus", 1, &PauseLostFocus, false, false},
|
||||||
|
|
||||||
|
{"DSBatteryLevelOkay", 1, &DSBatteryLevelOkay, true, true},
|
||||||
|
{"DSiBatteryLevel", 0, &DSiBatteryLevel, 0xF, true},
|
||||||
|
{"DSiBatteryCharging", 1, &DSiBatteryCharging, true, true},
|
||||||
// TODO!!
|
// TODO!!
|
||||||
// we need a more elegant way to deal with this
|
// we need a more elegant way to deal with this
|
||||||
{"Camera0_InputType", 0, &Camera[0].InputType, 0},
|
{"Camera0_InputType", 0, &Camera[0].InputType, 0, false},
|
||||||
{"Camera0_ImagePath", 2, &Camera[0].ImagePath, (std::string)""},
|
{"Camera0_ImagePath", 2, &Camera[0].ImagePath, (std::string)"", false},
|
||||||
{"Camera0_CamDeviceName", 2, &Camera[0].CamDeviceName, (std::string)""},
|
{"Camera0_CamDeviceName", 2, &Camera[0].CamDeviceName, (std::string)"", false},
|
||||||
{"Camera0_XFlip", 1, &Camera[0].XFlip, false},
|
{"Camera0_XFlip", 1, &Camera[0].XFlip, false, false},
|
||||||
{"Camera1_InputType", 0, &Camera[1].InputType, 0},
|
{"Camera1_InputType", 0, &Camera[1].InputType, 0, false},
|
||||||
{"Camera1_ImagePath", 2, &Camera[1].ImagePath, (std::string)""},
|
{"Camera1_ImagePath", 2, &Camera[1].ImagePath, (std::string)"", false},
|
||||||
{"Camera1_CamDeviceName", 2, &Camera[1].CamDeviceName, (std::string)""},
|
{"Camera1_CamDeviceName", 2, &Camera[1].CamDeviceName, (std::string)"", false},
|
||||||
{"Camera1_XFlip", 1, &Camera[1].XFlip, false},
|
{"Camera1_XFlip", 1, &Camera[1].XFlip, false, false},
|
||||||
|
|
||||||
{"", -1, nullptr, 0}
|
{"", -1, nullptr, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Load()
|
void LoadFile(int inst)
|
||||||
{
|
{
|
||||||
ConfigEntry* entry = &ConfigFile[0];
|
FILE* f;
|
||||||
for (;;)
|
if (inst > 0)
|
||||||
{
|
{
|
||||||
if (!entry->Value) break;
|
char name[100] = {0};
|
||||||
|
snprintf(name, 99, kUniqueConfigFile, inst+1);
|
||||||
switch (entry->Type)
|
f = Platform::OpenLocalFile(name, "r");
|
||||||
{
|
|
||||||
case 0: *(int*)entry->Value = std::get<int>(entry->Default); break;
|
|
||||||
case 1: *(bool*)entry->Value = std::get<bool>(entry->Default); break;
|
|
||||||
case 2: *(std::string*)entry->Value = std::get<std::string>(entry->Default); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry++;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
f = Platform::OpenLocalFile(kConfigFile, "r");
|
||||||
|
|
||||||
FILE* f = Platform::OpenLocalFile(kConfigFile, "r");
|
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
|
|
||||||
char linebuf[1024];
|
char linebuf[1024];
|
||||||
|
@ -362,13 +358,13 @@ void Load()
|
||||||
entryname[31] = '\0';
|
entryname[31] = '\0';
|
||||||
if (ret < 2) continue;
|
if (ret < 2) continue;
|
||||||
|
|
||||||
ConfigEntry* entry = &ConfigFile[0];
|
for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
if (!entry->Value) break;
|
|
||||||
|
|
||||||
if (!strncmp(entry->Name, entryname, 32))
|
if (!strncmp(entry->Name, entryname, 32))
|
||||||
{
|
{
|
||||||
|
if ((inst > 0) && (!entry->InstanceUnique))
|
||||||
|
break;
|
||||||
|
|
||||||
switch (entry->Type)
|
switch (entry->Type)
|
||||||
{
|
{
|
||||||
case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
|
case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
|
||||||
|
@ -378,23 +374,52 @@ void Load()
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Load()
|
||||||
|
{
|
||||||
|
|
||||||
|
for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
|
||||||
|
{
|
||||||
|
switch (entry->Type)
|
||||||
|
{
|
||||||
|
case 0: *(int*)entry->Value = std::get<int>(entry->Default); break;
|
||||||
|
case 1: *(bool*)entry->Value = std::get<bool>(entry->Default); break;
|
||||||
|
case 2: *(std::string*)entry->Value = std::get<std::string>(entry->Default); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadFile(0);
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
LoadFile(inst);
|
||||||
|
}
|
||||||
|
|
||||||
void Save()
|
void Save()
|
||||||
{
|
{
|
||||||
FILE* f = Platform::OpenLocalFile(kConfigFile, "w");
|
int inst = Platform::InstanceID();
|
||||||
|
|
||||||
|
FILE* f;
|
||||||
|
if (inst > 0)
|
||||||
|
{
|
||||||
|
char name[100] = {0};
|
||||||
|
snprintf(name, 99, kUniqueConfigFile, inst+1);
|
||||||
|
f = Platform::OpenLocalFile(name, "w");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
f = Platform::OpenLocalFile(kConfigFile, "w");
|
||||||
|
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
|
|
||||||
ConfigEntry* entry = &ConfigFile[0];
|
for (ConfigEntry* entry = &ConfigFile[0]; entry->Value; entry++)
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
if (!entry->Value) break;
|
if ((inst > 0) && (!entry->InstanceUnique))
|
||||||
|
continue;
|
||||||
|
|
||||||
switch (entry->Type)
|
switch (entry->Type)
|
||||||
{
|
{
|
||||||
|
@ -402,8 +427,6 @@ void Save()
|
||||||
case 1: fprintf(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
|
case 1: fprintf(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
|
||||||
case 2: fprintf(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
|
case 2: fprintf(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct ConfigEntry
|
||||||
int Type; // 0=int 1=bool 2=string
|
int Type; // 0=int 1=bool 2=string
|
||||||
void* Value; // pointer to the value variable
|
void* Value; // pointer to the value variable
|
||||||
std::variant<int, bool, std::string> Default;
|
std::variant<int, bool, std::string> Default;
|
||||||
|
bool InstanceUnique; // whether the setting can exist individually for each instance in multiplayer
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CameraConfig
|
struct CameraConfig
|
||||||
|
@ -149,9 +150,10 @@ extern int FirmwareBirthdayDay;
|
||||||
extern int FirmwareFavouriteColour;
|
extern int FirmwareFavouriteColour;
|
||||||
extern std::string FirmwareMessage;
|
extern std::string FirmwareMessage;
|
||||||
extern std::string FirmwareMAC;
|
extern std::string FirmwareMAC;
|
||||||
extern bool RandomizeMAC;
|
|
||||||
|
|
||||||
extern bool SocketBindAnyAddr;
|
extern int MPAudioMode;
|
||||||
|
extern int MPRecvTimeout;
|
||||||
|
|
||||||
extern std::string LANDevice;
|
extern std::string LANDevice;
|
||||||
extern bool DirectLAN;
|
extern bool DirectLAN;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "FirmwareSettingsDialog.h"
|
#include "FirmwareSettingsDialog.h"
|
||||||
|
@ -64,10 +65,14 @@ FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent
|
||||||
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
|
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
|
||||||
|
|
||||||
ui->txtMAC->setText(QString::fromStdString(Config::FirmwareMAC));
|
ui->txtMAC->setText(QString::fromStdString(Config::FirmwareMAC));
|
||||||
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC);
|
|
||||||
|
|
||||||
on_overrideFirmwareBox_toggled();
|
on_overrideFirmwareBox_toggled();
|
||||||
on_cbRandomizeMAC_toggled();
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
ui->lblInstanceNum->setText(QString("Configuring settings for instance %1").arg(inst+1));
|
||||||
|
else
|
||||||
|
ui->lblInstanceNum->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
FirmwareSettingsDialog::~FirmwareSettingsDialog()
|
FirmwareSettingsDialog::~FirmwareSettingsDialog()
|
||||||
|
@ -135,7 +140,6 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
std::string newMessage = ui->messageEdit->text().toStdString();
|
std::string newMessage = ui->messageEdit->text().toStdString();
|
||||||
|
|
||||||
std::string newMAC = ui->txtMAC->text().toStdString();
|
std::string newMAC = ui->txtMAC->text().toStdString();
|
||||||
bool newRandomizeMAC = ui->cbRandomizeMAC->isChecked();
|
|
||||||
|
|
||||||
if ( newOverride != Config::FirmwareOverrideSettings
|
if ( newOverride != Config::FirmwareOverrideSettings
|
||||||
|| newName != Config::FirmwareUsername
|
|| newName != Config::FirmwareUsername
|
||||||
|
@ -144,8 +148,7 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
|| newBirthdayDay != Config::FirmwareBirthdayDay
|
|| newBirthdayDay != Config::FirmwareBirthdayDay
|
||||||
|| newBirthdayMonth != Config::FirmwareBirthdayMonth
|
|| newBirthdayMonth != Config::FirmwareBirthdayMonth
|
||||||
|| newMessage != Config::FirmwareMessage
|
|| newMessage != Config::FirmwareMessage
|
||||||
|| newMAC != Config::FirmwareMAC
|
|| newMAC != Config::FirmwareMAC)
|
||||||
|| newRandomizeMAC != Config::RandomizeMAC)
|
|
||||||
{
|
{
|
||||||
if (RunningSomething
|
if (RunningSomething
|
||||||
&& QMessageBox::warning(this, "Reset necessary to apply changes",
|
&& QMessageBox::warning(this, "Reset necessary to apply changes",
|
||||||
|
@ -163,7 +166,6 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
Config::FirmwareMessage = newMessage;
|
Config::FirmwareMessage = newMessage;
|
||||||
|
|
||||||
Config::FirmwareMAC = newMAC;
|
Config::FirmwareMAC = newMAC;
|
||||||
Config::RandomizeMAC = newRandomizeMAC;
|
|
||||||
|
|
||||||
Config::Save();
|
Config::Save();
|
||||||
|
|
||||||
|
@ -210,9 +212,3 @@ void FirmwareSettingsDialog::on_overrideFirmwareBox_toggled()
|
||||||
ui->grpUserSettings->setDisabled(disable);
|
ui->grpUserSettings->setDisabled(disable);
|
||||||
ui->grpWifiSettings->setDisabled(disable);
|
ui->grpWifiSettings->setDisabled(disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareSettingsDialog::on_cbRandomizeMAC_toggled()
|
|
||||||
{
|
|
||||||
bool disable = ui->cbRandomizeMAC->isChecked();
|
|
||||||
ui->txtMAC->setDisabled(disable);
|
|
||||||
}
|
|
||||||
|
|
|
@ -124,7 +124,6 @@ private slots:
|
||||||
|
|
||||||
void on_cbxBirthdayMonth_currentIndexChanged(int idx);
|
void on_cbxBirthdayMonth_currentIndexChanged(int idx);
|
||||||
void on_overrideFirmwareBox_toggled();
|
void on_overrideFirmwareBox_toggled();
|
||||||
void on_cbRandomizeMAC_toggled();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool verifyMAC();
|
bool verifyMAC();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>511</width>
|
<width>511</width>
|
||||||
<height>342</height>
|
<height>357</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -23,6 +23,13 @@
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
<enum>QLayout::SetFixedSize</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblInstanceNum">
|
||||||
|
<property name="text">
|
||||||
|
<string>Configuring settings for instance X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="grpGeneral">
|
<widget class="QGroupBox" name="grpGeneral">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
@ -144,9 +151,9 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QCheckBox" name="cbRandomizeMAC">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Randomize</string>
|
<string>(leave empty to use default MAC)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "MapButton.h"
|
#include "MapButton.h"
|
||||||
|
@ -123,6 +124,12 @@ InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKeypadPage();
|
setupKeypadPage();
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
ui->lblInstanceNum->setText(QString("Configuring mappings for instance %1").arg(inst+1));
|
||||||
|
else
|
||||||
|
ui->lblInstanceNum->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputConfigDialog::~InputConfigDialog()
|
InputConfigDialog::~InputConfigDialog()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>770</width>
|
<width>770</width>
|
||||||
<height>719</height>
|
<height>678</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
<enum>QLayout::SetFixedSize</enum>
|
||||||
</property>
|
</property>
|
||||||
<item row="7" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -30,49 +30,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0" colspan="2">
|
<item row="1" column="0" colspan="2">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Joystick:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="cbxJoystick">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string><html><head/><body><p>Selects which joystick will be used for joystick input, if any is present.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
|
@ -167,7 +125,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyR">
|
<widget class="QPushButton" name="btnKeyR">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -258,7 +216,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyL">
|
<widget class="QPushButton" name="btnKeyL">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -384,7 +342,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyX">
|
<widget class="QPushButton" name="btnKeyX">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -464,7 +422,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyY">
|
<widget class="QPushButton" name="btnKeyY">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -523,7 +481,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyA">
|
<widget class="QPushButton" name="btnKeyA">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -615,7 +573,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyB">
|
<widget class="QPushButton" name="btnKeyB">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -698,7 +656,7 @@
|
||||||
<widget class="QPushButton" name="btnKeySelect">
|
<widget class="QPushButton" name="btnKeySelect">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -757,7 +715,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyStart">
|
<widget class="QPushButton" name="btnKeyStart">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -882,7 +840,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyUp">
|
<widget class="QPushButton" name="btnKeyUp">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -962,7 +920,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyLeft">
|
<widget class="QPushButton" name="btnKeyLeft">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1021,7 +979,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyRight">
|
<widget class="QPushButton" name="btnKeyRight">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1113,7 +1071,7 @@
|
||||||
<widget class="QPushButton" name="btnKeyDown">
|
<widget class="QPushButton" name="btnKeyDown">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1289,7 +1247,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyL">
|
<widget class="QPushButton" name="btnJoyL">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1441,7 +1399,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyUp">
|
<widget class="QPushButton" name="btnJoyUp">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1521,7 +1479,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyLeft">
|
<widget class="QPushButton" name="btnJoyLeft">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1580,7 +1538,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyRight">
|
<widget class="QPushButton" name="btnJoyRight">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1672,7 +1630,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyDown">
|
<widget class="QPushButton" name="btnJoyDown">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1814,7 +1772,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyX">
|
<widget class="QPushButton" name="btnJoyX">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1894,7 +1852,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyY">
|
<widget class="QPushButton" name="btnJoyY">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1953,7 +1911,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyA">
|
<widget class="QPushButton" name="btnJoyA">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -2045,7 +2003,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyB">
|
<widget class="QPushButton" name="btnJoyB">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -2128,7 +2086,7 @@
|
||||||
<widget class="QPushButton" name="btnJoySelect">
|
<widget class="QPushButton" name="btnJoySelect">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -2187,7 +2145,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyStart">
|
<widget class="QPushButton" name="btnJoyStart">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -2251,7 +2209,7 @@
|
||||||
<widget class="QPushButton" name="btnJoyR">
|
<widget class="QPushButton" name="btnJoyR">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>76</width>
|
<width>70</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -2321,6 +2279,55 @@
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Joystick:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="cbxJoystick">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string><html><head/><body><p>Selects which joystick will be used for joystick input, if any is present.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="lblInstanceNum">
|
||||||
|
<property name="text">
|
||||||
|
<string>Configuring mappings for instance X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -163,6 +163,7 @@ public:
|
||||||
|
|
||||||
setCheckable(true);
|
setCheckable(true);
|
||||||
setText(mappingText());
|
setText(mappingText());
|
||||||
|
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
|
||||||
|
|
||||||
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
|
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
|
||||||
|
|
||||||
|
@ -245,19 +246,21 @@ protected:
|
||||||
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
|
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
|
||||||
int diff = abs(axisval - axesRest[i]);
|
int diff = abs(axisval - axesRest[i]);
|
||||||
|
|
||||||
if (axesRest[i] < -16384 && axisval >= 0)
|
if (diff >= 16384)
|
||||||
{
|
{
|
||||||
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
|
if (axesRest[i] < -16384) // Trigger
|
||||||
click();
|
{
|
||||||
return;
|
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
|
||||||
}
|
}
|
||||||
else if (diff > 16384)
|
else // Analog stick
|
||||||
{
|
{
|
||||||
int axistype;
|
int axistype;
|
||||||
if (axisval > 0) axistype = 0;
|
if (axisval > 0) axistype = 0;
|
||||||
else axistype = 1;
|
else axistype = 1;
|
||||||
|
|
||||||
|
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
|
||||||
|
}
|
||||||
|
|
||||||
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
|
|
||||||
click();
|
click();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -352,4 +355,4 @@ private:
|
||||||
int axesRest[16];
|
int axesRest[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAPBUTTON_H
|
#endif // MAPBUTTON_H
|
||||||
|
|
|
@ -114,6 +114,12 @@ bool TryLoadPCap(void* lib)
|
||||||
|
|
||||||
bool Init(bool open_adapter)
|
bool Init(bool open_adapter)
|
||||||
{
|
{
|
||||||
|
PCapAdapter = NULL;
|
||||||
|
PacketLen = 0;
|
||||||
|
RXNum = 0;
|
||||||
|
|
||||||
|
NumAdapters = 0;
|
||||||
|
|
||||||
// TODO: how to deal with cases where an adapter is unplugged or changes config??
|
// TODO: how to deal with cases where an adapter is unplugged or changes config??
|
||||||
if (!PCapLib)
|
if (!PCapLib)
|
||||||
{
|
{
|
||||||
|
@ -142,12 +148,6 @@ bool Init(bool open_adapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PCapAdapter = NULL;
|
|
||||||
PacketLen = 0;
|
|
||||||
RXNum = 0;
|
|
||||||
|
|
||||||
NumAdapters = 0;
|
|
||||||
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,634 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "sem_timedwait.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "LocalMP.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace LocalMP
|
||||||
|
{
|
||||||
|
|
||||||
|
u32 MPUniqueID;
|
||||||
|
u8 PacketBuffer[2048];
|
||||||
|
|
||||||
|
struct MPQueueHeader
|
||||||
|
{
|
||||||
|
u16 NumInstances;
|
||||||
|
u16 InstanceBitmask; // bitmask of all instances present
|
||||||
|
u16 ConnectedBitmask; // bitmask of which instances are ready to send/receive packets
|
||||||
|
u32 PacketWriteOffset;
|
||||||
|
u32 ReplyWriteOffset;
|
||||||
|
u16 MPHostInstanceID; // instance ID from which the last CMD frame was sent
|
||||||
|
u16 MPReplyBitmask; // bitmask of which clients replied in time
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MPPacketHeader
|
||||||
|
{
|
||||||
|
u32 Magic;
|
||||||
|
u32 SenderID;
|
||||||
|
u32 Type; // 0=regular 1=CMD 2=reply 3=ack
|
||||||
|
u32 Length;
|
||||||
|
u64 Timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MPSync
|
||||||
|
{
|
||||||
|
u32 Magic;
|
||||||
|
u32 SenderID;
|
||||||
|
u16 ClientMask;
|
||||||
|
u16 Type;
|
||||||
|
u64 Timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
QSharedMemory* MPQueue;
|
||||||
|
int InstanceID;
|
||||||
|
u32 PacketReadOffset;
|
||||||
|
u32 ReplyReadOffset;
|
||||||
|
|
||||||
|
const u32 kQueueSize = 0x20000;
|
||||||
|
const u32 kMaxFrameSize = 0x800;
|
||||||
|
const u32 kPacketStart = sizeof(MPQueueHeader);
|
||||||
|
const u32 kReplyStart = kQueueSize / 2;
|
||||||
|
const u32 kPacketEnd = kReplyStart;
|
||||||
|
const u32 kReplyEnd = kQueueSize;
|
||||||
|
|
||||||
|
int RecvTimeout;
|
||||||
|
|
||||||
|
int LastHostID;
|
||||||
|
|
||||||
|
|
||||||
|
// we need to come up with our own abstraction layer for named semaphores
|
||||||
|
// because QSystemSemaphore doesn't support waiting with a timeout
|
||||||
|
// and, as such, is unsuitable to our needs
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
|
||||||
|
bool SemInited[32];
|
||||||
|
HANDLE SemPool[32];
|
||||||
|
|
||||||
|
void SemPoolInit()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
SemPool[i] = INVALID_HANDLE_VALUE;
|
||||||
|
SemInited[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemDeinit(int num);
|
||||||
|
|
||||||
|
void SemPoolDeinit()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
SemDeinit(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemInit(int num)
|
||||||
|
{
|
||||||
|
if (SemInited[num])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char semname[64];
|
||||||
|
sprintf(semname, "Local\\melonNIFI_Sem%02d", num);
|
||||||
|
|
||||||
|
HANDLE sem = CreateSemaphore(nullptr, 0, 64, semname);
|
||||||
|
SemPool[num] = sem;
|
||||||
|
SemInited[num] = true;
|
||||||
|
return sem != INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemDeinit(int num)
|
||||||
|
{
|
||||||
|
if (SemPool[num] != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(SemPool[num]);
|
||||||
|
SemPool[num] = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SemInited[num] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemPost(int num)
|
||||||
|
{
|
||||||
|
SemInit(num);
|
||||||
|
return ReleaseSemaphore(SemPool[num], 1, nullptr) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemWait(int num, int timeout)
|
||||||
|
{
|
||||||
|
return WaitForSingleObject(SemPool[num], timeout) == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemReset(int num)
|
||||||
|
{
|
||||||
|
while (WaitForSingleObject(SemPool[num], 0) == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
bool SemInited[32];
|
||||||
|
sem_t* SemPool[32];
|
||||||
|
|
||||||
|
void SemPoolInit()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
SemPool[i] = SEM_FAILED;
|
||||||
|
SemInited[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemDeinit(int num);
|
||||||
|
|
||||||
|
void SemPoolDeinit()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
SemDeinit(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemInit(int num)
|
||||||
|
{
|
||||||
|
if (SemInited[num])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char semname[64];
|
||||||
|
sprintf(semname, "/melonNIFI_Sem%02d", num);
|
||||||
|
|
||||||
|
sem_t* sem = sem_open(semname, O_CREAT, 0644, 0);
|
||||||
|
SemPool[num] = sem;
|
||||||
|
SemInited[num] = true;
|
||||||
|
return sem != SEM_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemDeinit(int num)
|
||||||
|
{
|
||||||
|
if (SemPool[num] != SEM_FAILED)
|
||||||
|
{
|
||||||
|
sem_close(SemPool[num]);
|
||||||
|
SemPool[num] = SEM_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
SemInited[num] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemPost(int num)
|
||||||
|
{
|
||||||
|
SemInit(num);
|
||||||
|
return sem_post(SemPool[num]) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemWait(int num, int timeout)
|
||||||
|
{
|
||||||
|
if (!timeout)
|
||||||
|
return sem_trywait(SemPool[num]) == 0;
|
||||||
|
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
ts.tv_nsec += timeout * 1000000;
|
||||||
|
long sec = ts.tv_nsec / 1000000000;
|
||||||
|
ts.tv_nsec -= sec * 1000000000;
|
||||||
|
ts.tv_sec += sec;
|
||||||
|
|
||||||
|
return sem_timedwait(SemPool[num], &ts) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemReset(int num)
|
||||||
|
{
|
||||||
|
while (sem_trywait(SemPool[num]) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
bool Init()
|
||||||
|
{
|
||||||
|
MPQueue = new QSharedMemory("melonNIFI");
|
||||||
|
|
||||||
|
if (!MPQueue->attach())
|
||||||
|
{
|
||||||
|
printf("MP sharedmem doesn't exist. creating\n");
|
||||||
|
if (!MPQueue->create(kQueueSize))
|
||||||
|
{
|
||||||
|
printf("MP sharedmem create failed :(\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->lock();
|
||||||
|
memset(MPQueue->data(), 0, MPQueue->size());
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||||
|
header->PacketWriteOffset = kPacketStart;
|
||||||
|
header->ReplyWriteOffset = kReplyStart;
|
||||||
|
MPQueue->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->lock();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||||
|
|
||||||
|
u16 mask = header->InstanceBitmask;
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (!(mask & (1<<i)))
|
||||||
|
{
|
||||||
|
InstanceID = i;
|
||||||
|
header->InstanceBitmask |= (1<<i);
|
||||||
|
//header->ConnectedBitmask |= (1 << i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header->NumInstances++;
|
||||||
|
|
||||||
|
PacketReadOffset = header->PacketWriteOffset;
|
||||||
|
ReplyReadOffset = header->ReplyWriteOffset;
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
|
||||||
|
// prepare semaphores
|
||||||
|
// semaphores 0-15: regular frames; semaphore I is posted when instance I needs to process a new frame
|
||||||
|
// semaphores 16-31: MP replies; semaphore I is posted when instance I needs to process a new MP reply
|
||||||
|
|
||||||
|
SemPoolInit();
|
||||||
|
SemInit(InstanceID);
|
||||||
|
SemInit(16+InstanceID);
|
||||||
|
|
||||||
|
LastHostID = -1;
|
||||||
|
|
||||||
|
printf("MP comm init OK, instance ID %d\n", InstanceID);
|
||||||
|
|
||||||
|
RecvTimeout = 25;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeInit()
|
||||||
|
{
|
||||||
|
MPQueue->lock();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||||
|
header->ConnectedBitmask &= ~(1 << InstanceID);
|
||||||
|
header->InstanceBitmask &= ~(1 << InstanceID);
|
||||||
|
header->NumInstances--;
|
||||||
|
MPQueue->unlock();
|
||||||
|
|
||||||
|
SemPoolDeinit();
|
||||||
|
|
||||||
|
MPQueue->detach();
|
||||||
|
delete MPQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRecvTimeout(int timeout)
|
||||||
|
{
|
||||||
|
RecvTimeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Begin()
|
||||||
|
{
|
||||||
|
MPQueue->lock();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||||
|
PacketReadOffset = header->PacketWriteOffset;
|
||||||
|
ReplyReadOffset = header->ReplyWriteOffset;
|
||||||
|
SemReset(InstanceID);
|
||||||
|
SemReset(16+InstanceID);
|
||||||
|
header->ConnectedBitmask |= (1 << InstanceID);
|
||||||
|
MPQueue->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void End()
|
||||||
|
{
|
||||||
|
MPQueue->lock();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||||
|
//SemReset(InstanceID);
|
||||||
|
//SemReset(16+InstanceID);
|
||||||
|
header->ConnectedBitmask &= ~(1 << InstanceID);
|
||||||
|
MPQueue->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FIFORead(int fifo, void* buf, int len)
|
||||||
|
{
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
|
||||||
|
u32 offset, start, end;
|
||||||
|
if (fifo == 0)
|
||||||
|
{
|
||||||
|
offset = PacketReadOffset;
|
||||||
|
start = kPacketStart;
|
||||||
|
end = kPacketEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = ReplyReadOffset;
|
||||||
|
start = kReplyStart;
|
||||||
|
end = kReplyEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset + len) >= end)
|
||||||
|
{
|
||||||
|
u32 part1 = end - offset;
|
||||||
|
memcpy(buf, &data[offset], part1);
|
||||||
|
memcpy(&((u8*)buf)[part1], &data[start], len - part1);
|
||||||
|
offset = start + len - part1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buf, &data[offset], len);
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifo == 0) PacketReadOffset = offset;
|
||||||
|
else ReplyReadOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FIFOWrite(int fifo, void* buf, int len)
|
||||||
|
{
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
|
||||||
|
u32 offset, start, end;
|
||||||
|
if (fifo == 0)
|
||||||
|
{
|
||||||
|
offset = header->PacketWriteOffset;
|
||||||
|
start = kPacketStart;
|
||||||
|
end = kPacketEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = header->ReplyWriteOffset;
|
||||||
|
start = kReplyStart;
|
||||||
|
end = kReplyEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset + len) >= end)
|
||||||
|
{
|
||||||
|
u32 part1 = end - offset;
|
||||||
|
memcpy(&data[offset], buf, part1);
|
||||||
|
memcpy(&data[start], &((u8*)buf)[part1], len - part1);
|
||||||
|
offset = start + len - part1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&data[offset], buf, len);
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifo == 0) header->PacketWriteOffset = offset;
|
||||||
|
else header->ReplyWriteOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp)
|
||||||
|
{
|
||||||
|
MPQueue->lock();
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
|
||||||
|
u16 mask = header->ConnectedBitmask;
|
||||||
|
|
||||||
|
// TODO: check if the FIFO is full!
|
||||||
|
|
||||||
|
MPPacketHeader pktheader;
|
||||||
|
pktheader.Magic = 0x4946494E;
|
||||||
|
pktheader.SenderID = InstanceID;
|
||||||
|
pktheader.Type = type;
|
||||||
|
pktheader.Length = len;
|
||||||
|
pktheader.Timestamp = timestamp;
|
||||||
|
|
||||||
|
type &= 0xFFFF;
|
||||||
|
int nfifo = (type == 2) ? 1 : 0;
|
||||||
|
FIFOWrite(nfifo, &pktheader, sizeof(pktheader));
|
||||||
|
if (len)
|
||||||
|
FIFOWrite(nfifo, packet, len);
|
||||||
|
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
// NOTE: this is not guarded against, say, multiple multiplay games happening on the same machine
|
||||||
|
// we would need to pass the packet's SenderID through the wifi module for that
|
||||||
|
header->MPHostInstanceID = InstanceID;
|
||||||
|
header->MPReplyBitmask = 0;
|
||||||
|
ReplyReadOffset = header->ReplyWriteOffset;
|
||||||
|
SemReset(16 + InstanceID);
|
||||||
|
}
|
||||||
|
else if (type == 2)
|
||||||
|
{
|
||||||
|
header->MPReplyBitmask |= (1 << InstanceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
SemPost(16 + header->MPHostInstanceID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (mask & (1<<i))
|
||||||
|
SemPost(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RecvPacketGeneric(u8* packet, bool block, u64* timestamp)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!SemWait(InstanceID, block ? RecvTimeout : 0))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->lock();
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
|
||||||
|
MPPacketHeader pktheader;
|
||||||
|
FIFORead(0, &pktheader, sizeof(pktheader));
|
||||||
|
|
||||||
|
if (pktheader.Magic != 0x4946494E)
|
||||||
|
{
|
||||||
|
printf("PACKET FIFO OVERFLOW\n");
|
||||||
|
PacketReadOffset = header->PacketWriteOffset;
|
||||||
|
SemReset(InstanceID);
|
||||||
|
MPQueue->unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pktheader.SenderID == InstanceID)
|
||||||
|
{
|
||||||
|
// skip this packet
|
||||||
|
PacketReadOffset += pktheader.Length;
|
||||||
|
if (PacketReadOffset >= kPacketEnd)
|
||||||
|
PacketReadOffset += kPacketStart - kPacketEnd;
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pktheader.Length)
|
||||||
|
{
|
||||||
|
FIFORead(0, packet, pktheader.Length);
|
||||||
|
|
||||||
|
if (pktheader.Type == 1)
|
||||||
|
LastHostID = pktheader.SenderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp) *timestamp = pktheader.Timestamp;
|
||||||
|
MPQueue->unlock();
|
||||||
|
return pktheader.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendPacket(u8* packet, int len, u64 timestamp)
|
||||||
|
{
|
||||||
|
return SendPacketGeneric(0, packet, len, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RecvPacket(u8* packet, u64* timestamp)
|
||||||
|
{
|
||||||
|
return RecvPacketGeneric(packet, false, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SendCmd(u8* packet, int len, u64 timestamp)
|
||||||
|
{
|
||||||
|
return SendPacketGeneric(1, packet, len, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendReply(u8* packet, int len, u64 timestamp, u16 aid)
|
||||||
|
{
|
||||||
|
return SendPacketGeneric(2 | (aid<<16), packet, len, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendAck(u8* packet, int len, u64 timestamp)
|
||||||
|
{
|
||||||
|
return SendPacketGeneric(3, packet, len, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RecvHostPacket(u8* packet, u64* timestamp)
|
||||||
|
{
|
||||||
|
if (LastHostID != -1)
|
||||||
|
{
|
||||||
|
// check if the host is still connected
|
||||||
|
|
||||||
|
MPQueue->lock();
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
u16 curinstmask = header->ConnectedBitmask;
|
||||||
|
MPQueue->unlock();
|
||||||
|
|
||||||
|
if (!(curinstmask & (1 << LastHostID)))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RecvPacketGeneric(packet, true, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask)
|
||||||
|
{
|
||||||
|
u16 ret = 0;
|
||||||
|
u16 myinstmask = (1 << InstanceID);
|
||||||
|
u16 curinstmask;
|
||||||
|
|
||||||
|
{
|
||||||
|
MPQueue->lock();
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
curinstmask = header->ConnectedBitmask;
|
||||||
|
MPQueue->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all clients have left: return early
|
||||||
|
if ((myinstmask & curinstmask) == curinstmask)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!SemWait(16+InstanceID, RecvTimeout))
|
||||||
|
{
|
||||||
|
// no more replies available
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->lock();
|
||||||
|
u8* data = (u8*)MPQueue->data();
|
||||||
|
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||||
|
|
||||||
|
MPPacketHeader pktheader;
|
||||||
|
FIFORead(1, &pktheader, sizeof(pktheader));
|
||||||
|
|
||||||
|
if (pktheader.Magic != 0x4946494E)
|
||||||
|
{
|
||||||
|
printf("REPLY FIFO OVERFLOW\n");
|
||||||
|
ReplyReadOffset = header->ReplyWriteOffset;
|
||||||
|
SemReset(16+InstanceID);
|
||||||
|
MPQueue->unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pktheader.SenderID == InstanceID) || // packet we sent out (shouldn't happen, but hey)
|
||||||
|
(pktheader.Timestamp < (timestamp - 32))) // stale packet
|
||||||
|
{
|
||||||
|
// skip this packet
|
||||||
|
ReplyReadOffset += pktheader.Length;
|
||||||
|
if (ReplyReadOffset >= kReplyEnd)
|
||||||
|
ReplyReadOffset += kReplyStart - kReplyEnd;
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pktheader.Length)
|
||||||
|
{
|
||||||
|
u32 aid = (pktheader.Type >> 16);
|
||||||
|
FIFORead(1, &packets[(aid-1)*1024], pktheader.Length);
|
||||||
|
ret |= (1 << aid);
|
||||||
|
}
|
||||||
|
|
||||||
|
myinstmask |= (1 << pktheader.SenderID);
|
||||||
|
if (((myinstmask & curinstmask) == curinstmask) ||
|
||||||
|
((ret & aidmask) == aidmask))
|
||||||
|
{
|
||||||
|
// all the clients have sent their reply
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPQueue->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOCALMP_H
|
||||||
|
#define LOCALMP_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace LocalMP
|
||||||
|
{
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
void DeInit();
|
||||||
|
|
||||||
|
void SetRecvTimeout(int timeout);
|
||||||
|
|
||||||
|
void Begin();
|
||||||
|
void End();
|
||||||
|
|
||||||
|
int SendPacket(u8* data, int len, u64 timestamp);
|
||||||
|
int RecvPacket(u8* data, u64* timestamp);
|
||||||
|
int SendCmd(u8* data, int len, u64 timestamp);
|
||||||
|
int SendReply(u8* data, int len, u64 timestamp, u16 aid);
|
||||||
|
int SendAck(u8* data, int len, u64 timestamp);
|
||||||
|
int RecvHostPacket(u8* data, u64* timestamp);
|
||||||
|
u16 RecvReplies(u8* data, u64 timestamp, u16 aidmask);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LOCALMP_H
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "LAN_Socket.h"
|
||||||
|
#include "LAN_PCap.h"
|
||||||
|
#include "Wifi.h"
|
||||||
|
|
||||||
|
#include "MPSettingsDialog.h"
|
||||||
|
#include "ui_MPSettingsDialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
MPSettingsDialog* MPSettingsDialog::currentDlg = nullptr;
|
||||||
|
|
||||||
|
extern bool RunningSomething;
|
||||||
|
|
||||||
|
|
||||||
|
MPSettingsDialog::MPSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::MPSettingsDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
grpAudioMode = new QButtonGroup(this);
|
||||||
|
grpAudioMode->addButton(ui->rbAudioAll, 0);
|
||||||
|
grpAudioMode->addButton(ui->rbAudioOneOnly, 1);
|
||||||
|
grpAudioMode->addButton(ui->rbAudioActiveOnly, 2);
|
||||||
|
grpAudioMode->button(Config::MPAudioMode)->setChecked(true);
|
||||||
|
|
||||||
|
ui->sbReceiveTimeout->setValue(Config::MPRecvTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPSettingsDialog::~MPSettingsDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPSettingsDialog::done(int r)
|
||||||
|
{
|
||||||
|
if (r == QDialog::Accepted)
|
||||||
|
{
|
||||||
|
Config::MPAudioMode = grpAudioMode->checkedId();
|
||||||
|
Config::MPRecvTimeout = ui->sbReceiveTimeout->value();
|
||||||
|
|
||||||
|
Config::Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::done(r);
|
||||||
|
|
||||||
|
closeDlg();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPSETTINGSDIALOG_H
|
||||||
|
#define MPSETTINGSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QButtonGroup>
|
||||||
|
|
||||||
|
namespace Ui { class MPSettingsDialog; }
|
||||||
|
class MPSettingsDialog;
|
||||||
|
|
||||||
|
class MPSettingsDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MPSettingsDialog(QWidget* parent);
|
||||||
|
~MPSettingsDialog();
|
||||||
|
|
||||||
|
static MPSettingsDialog* currentDlg;
|
||||||
|
static MPSettingsDialog* openDlg(QWidget* parent)
|
||||||
|
{
|
||||||
|
if (currentDlg)
|
||||||
|
{
|
||||||
|
currentDlg->activateWindow();
|
||||||
|
return currentDlg;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDlg = new MPSettingsDialog(parent);
|
||||||
|
currentDlg->open();
|
||||||
|
return currentDlg;
|
||||||
|
}
|
||||||
|
static void closeDlg()
|
||||||
|
{
|
||||||
|
currentDlg = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void done(int r);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MPSettingsDialog* ui;
|
||||||
|
|
||||||
|
QButtonGroup* grpAudioMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MPSETTINGSDIALOG_H
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MPSettingsDialog</class>
|
||||||
|
<widget class="QDialog" name="MPSettingsDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>466</width>
|
||||||
|
<height>202</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Multiplayer settings - melonDS</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Audio output</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QRadioButton" name="rbAudioOneOnly">
|
||||||
|
<property name="text">
|
||||||
|
<string>Instance 1 only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QRadioButton" name="rbAudioAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>All instances</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QRadioButton" name="rbAudioActiveOnly">
|
||||||
|
<property name="text">
|
||||||
|
<string>Active instance only</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Network</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="sbReceiveTimeout">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data reception timeout: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>milliseconds</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>MPSettingsDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>MPSettingsDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -146,7 +146,7 @@ void LayoutText(const char* text, u32* width, u32* height, int* breaks)
|
||||||
u32 w = 0;
|
u32 w = 0;
|
||||||
u32 h = 14;
|
u32 h = 14;
|
||||||
u32 totalw = 0;
|
u32 totalw = 0;
|
||||||
u32 maxw = mainWindow->panel->width() - (kOSDMargin*2);
|
u32 maxw = mainWindow->panelWidget->width() - (kOSDMargin*2);
|
||||||
int lastbreak = -1;
|
int lastbreak = -1;
|
||||||
int numbrk = 0;
|
int numbrk = 0;
|
||||||
u16* ptr;
|
u16* ptr;
|
||||||
|
@ -236,7 +236,7 @@ void RenderText(u32 color, const char* text, Item* item)
|
||||||
memset(item->Bitmap, 0, w*h*sizeof(u32));
|
memset(item->Bitmap, 0, w*h*sizeof(u32));
|
||||||
|
|
||||||
u32 x = 0, y = 1;
|
u32 x = 0, y = 1;
|
||||||
u32 maxw = mainWindow->panel->width() - (kOSDMargin*2);
|
u32 maxw = mainWindow->panelWidget->width() - (kOSDMargin*2);
|
||||||
int curline = 0;
|
int curline = 0;
|
||||||
u16* ptr;
|
u16* ptr;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
#include "PathSettingsDialog.h"
|
#include "PathSettingsDialog.h"
|
||||||
#include "ui_PathSettingsDialog.h"
|
#include "ui_PathSettingsDialog.h"
|
||||||
|
@ -43,6 +44,12 @@ PathSettingsDialog::PathSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
|
||||||
ui->txtSaveFilePath->setText(QString::fromStdString(Config::SaveFilePath));
|
ui->txtSaveFilePath->setText(QString::fromStdString(Config::SaveFilePath));
|
||||||
ui->txtSavestatePath->setText(QString::fromStdString(Config::SavestatePath));
|
ui->txtSavestatePath->setText(QString::fromStdString(Config::SavestatePath));
|
||||||
ui->txtCheatFilePath->setText(QString::fromStdString(Config::CheatFilePath));
|
ui->txtCheatFilePath->setText(QString::fromStdString(Config::CheatFilePath));
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
ui->lblInstanceNum->setText(QString("Configuring paths for instance %1").arg(inst+1));
|
||||||
|
else
|
||||||
|
ui->lblInstanceNum->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
PathSettingsDialog::~PathSettingsDialog()
|
PathSettingsDialog::~PathSettingsDialog()
|
||||||
|
|
|
@ -7,49 +7,63 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>439</width>
|
<width>439</width>
|
||||||
<height>166</height>
|
<height>185</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Path settings - melonDS</string>
|
<string>Path settings - melonDS</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="1">
|
<item row="3" column="0">
|
||||||
<widget class="QLineEdit" name="txtSaveFilePath">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="clearButtonEnabled">
|
<property name="text">
|
||||||
<bool>true</bool>
|
<string>Cheat files path:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="3" column="2">
|
||||||
<widget class="QPushButton" name="btnCheatFileBrowse">
|
<widget class="QPushButton" name="btnCheatFileBrowse">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Browse...</string>
|
<string>Browse...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Savestates path:</string>
|
<string>Savestates path:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="5" column="0" colspan="3">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="txtSavestatePath">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="btnSaveFileBrowse">
|
||||||
|
<property name="text">
|
||||||
|
<string>Browse...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="txtCheatFilePath">
|
<widget class="QLineEdit" name="txtCheatFilePath">
|
||||||
<property name="clearButtonEnabled">
|
<property name="clearButtonEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="3">
|
<item row="6" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Leave a path blank to use the current ROM's path.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" colspan="3">
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -59,35 +73,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="2">
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string>Cheat files path:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QPushButton" name="btnSaveFileBrowse">
|
|
||||||
<property name="text">
|
|
||||||
<string>Browse...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QPushButton" name="btnSavestateBrowse">
|
<widget class="QPushButton" name="btnSavestateBrowse">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Browse...</string>
|
<string>Browse...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="0">
|
||||||
<widget class="QLineEdit" name="txtSavestatePath">
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save files path:</string>
|
<string>Save files path:</string>
|
||||||
|
@ -95,9 +88,23 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0" colspan="3">
|
<item row="4" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>Leave a path blank to use the current ROM's path.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="txtSaveFilePath">
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="3">
|
||||||
|
<widget class="QLabel" name="lblInstanceNum">
|
||||||
|
<property name="text">
|
||||||
|
<string>Configuring paths for instance X</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -20,28 +20,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#include <string>
|
||||||
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
//#include <knownfolders.h> // FUCK THAT SHIT
|
|
||||||
#include <shlobj.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <io.h>
|
|
||||||
#define dup _dup
|
|
||||||
#define socket_t SOCKET
|
|
||||||
#define sockaddr_t SOCKADDR
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#define socket_t int
|
|
||||||
#define sockaddr_t struct sockaddr
|
|
||||||
#define closesocket close
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -49,6 +28,7 @@
|
||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
|
#include <QSharedMemory>
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
@ -56,11 +36,7 @@
|
||||||
#include "CameraManager.h"
|
#include "CameraManager.h"
|
||||||
#include "LAN_Socket.h"
|
#include "LAN_Socket.h"
|
||||||
#include "LAN_PCap.h"
|
#include "LAN_PCap.h"
|
||||||
#include <string>
|
#include "LocalMP.h"
|
||||||
|
|
||||||
#ifndef INVALID_SOCKET
|
|
||||||
#define INVALID_SOCKET (socket_t)-1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
std::string EmuDirectory;
|
std::string EmuDirectory;
|
||||||
|
@ -73,11 +49,63 @@ extern CameraManager* camManager[2];
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
|
|
||||||
socket_t MPSocket;
|
QSharedMemory* IPCBuffer = nullptr;
|
||||||
sockaddr_t MPSendAddr;
|
int IPCInstanceID;
|
||||||
u8 PacketBuffer[2048];
|
|
||||||
|
|
||||||
#define NIFI_VER 1
|
void IPCInit()
|
||||||
|
{
|
||||||
|
IPCInstanceID = 0;
|
||||||
|
|
||||||
|
IPCBuffer = new QSharedMemory("melonIPC");
|
||||||
|
|
||||||
|
if (!IPCBuffer->attach())
|
||||||
|
{
|
||||||
|
printf("IPC sharedmem doesn't exist. creating\n");
|
||||||
|
if (!IPCBuffer->create(1024))
|
||||||
|
{
|
||||||
|
printf("IPC sharedmem create failed :(\n");
|
||||||
|
delete IPCBuffer;
|
||||||
|
IPCBuffer = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCBuffer->lock();
|
||||||
|
memset(IPCBuffer->data(), 0, IPCBuffer->size());
|
||||||
|
IPCBuffer->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCBuffer->lock();
|
||||||
|
u8* data = (u8*)IPCBuffer->data();
|
||||||
|
u16 mask = *(u16*)&data[0];
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (!(mask & (1<<i)))
|
||||||
|
{
|
||||||
|
IPCInstanceID = i;
|
||||||
|
*(u16*)&data[0] |= (1<<i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPCBuffer->unlock();
|
||||||
|
|
||||||
|
printf("IPC: instance ID %d\n", IPCInstanceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPCDeInit()
|
||||||
|
{
|
||||||
|
if (IPCBuffer)
|
||||||
|
{
|
||||||
|
IPCBuffer->lock();
|
||||||
|
u8* data = (u8*)IPCBuffer->data();
|
||||||
|
*(u16*)&data[0] &= ~(1<<IPCInstanceID);
|
||||||
|
IPCBuffer->unlock();
|
||||||
|
|
||||||
|
IPCBuffer->detach();
|
||||||
|
delete IPCBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Init(int argc, char** argv)
|
void Init(int argc, char** argv)
|
||||||
|
@ -113,10 +141,13 @@ void Init(int argc, char** argv)
|
||||||
confdir = config.absolutePath() + "/melonDS/";
|
confdir = config.absolutePath() + "/melonDS/";
|
||||||
EmuDirectory = confdir.toStdString();
|
EmuDirectory = confdir.toStdString();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
IPCInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
|
IPCDeInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +157,22 @@ void StopEmu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InstanceID()
|
||||||
|
{
|
||||||
|
return IPCInstanceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string InstanceFileSuffix()
|
||||||
|
{
|
||||||
|
int inst = IPCInstanceID;
|
||||||
|
if (inst == 0) return "";
|
||||||
|
|
||||||
|
char suffix[16] = {0};
|
||||||
|
snprintf(suffix, 15, ".%d", inst+1);
|
||||||
|
return suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int GetConfigInt(ConfigEntry entry)
|
int GetConfigInt(ConfigEntry entry)
|
||||||
{
|
{
|
||||||
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
|
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
|
||||||
|
@ -172,7 +219,6 @@ bool GetConfigBool(ConfigEntry entry)
|
||||||
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
|
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
|
||||||
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
|
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
|
||||||
|
|
||||||
case Firm_RandomizeMAC: return Config::RandomizeMAC != 0;
|
|
||||||
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
|
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,146 +440,60 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool MP_Init()
|
bool MP_Init()
|
||||||
{
|
{
|
||||||
int opt_true = 1;
|
return LocalMP::Init();
|
||||||
int res;
|
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
WSADATA wsadata;
|
|
||||||
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif // __WIN32__
|
|
||||||
|
|
||||||
MPSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (MPSocket < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt_true, sizeof(int));
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
closesocket(MPSocket);
|
|
||||||
MPSocket = INVALID_SOCKET;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BSD) || defined(__APPLE__)
|
|
||||||
res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt_true, sizeof(int));
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
closesocket(MPSocket);
|
|
||||||
MPSocket = INVALID_SOCKET;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sockaddr_t saddr;
|
|
||||||
saddr.sa_family = AF_INET;
|
|
||||||
*(u32*)&saddr.sa_data[2] = htonl(Config::SocketBindAnyAddr ? INADDR_ANY : INADDR_LOOPBACK);
|
|
||||||
*(u16*)&saddr.sa_data[0] = htons(7064);
|
|
||||||
res = bind(MPSocket, &saddr, sizeof(sockaddr_t));
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
closesocket(MPSocket);
|
|
||||||
MPSocket = INVALID_SOCKET;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = setsockopt(MPSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&opt_true, sizeof(int));
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
closesocket(MPSocket);
|
|
||||||
MPSocket = INVALID_SOCKET;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MPSendAddr.sa_family = AF_INET;
|
|
||||||
*(u32*)&MPSendAddr.sa_data[2] = htonl(INADDR_BROADCAST);
|
|
||||||
*(u16*)&MPSendAddr.sa_data[0] = htons(7064);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MP_DeInit()
|
void MP_DeInit()
|
||||||
{
|
{
|
||||||
if (MPSocket >= 0)
|
return LocalMP::DeInit();
|
||||||
closesocket(MPSocket);
|
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
WSACleanup();
|
|
||||||
#endif // __WIN32__
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MP_SendPacket(u8* data, int len)
|
void MP_Begin()
|
||||||
{
|
{
|
||||||
if (MPSocket < 0)
|
return LocalMP::Begin();
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (len > 2048-8)
|
|
||||||
{
|
|
||||||
printf("MP_SendPacket: error: packet too long (%d)\n", len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(u32*)&PacketBuffer[0] = htonl(0x4946494E); // NIFI
|
|
||||||
PacketBuffer[4] = NIFI_VER;
|
|
||||||
PacketBuffer[5] = 0;
|
|
||||||
*(u16*)&PacketBuffer[6] = htons(len);
|
|
||||||
memcpy(&PacketBuffer[8], data, len);
|
|
||||||
|
|
||||||
int slen = sendto(MPSocket, (const char*)PacketBuffer, len+8, 0, &MPSendAddr, sizeof(sockaddr_t));
|
|
||||||
if (slen < 8) return 0;
|
|
||||||
return slen - 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MP_RecvPacket(u8* data, bool block)
|
void MP_End()
|
||||||
{
|
{
|
||||||
if (MPSocket < 0)
|
return LocalMP::End();
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
fd_set fd;
|
int MP_SendPacket(u8* data, int len, u64 timestamp)
|
||||||
struct timeval tv;
|
{
|
||||||
|
return LocalMP::SendPacket(data, len, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
FD_ZERO(&fd);
|
int MP_RecvPacket(u8* data, u64* timestamp)
|
||||||
FD_SET(MPSocket, &fd);
|
{
|
||||||
tv.tv_sec = 0;
|
return LocalMP::RecvPacket(data, timestamp);
|
||||||
tv.tv_usec = block ? 5000 : 0;
|
}
|
||||||
|
|
||||||
if (!select(MPSocket+1, &fd, 0, 0, &tv))
|
int MP_SendCmd(u8* data, int len, u64 timestamp)
|
||||||
{
|
{
|
||||||
return 0;
|
return LocalMP::SendCmd(data, len, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_t fromAddr;
|
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid)
|
||||||
socklen_t fromLen = sizeof(sockaddr_t);
|
{
|
||||||
int rlen = recvfrom(MPSocket, (char*)PacketBuffer, 2048, 0, &fromAddr, &fromLen);
|
return LocalMP::SendReply(data, len, timestamp, aid);
|
||||||
if (rlen < 8+24)
|
}
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
rlen -= 8;
|
|
||||||
|
|
||||||
if (ntohl(*(u32*)&PacketBuffer[0]) != 0x4946494E)
|
int MP_SendAck(u8* data, int len, u64 timestamp)
|
||||||
{
|
{
|
||||||
return 0;
|
return LocalMP::SendAck(data, len, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PacketBuffer[4] != NIFI_VER)
|
int MP_RecvHostPacket(u8* data, u64* timestamp)
|
||||||
{
|
{
|
||||||
return 0;
|
return LocalMP::RecvHostPacket(data, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntohs(*(u16*)&PacketBuffer[6]) != rlen)
|
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask)
|
||||||
{
|
{
|
||||||
return 0;
|
return LocalMP::RecvReplies(data, timestamp, aidmask);
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(data, &PacketBuffer[8], rlen);
|
|
||||||
return rlen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "DSi_I2C.h"
|
#include "DSi_I2C.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -65,6 +66,12 @@ PowerManagementDialog::PowerManagementDialog(QWidget* parent) : QDialog(parent),
|
||||||
}
|
}
|
||||||
ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos);
|
ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos);
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst > 0)
|
||||||
|
ui->lblInstanceNum->setText(QString("Setting battery levels for instance %1").arg(inst+1));
|
||||||
|
else
|
||||||
|
ui->lblInstanceNum->hide();
|
||||||
|
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>562</width>
|
<width>562</width>
|
||||||
<height>279</height>
|
<height>288</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -23,37 +23,7 @@
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
<enum>QLayout::SetFixedSize</enum>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QGroupBox" name="grpDSBattery">
|
|
||||||
<property name="title">
|
|
||||||
<string>DS Battery</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QRadioButton" name="rbDSBatteryLow">
|
|
||||||
<property name="text">
|
|
||||||
<string>Low</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" rowspan="2">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Battery Level</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QRadioButton" name="rbDSBatteryOkay">
|
|
||||||
<property name="text">
|
|
||||||
<string>Okay</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -63,7 +33,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QGroupBox" name="grpDSiBattery">
|
<widget class="QGroupBox" name="grpDSiBattery">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>DSi Battery</string>
|
<string>DSi Battery</string>
|
||||||
|
@ -219,6 +189,49 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="grpDSBattery">
|
||||||
|
<property name="title">
|
||||||
|
<string>DS Battery</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QRadioButton" name="rbDSBatteryLow">
|
||||||
|
<property name="text">
|
||||||
|
<string>Low</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" rowspan="2">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Battery Level</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QRadioButton" name="rbDSBatteryOkay">
|
||||||
|
<property name="text">
|
||||||
|
<string>Okay</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="lblInstanceNum">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Configuring settings for instance X</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -75,12 +75,12 @@ ROMInfoDialog::ROMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ROMI
|
||||||
|
|
||||||
ui->iconTitle->setText(QString::fromUtf16(NDSCart::Banner.EnglishTitle));
|
ui->iconTitle->setText(QString::fromUtf16(NDSCart::Banner.EnglishTitle));
|
||||||
|
|
||||||
ui->japaneseTitle->setText(QString::fromUtf16(NDSCart::Banner.JapaneseTitle, 128));
|
ui->japaneseTitle->setText(QString::fromUtf16(NDSCart::Banner.JapaneseTitle));
|
||||||
ui->englishTitle->setText(QString::fromUtf16(NDSCart::Banner.EnglishTitle, 128));
|
ui->englishTitle->setText(QString::fromUtf16(NDSCart::Banner.EnglishTitle));
|
||||||
ui->frenchTitle->setText(QString::fromUtf16(NDSCart::Banner.FrenchTitle, 128));
|
ui->frenchTitle->setText(QString::fromUtf16(NDSCart::Banner.FrenchTitle));
|
||||||
ui->germanTitle->setText(QString::fromUtf16(NDSCart::Banner.GermanTitle, 128));
|
ui->germanTitle->setText(QString::fromUtf16(NDSCart::Banner.GermanTitle));
|
||||||
ui->italianTitle->setText(QString::fromUtf16(NDSCart::Banner.ItalianTitle, 128));
|
ui->italianTitle->setText(QString::fromUtf16(NDSCart::Banner.ItalianTitle));
|
||||||
ui->spanishTitle->setText(QString::fromUtf16(NDSCart::Banner.SpanishTitle, 128));
|
ui->spanishTitle->setText(QString::fromUtf16(NDSCart::Banner.SpanishTitle));
|
||||||
|
|
||||||
if (NDSCart::Banner.Version > 1)
|
if (NDSCart::Banner.Version > 1)
|
||||||
ui->chineseTitle->setText(QString::fromUtf16(NDSCart::Banner.ChineseTitle));
|
ui->chineseTitle->setText(QString::fromUtf16(NDSCart::Banner.ChineseTitle));
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>427</width>
|
<width>559</width>
|
||||||
<height>434</height>
|
<height>532</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -22,12 +22,6 @@
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QGroupBox" name="titles">
|
<widget class="QGroupBox" name="titles">
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Titles</string>
|
<string>Titles</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -350,12 +344,6 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QGroupBox" name="filesystem">
|
<widget class="QGroupBox" name="filesystem">
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Filesystem</string>
|
<string>Filesystem</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -441,12 +429,6 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QGroupBox" name="generalInfo">
|
<widget class="QGroupBox" name="generalInfo">
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>General info</string>
|
<string>General info</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -668,7 +650,7 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="3">
|
<item row="0" column="2">
|
||||||
<widget class="QGroupBox" name="dsiIconBox">
|
<widget class="QGroupBox" name="dsiIconBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
@ -742,43 +724,11 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="3">
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>55</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="4">
|
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2">
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
|
@ -788,6 +738,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -326,6 +326,7 @@ bool LoadState(std::string filename)
|
||||||
|
|
||||||
std::string savefile = filename.substr(LastSep(filename)+1);
|
std::string savefile = filename.substr(LastSep(filename)+1);
|
||||||
savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
|
savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
|
||||||
|
savefile += Platform::InstanceFileSuffix();
|
||||||
NDSSave->SetPath(savefile, true);
|
NDSSave->SetPath(savefile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +351,7 @@ bool SaveState(std::string filename)
|
||||||
{
|
{
|
||||||
std::string savefile = filename.substr(LastSep(filename)+1);
|
std::string savefile = filename.substr(LastSep(filename)+1);
|
||||||
savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
|
savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
|
||||||
|
savefile += Platform::InstanceFileSuffix();
|
||||||
NDSSave->SetPath(savefile, false);
|
NDSSave->SetPath(savefile, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +434,7 @@ void Reset()
|
||||||
{
|
{
|
||||||
std::string oldsave = NDSSave->GetPath();
|
std::string oldsave = NDSSave->GetPath();
|
||||||
std::string newsave = GetAssetPath(false, Config::SaveFilePath, ".sav");
|
std::string newsave = GetAssetPath(false, Config::SaveFilePath, ".sav");
|
||||||
|
newsave += Platform::InstanceFileSuffix();
|
||||||
if (oldsave != newsave)
|
if (oldsave != newsave)
|
||||||
NDSSave->SetPath(newsave, false);
|
NDSSave->SetPath(newsave, false);
|
||||||
}
|
}
|
||||||
|
@ -440,6 +443,7 @@ void Reset()
|
||||||
{
|
{
|
||||||
std::string oldsave = GBASave->GetPath();
|
std::string oldsave = GBASave->GetPath();
|
||||||
std::string newsave = GetAssetPath(true, Config::SaveFilePath, ".sav");
|
std::string newsave = GetAssetPath(true, Config::SaveFilePath, ".sav");
|
||||||
|
newsave += Platform::InstanceFileSuffix();
|
||||||
if (oldsave != newsave)
|
if (oldsave != newsave)
|
||||||
GBASave->SetPath(newsave, false);
|
GBASave->SetPath(newsave, false);
|
||||||
}
|
}
|
||||||
|
@ -562,7 +566,11 @@ bool LoadROM(QStringList filepath, bool reset)
|
||||||
u8* savedata = nullptr;
|
u8* savedata = nullptr;
|
||||||
|
|
||||||
std::string savname = GetAssetPath(false, Config::SaveFilePath, ".sav");
|
std::string savname = GetAssetPath(false, Config::SaveFilePath, ".sav");
|
||||||
|
std::string origsav = savname;
|
||||||
|
savname += Platform::InstanceFileSuffix();
|
||||||
|
|
||||||
FILE* sav = Platform::OpenFile(savname, "rb", true);
|
FILE* sav = Platform::OpenFile(savname, "rb", true);
|
||||||
|
if (!sav) sav = Platform::OpenFile(origsav, "rb", true);
|
||||||
if (sav)
|
if (sav)
|
||||||
{
|
{
|
||||||
fseek(sav, 0, SEEK_END);
|
fseek(sav, 0, SEEK_END);
|
||||||
|
@ -711,7 +719,11 @@ bool LoadGBAROM(QStringList filepath)
|
||||||
u8* savedata = nullptr;
|
u8* savedata = nullptr;
|
||||||
|
|
||||||
std::string savname = GetAssetPath(true, Config::SaveFilePath, ".sav");
|
std::string savname = GetAssetPath(true, Config::SaveFilePath, ".sav");
|
||||||
|
std::string origsav = savname;
|
||||||
|
savname += Platform::InstanceFileSuffix();
|
||||||
|
|
||||||
FILE* sav = Platform::OpenFile(savname, "rb", true);
|
FILE* sav = Platform::OpenFile(savname, "rb", true);
|
||||||
|
if (!sav) sav = Platform::OpenFile(origsav, "rb", true);
|
||||||
if (sav)
|
if (sav)
|
||||||
{
|
{
|
||||||
fseek(sav, 0, SEEK_END);
|
fseek(sav, 0, SEEK_END);
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "ui_TitleImportDialog.h"
|
#include "ui_TitleImportDialog.h"
|
||||||
|
|
||||||
|
|
||||||
FILE* TitleManagerDialog::curNAND = nullptr;
|
bool TitleManagerDialog::NANDInited = false;
|
||||||
TitleManagerDialog* TitleManagerDialog::currentDlg = nullptr;
|
TitleManagerDialog* TitleManagerDialog::currentDlg = nullptr;
|
||||||
|
|
||||||
extern std::string EmuDirectory;
|
extern std::string EmuDirectory;
|
||||||
|
@ -136,6 +136,8 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid)
|
||||||
|
|
||||||
bool TitleManagerDialog::openNAND()
|
bool TitleManagerDialog::openNAND()
|
||||||
{
|
{
|
||||||
|
NANDInited = false;
|
||||||
|
|
||||||
FILE* bios7i = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
|
FILE* bios7i = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
|
||||||
if (!bios7i)
|
if (!bios7i)
|
||||||
return false;
|
return false;
|
||||||
|
@ -145,28 +147,21 @@ bool TitleManagerDialog::openNAND()
|
||||||
fread(es_keyY, 16, 1, bios7i);
|
fread(es_keyY, 16, 1, bios7i);
|
||||||
fclose(bios7i);
|
fclose(bios7i);
|
||||||
|
|
||||||
curNAND = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
|
if (!DSi_NAND::Init(es_keyY))
|
||||||
if (!curNAND)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!DSi_NAND::Init(curNAND, es_keyY))
|
|
||||||
{
|
{
|
||||||
fclose(curNAND);
|
|
||||||
curNAND = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NANDInited = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleManagerDialog::closeNAND()
|
void TitleManagerDialog::closeNAND()
|
||||||
{
|
{
|
||||||
if (curNAND)
|
if (NANDInited)
|
||||||
{
|
{
|
||||||
DSi_NAND::DeInit();
|
DSi_NAND::DeInit();
|
||||||
|
NANDInited = false;
|
||||||
fclose(curNAND);
|
|
||||||
curNAND = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
explicit TitleManagerDialog(QWidget* parent);
|
explicit TitleManagerDialog(QWidget* parent);
|
||||||
~TitleManagerDialog();
|
~TitleManagerDialog();
|
||||||
|
|
||||||
static FILE* curNAND;
|
static bool NANDInited;
|
||||||
static bool openNAND();
|
static bool openNAND();
|
||||||
static void closeNAND();
|
static void closeNAND();
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,12 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
LAN_Socket::Init();
|
|
||||||
haspcap = LAN_PCap::Init(false);
|
haspcap = LAN_PCap::Init(false);
|
||||||
|
|
||||||
ui->rbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
|
ui->rbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
|
||||||
|
|
||||||
ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr);
|
ui->lblAdapterMAC->setText("(none)");
|
||||||
|
ui->lblAdapterIP->setText("(none)");
|
||||||
|
|
||||||
int sel = 0;
|
int sel = 0;
|
||||||
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
|
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
|
||||||
|
@ -88,7 +88,6 @@ void WifiSettingsDialog::done(int r)
|
||||||
|
|
||||||
if (r == QDialog::Accepted)
|
if (r == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked();
|
|
||||||
Config::DirectLAN = ui->rbDirectMode->isChecked();
|
Config::DirectLAN = ui->rbDirectMode->isChecked();
|
||||||
|
|
||||||
int sel = ui->cbxDirectAdapter->currentIndex();
|
int sel = ui->cbxDirectAdapter->currentIndex();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>572</width>
|
<width>572</width>
|
||||||
<height>273</height>
|
<height>217</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -26,92 +26,10 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Local</string>
|
<string>Network mode</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="cbBindAnyAddr">
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string><html><head/><body><p>Enabling this allows (theoretically) playing local multiplayer games over a local network. It may or may not help make for a better connection in general.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Bind socket to any address</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
|
||||||
<property name="title">
|
|
||||||
<string>Online</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="3" column="0" rowspan="3" colspan="2">
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Direct mode settings</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Network adapter:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QComboBox" name="cbxDirectAdapter">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>300</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string><html><head/><body><p>Selects the network adapter through which to route network traffic under direct mode.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>MAC address:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLabel" name="lblAdapterMAC">
|
|
||||||
<property name="text">
|
|
||||||
<string>[PLACEHOLDER]</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>IP address:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLabel" name="lblAdapterIP">
|
|
||||||
<property name="text">
|
|
||||||
<string>[PLACEHOLDER]</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QRadioButton" name="rbIndirectMode">
|
<widget class="QRadioButton" name="rbIndirectMode">
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>Indirect mode uses libslirp. It requires no extra setup and is easy to use.</p></body></html></string>
|
<string><html><head/><body><p>Indirect mode uses libslirp. It requires no extra setup and is easy to use.</p></body></html></string>
|
||||||
|
@ -121,7 +39,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QRadioButton" name="rbDirectMode">
|
<widget class="QRadioButton" name="rbDirectMode">
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>Direct mode directly routes network traffic to the host network. It is the most reliable, but requires an ethernet connection.</p><p><br/></p><p>Non-direct mode uses a layer of emulation to get around this, but is more prone to problems.</p></body></html></string>
|
<string><html><head/><body><p>Direct mode directly routes network traffic to the host network. It is the most reliable, but requires an ethernet connection.</p><p><br/></p><p>Non-direct mode uses a layer of emulation to get around this, but is more prone to problems.</p></body></html></string>
|
||||||
|
@ -134,6 +52,69 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Direct mode settings</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Network adapter:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="cbxDirectAdapter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>300</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string><html><head/><body><p>Selects the network adapter through which to route network traffic under direct mode.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>MAC address:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="lblAdapterMAC">
|
||||||
|
<property name="text">
|
||||||
|
<string>[PLACEHOLDER]</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>IP address:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="lblAdapterIP">
|
||||||
|
<property name="text">
|
||||||
|
<string>[PLACEHOLDER]</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
#include "AudioSettingsDialog.h"
|
#include "AudioSettingsDialog.h"
|
||||||
#include "FirmwareSettingsDialog.h"
|
#include "FirmwareSettingsDialog.h"
|
||||||
#include "PathSettingsDialog.h"
|
#include "PathSettingsDialog.h"
|
||||||
|
#include "MPSettingsDialog.h"
|
||||||
#include "WifiSettingsDialog.h"
|
#include "WifiSettingsDialog.h"
|
||||||
#include "InterfaceSettingsDialog.h"
|
#include "InterfaceSettingsDialog.h"
|
||||||
#include "ROMInfoDialog.h"
|
#include "ROMInfoDialog.h"
|
||||||
|
@ -78,6 +80,7 @@
|
||||||
#include "SPU.h"
|
#include "SPU.h"
|
||||||
#include "Wifi.h"
|
#include "Wifi.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
#include "LocalMP.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
|
@ -103,6 +106,7 @@ bool videoSettingsDirty;
|
||||||
|
|
||||||
SDL_AudioDeviceID audioDevice;
|
SDL_AudioDeviceID audioDevice;
|
||||||
int audioFreq;
|
int audioFreq;
|
||||||
|
bool audioMuted;
|
||||||
SDL_cond* audioSync;
|
SDL_cond* audioSync;
|
||||||
SDL_mutex* audioSyncLock;
|
SDL_mutex* audioSyncLock;
|
||||||
|
|
||||||
|
@ -115,6 +119,15 @@ s16* micWavBuffer;
|
||||||
|
|
||||||
CameraManager* camManager[2];
|
CameraManager* camManager[2];
|
||||||
|
|
||||||
|
const struct { int id; float ratio; const char* label; } aspectRatios[] =
|
||||||
|
{
|
||||||
|
{ 0, 1, "4:3 (native)" },
|
||||||
|
{ 4, (5.f / 3) / (4.f / 3), "5:3 (3DS)"},
|
||||||
|
{ 1, (16.f / 9) / (4.f / 3), "16:9" },
|
||||||
|
{ 2, (21.f / 9) / (4.f / 3), "21:9" },
|
||||||
|
{ 3, 0, "window" }
|
||||||
|
};
|
||||||
|
|
||||||
void micCallback(void* data, Uint8* stream, int len);
|
void micCallback(void* data, Uint8* stream, int len);
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +147,7 @@ void audioCallback(void* data, Uint8* stream, int len)
|
||||||
SDL_CondSignal(audioSync);
|
SDL_CondSignal(audioSync);
|
||||||
SDL_UnlockMutex(audioSyncLock);
|
SDL_UnlockMutex(audioSyncLock);
|
||||||
|
|
||||||
if (num_in < 1)
|
if ((num_in < 1) || audioMuted)
|
||||||
{
|
{
|
||||||
memset(stream, 0, len*sizeof(s16)*2);
|
memset(stream, 0, len*sizeof(s16)*2);
|
||||||
return;
|
return;
|
||||||
|
@ -154,6 +167,23 @@ void audioCallback(void* data, Uint8* stream, int len)
|
||||||
Frontend::AudioOut_Resample(buf_in, num_in, (s16*)stream, len, Config::AudioVolume);
|
Frontend::AudioOut_Resample(buf_in, num_in, (s16*)stream, len, Config::AudioVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void audioMute()
|
||||||
|
{
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
audioMuted = false;
|
||||||
|
|
||||||
|
switch (Config::MPAudioMode)
|
||||||
|
{
|
||||||
|
case 1: // only instance 1
|
||||||
|
if (inst > 0) audioMuted = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // only currently focused instance
|
||||||
|
if (!mainWindow->isActiveWindow()) audioMuted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void micOpen()
|
void micOpen()
|
||||||
{
|
{
|
||||||
|
@ -326,7 +356,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
EmuPause = 0;
|
EmuPause = 0;
|
||||||
RunningSomething = false;
|
RunningSomething = false;
|
||||||
|
|
||||||
connect(this, SIGNAL(windowUpdate()), mainWindow->panel, SLOT(repaint()));
|
connect(this, SIGNAL(windowUpdate()), mainWindow->panelWidget, SLOT(repaint()));
|
||||||
connect(this, SIGNAL(windowTitleChange(QString)), mainWindow, SLOT(onTitleUpdate(QString)));
|
connect(this, SIGNAL(windowTitleChange(QString)), mainWindow, SLOT(onTitleUpdate(QString)));
|
||||||
connect(this, SIGNAL(windowEmuStart()), mainWindow, SLOT(onEmuStart()));
|
connect(this, SIGNAL(windowEmuStart()), mainWindow, SLOT(onEmuStart()));
|
||||||
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
||||||
|
@ -334,7 +364,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(windowEmuFrameStep()), mainWindow->actFrameStep, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuFrameStep()), mainWindow->actFrameStep, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(windowLimitFPSChange()), mainWindow->actLimitFramerate, SLOT(trigger()));
|
connect(this, SIGNAL(windowLimitFPSChange()), mainWindow->actLimitFramerate, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged()));
|
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panelWidget, SLOT(onScreenLayoutChanged()));
|
||||||
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
|
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
|
||||||
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
|
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
|
||||||
|
|
||||||
|
@ -683,7 +713,11 @@ printf("PROULON\n");
|
||||||
if (winUpdateFreq < 1)
|
if (winUpdateFreq < 1)
|
||||||
winUpdateFreq = 1;
|
winUpdateFreq = 1;
|
||||||
|
|
||||||
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget);
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst == 0)
|
||||||
|
sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget);
|
||||||
|
else
|
||||||
|
sprintf(melontitle, "[%d/%.0f] melonDS (%d)", fps, fpstarget, inst+1);
|
||||||
changeWindowTitle(melontitle);
|
changeWindowTitle(melontitle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,7 +732,11 @@ printf("PROULON\n");
|
||||||
|
|
||||||
EmuStatus = EmuRunning;
|
EmuStatus = EmuRunning;
|
||||||
|
|
||||||
sprintf(melontitle, "melonDS " MELONDS_VERSION);
|
int inst = Platform::InstanceID();
|
||||||
|
if (inst == 0)
|
||||||
|
sprintf(melontitle, "melonDS " MELONDS_VERSION);
|
||||||
|
else
|
||||||
|
sprintf(melontitle, "melonDS (%d)", inst+1);
|
||||||
changeWindowTitle(melontitle);
|
changeWindowTitle(melontitle);
|
||||||
|
|
||||||
SDL_Delay(75);
|
SDL_Delay(75);
|
||||||
|
@ -789,19 +827,39 @@ bool EmuThread::emuIsActive()
|
||||||
return (RunningSomething == 1);
|
return (RunningSomething == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScreenHandler::ScreenHandler(QWidget* widget)
|
||||||
|
{
|
||||||
|
widget->setMouseTracking(true);
|
||||||
|
widget->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
|
QTimer* mouseTimer = setupMouseTimer();
|
||||||
|
widget->connect(mouseTimer, &QTimer::timeout, [=] { if (Config::MouseHide) widget->setCursor(Qt::BlankCursor);});
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenHandler::~ScreenHandler()
|
||||||
|
{
|
||||||
|
mouseTimer->stop();
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenSetupLayout(int w, int h)
|
void ScreenHandler::screenSetupLayout(int w, int h)
|
||||||
{
|
{
|
||||||
int sizing = Config::ScreenSizing;
|
int sizing = Config::ScreenSizing;
|
||||||
if (sizing == 3) sizing = autoScreenSizing;
|
if (sizing == 3) sizing = autoScreenSizing;
|
||||||
|
|
||||||
float aspectRatios[] =
|
float aspectTop, aspectBot;
|
||||||
|
|
||||||
|
for (auto ratio : aspectRatios)
|
||||||
{
|
{
|
||||||
1.f,
|
if (ratio.id == Config::ScreenAspectTop)
|
||||||
(16.f/9)/(4.f/3),
|
aspectTop = ratio.ratio;
|
||||||
(21.f/9)/(4.f/3),
|
if (ratio.id == Config::ScreenAspectBot)
|
||||||
((float)w/h)/(4.f/3)
|
aspectBot = ratio.ratio;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (aspectTop == 0)
|
||||||
|
aspectTop = (float) w / h;
|
||||||
|
|
||||||
|
if (aspectBot == 0)
|
||||||
|
aspectBot = (float) w / h;
|
||||||
|
|
||||||
Frontend::SetupScreenLayout(w, h,
|
Frontend::SetupScreenLayout(w, h,
|
||||||
Config::ScreenLayout,
|
Config::ScreenLayout,
|
||||||
|
@ -810,8 +868,8 @@ void ScreenHandler::screenSetupLayout(int w, int h)
|
||||||
Config::ScreenGap,
|
Config::ScreenGap,
|
||||||
Config::IntegerScaling != 0,
|
Config::IntegerScaling != 0,
|
||||||
Config::ScreenSwap != 0,
|
Config::ScreenSwap != 0,
|
||||||
aspectRatios[Config::ScreenAspectTop],
|
aspectTop,
|
||||||
aspectRatios[Config::ScreenAspectBot]);
|
aspectBot);
|
||||||
|
|
||||||
numScreens = Frontend::GetScreenTransforms(screenMatrix[0], screenKind);
|
numScreens = Frontend::GetScreenTransforms(screenMatrix[0], screenKind);
|
||||||
}
|
}
|
||||||
|
@ -819,11 +877,16 @@ void ScreenHandler::screenSetupLayout(int w, int h)
|
||||||
QSize ScreenHandler::screenGetMinSize(int factor = 1)
|
QSize ScreenHandler::screenGetMinSize(int factor = 1)
|
||||||
{
|
{
|
||||||
bool isHori = (Config::ScreenRotation == 1 || Config::ScreenRotation == 3);
|
bool isHori = (Config::ScreenRotation == 1 || Config::ScreenRotation == 3);
|
||||||
int gap = Config::ScreenGap;
|
int gap = Config::ScreenGap * factor;
|
||||||
|
|
||||||
int w = 256 * factor;
|
int w = 256 * factor;
|
||||||
int h = 192 * factor;
|
int h = 192 * factor;
|
||||||
|
|
||||||
|
if (Config::ScreenSizing == 4 || Config::ScreenSizing == 5)
|
||||||
|
{
|
||||||
|
return QSize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
if (Config::ScreenLayout == 0) // natural
|
if (Config::ScreenLayout == 0) // natural
|
||||||
{
|
{
|
||||||
if (isHori)
|
if (isHori)
|
||||||
|
@ -959,7 +1022,7 @@ void ScreenHandler::screenHandleTouch(QTouchEvent* event)
|
||||||
|
|
||||||
void ScreenHandler::showCursor()
|
void ScreenHandler::showCursor()
|
||||||
{
|
{
|
||||||
mainWindow->panel->setCursor(Qt::ArrowCursor);
|
mainWindow->panelWidget->setCursor(Qt::ArrowCursor);
|
||||||
mouseTimer->start();
|
mouseTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,7 +1036,7 @@ QTimer* ScreenHandler::setupMouseTimer()
|
||||||
return mouseTimer;
|
return mouseTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent)
|
ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent), ScreenHandler(this)
|
||||||
{
|
{
|
||||||
screen[0] = QImage(256, 192, QImage::Format_RGB32);
|
screen[0] = QImage(256, 192, QImage::Format_RGB32);
|
||||||
screen[1] = QImage(256, 192, QImage::Format_RGB32);
|
screen[1] = QImage(256, 192, QImage::Format_RGB32);
|
||||||
|
@ -981,17 +1044,12 @@ ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent)
|
||||||
screenTrans[0].reset();
|
screenTrans[0].reset();
|
||||||
screenTrans[1].reset();
|
screenTrans[1].reset();
|
||||||
|
|
||||||
touching = false;
|
|
||||||
|
|
||||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
|
||||||
|
|
||||||
OSD::Init(nullptr);
|
OSD::Init(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenPanelNative::~ScreenPanelNative()
|
ScreenPanelNative::~ScreenPanelNative()
|
||||||
{
|
{
|
||||||
OSD::DeInit(nullptr);
|
OSD::DeInit(nullptr);
|
||||||
mouseTimer->stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenPanelNative::setupScreenLayout()
|
void ScreenPanelNative::setupScreenLayout()
|
||||||
|
@ -1090,17 +1148,11 @@ void ScreenPanelNative::onScreenLayoutChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QOpenGLWidget(parent)
|
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QOpenGLWidget(parent), ScreenHandler(this)
|
||||||
{
|
{}
|
||||||
touching = false;
|
|
||||||
|
|
||||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenPanelGL::~ScreenPanelGL()
|
ScreenPanelGL::~ScreenPanelGL()
|
||||||
{
|
{
|
||||||
mouseTimer->stop();
|
|
||||||
|
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
|
|
||||||
OSD::DeInit(this);
|
OSD::DeInit(this);
|
||||||
|
@ -1356,6 +1408,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
setWindowTitle("melonDS " MELONDS_VERSION);
|
setWindowTitle("melonDS " MELONDS_VERSION);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
|
||||||
|
int inst = Platform::InstanceID();
|
||||||
|
|
||||||
QMenuBar* menubar = new QMenuBar();
|
QMenuBar* menubar = new QMenuBar();
|
||||||
{
|
{
|
||||||
|
@ -1488,19 +1543,30 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
actEnableCheats->setCheckable(true);
|
actEnableCheats->setCheckable(true);
|
||||||
connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats);
|
connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats);
|
||||||
|
|
||||||
actSetupCheats = menu->addAction("Setup cheat codes");
|
//if (inst == 0)
|
||||||
actSetupCheats->setMenuRole(QAction::NoRole);
|
{
|
||||||
connect(actSetupCheats, &QAction::triggered, this, &MainWindow::onSetupCheats);
|
actSetupCheats = menu->addAction("Setup cheat codes");
|
||||||
|
actSetupCheats->setMenuRole(QAction::NoRole);
|
||||||
|
connect(actSetupCheats, &QAction::triggered, this, &MainWindow::onSetupCheats);
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
actROMInfo = menu->addAction("ROM info");
|
actROMInfo = menu->addAction("ROM info");
|
||||||
connect(actROMInfo, &QAction::triggered, this, &MainWindow::onROMInfo);
|
connect(actROMInfo, &QAction::triggered, this, &MainWindow::onROMInfo);
|
||||||
|
|
||||||
actRAMInfo = menu->addAction("RAM search");
|
actRAMInfo = menu->addAction("RAM search");
|
||||||
connect(actRAMInfo, &QAction::triggered, this, &MainWindow::onRAMInfo);
|
connect(actRAMInfo, &QAction::triggered, this, &MainWindow::onRAMInfo);
|
||||||
|
|
||||||
actTitleManager = menu->addAction("Manage DSi titles");
|
actTitleManager = menu->addAction("Manage DSi titles");
|
||||||
connect(actTitleManager, &QAction::triggered, this, &MainWindow::onOpenTitleManager);
|
connect(actTitleManager, &QAction::triggered, this, &MainWindow::onOpenTitleManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
menu->addSeparator();
|
||||||
|
QMenu* submenu = menu->addMenu("Multiplayer");
|
||||||
|
|
||||||
|
actMPNewInstance = submenu->addAction("Launch new instance");
|
||||||
|
connect(actMPNewInstance, &QAction::triggered, this, &MainWindow::onMPNewInstance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QMenu* menu = menubar->addMenu("Config");
|
QMenu* menu = menubar->addMenu("Config");
|
||||||
|
@ -1509,7 +1575,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings);
|
connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
QAction* actPreferences = menu->addAction("Preferences...");
|
actPreferences = menu->addAction("Preferences...");
|
||||||
connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings);
|
connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings);
|
||||||
actPreferences->setMenuRole(QAction::PreferencesRole);
|
actPreferences->setMenuRole(QAction::PreferencesRole);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1526,15 +1592,18 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
actAudioSettings = menu->addAction("Audio settings");
|
actAudioSettings = menu->addAction("Audio settings");
|
||||||
connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings);
|
connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings);
|
||||||
|
|
||||||
|
actMPSettings = menu->addAction("Multiplayer settings");
|
||||||
|
connect(actMPSettings, &QAction::triggered, this, &MainWindow::onOpenMPSettings);
|
||||||
|
|
||||||
actWifiSettings = menu->addAction("Wifi settings");
|
actWifiSettings = menu->addAction("Wifi settings");
|
||||||
connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings);
|
connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings);
|
||||||
|
|
||||||
actInterfaceSettings = menu->addAction("Interface settings");
|
|
||||||
connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings);
|
|
||||||
|
|
||||||
actFirmwareSettings = menu->addAction("Firmware settings");
|
actFirmwareSettings = menu->addAction("Firmware settings");
|
||||||
connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings);
|
connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings);
|
||||||
|
|
||||||
|
actInterfaceSettings = menu->addAction("Interface settings");
|
||||||
|
connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings);
|
||||||
|
|
||||||
actPathSettings = menu->addAction("Path settings");
|
actPathSettings = menu->addAction("Path settings");
|
||||||
connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings);
|
connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings);
|
||||||
|
|
||||||
|
@ -1638,34 +1707,34 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
{
|
{
|
||||||
QMenu* submenu = menu->addMenu("Aspect ratio");
|
QMenu* submenu = menu->addMenu("Aspect ratio");
|
||||||
grpScreenAspectTop = new QActionGroup(submenu);
|
grpScreenAspectTop = new QActionGroup(submenu);
|
||||||
|
|
||||||
const char* aspectRatiosTop[] = {"Top 4:3 (native)", "Top 16:9", "Top 21:9", "Top window"};
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
actScreenAspectTop[i] = submenu->addAction(QString(aspectRatiosTop[i]));
|
|
||||||
actScreenAspectTop[i]->setActionGroup(grpScreenAspectTop);
|
|
||||||
actScreenAspectTop[i]->setData(QVariant(i));
|
|
||||||
actScreenAspectTop[i]->setCheckable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(grpScreenAspectTop, &QActionGroup::triggered, this, &MainWindow::onChangeScreenAspectTop);
|
|
||||||
|
|
||||||
submenu->addSeparator();
|
|
||||||
|
|
||||||
grpScreenAspectBot = new QActionGroup(submenu);
|
grpScreenAspectBot = new QActionGroup(submenu);
|
||||||
|
actScreenAspectTop = new QAction*[sizeof(aspectRatios) / sizeof(aspectRatios[0])];
|
||||||
|
actScreenAspectBot = new QAction*[sizeof(aspectRatios) / sizeof(aspectRatios[0])];
|
||||||
|
|
||||||
const char* aspectRatiosBot[] = {"Bottom 4:3 (native)", "Bottom 16:9", "Bottom 21:9", "Bottom window"};
|
for (int i = 0; i < 2; i++)
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
{
|
||||||
actScreenAspectBot[i] = submenu->addAction(QString(aspectRatiosBot[i]));
|
QActionGroup* group = grpScreenAspectTop;
|
||||||
actScreenAspectBot[i]->setActionGroup(grpScreenAspectBot);
|
QAction** actions = actScreenAspectTop;
|
||||||
actScreenAspectBot[i]->setData(QVariant(i));
|
|
||||||
actScreenAspectBot[i]->setCheckable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(grpScreenAspectBot, &QActionGroup::triggered, this, &MainWindow::onChangeScreenAspectBot);
|
if (i == 1)
|
||||||
|
{
|
||||||
|
group = grpScreenAspectBot;
|
||||||
|
submenu->addSeparator();
|
||||||
|
actions = actScreenAspectBot;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < sizeof(aspectRatios) / sizeof(aspectRatios[0]); j++)
|
||||||
|
{
|
||||||
|
auto ratio = aspectRatios[j];
|
||||||
|
QString label = QString("%1 %2").arg(i ? "Bottom" : "Top", ratio.label);
|
||||||
|
actions[j] = submenu->addAction(label);
|
||||||
|
actions[j]->setActionGroup(group);
|
||||||
|
actions[j]->setData(QVariant(ratio.id));
|
||||||
|
actions[j]->setCheckable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(group, &QActionGroup::triggered, this, &MainWindow::onChangeScreenAspect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actScreenFiltering = menu->addAction("Screen filtering");
|
actScreenFiltering = menu->addAction("Screen filtering");
|
||||||
|
@ -1690,6 +1759,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
|
|
||||||
resize(Config::WindowWidth, Config::WindowHeight);
|
resize(Config::WindowWidth, Config::WindowHeight);
|
||||||
|
|
||||||
|
if (Config::FirmwareUsername == "Arisotura")
|
||||||
|
actMPNewInstance->setText("Fart");
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QPoint screenCenter = screen()->availableGeometry().center();
|
QPoint screenCenter = screen()->availableGeometry().center();
|
||||||
QRect frameGeo = frameGeometry();
|
QRect frameGeo = frameGeometry();
|
||||||
|
@ -1756,8 +1828,13 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
|
|
||||||
actScreenSwap->setChecked(Config::ScreenSwap);
|
actScreenSwap->setChecked(Config::ScreenSwap);
|
||||||
|
|
||||||
actScreenAspectTop[Config::ScreenAspectTop]->setChecked(true);
|
for (int i = 0; i < sizeof(aspectRatios) / sizeof(aspectRatios[0]); i++)
|
||||||
actScreenAspectBot[Config::ScreenAspectBot]->setChecked(true);
|
{
|
||||||
|
if (Config::ScreenAspectTop == aspectRatios[i].id)
|
||||||
|
actScreenAspectTop[i]->setChecked(true);
|
||||||
|
if (Config::ScreenAspectBot == aspectRatios[i].id)
|
||||||
|
actScreenAspectBot[i]->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
actScreenFiltering->setChecked(Config::ScreenFilter);
|
actScreenFiltering->setChecked(Config::ScreenFilter);
|
||||||
actShowOSD->setChecked(Config::ShowOSD);
|
actShowOSD->setChecked(Config::ShowOSD);
|
||||||
|
@ -1765,11 +1842,18 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
|
||||||
actLimitFramerate->setChecked(Config::LimitFPS);
|
actLimitFramerate->setChecked(Config::LimitFPS);
|
||||||
actAudioSync->setChecked(Config::AudioSync);
|
actAudioSync->setChecked(Config::AudioSync);
|
||||||
|
|
||||||
|
if (inst > 0)
|
||||||
|
{
|
||||||
|
actEmuSettings->setEnabled(false);
|
||||||
|
actVideoSettings->setEnabled(false);
|
||||||
|
actMPSettings->setEnabled(false);
|
||||||
|
actWifiSettings->setEnabled(false);
|
||||||
|
actInterfaceSettings->setEnabled(false);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
|
actPreferences->setEnabled(false);
|
||||||
for (const QCameraInfo &cameraInfo : cameras)
|
#endif // __APPLE__
|
||||||
printf("CAMERAFAZIL: %s\n", cameraInfo.deviceName().toStdString().c_str());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -1780,17 +1864,13 @@ void MainWindow::createScreenPanel()
|
||||||
{
|
{
|
||||||
hasOGL = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
hasOGL = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||||
|
|
||||||
QTimer* mouseTimer;
|
|
||||||
|
|
||||||
if (hasOGL)
|
if (hasOGL)
|
||||||
{
|
{
|
||||||
panelGL = new ScreenPanelGL(this);
|
ScreenPanelGL* panelGL = new ScreenPanelGL(this);
|
||||||
panelGL->show();
|
panelGL->show();
|
||||||
|
|
||||||
panel = panelGL;
|
panel = panelGL;
|
||||||
panelGL->setMouseTracking(true);
|
panelWidget = panelGL;
|
||||||
mouseTimer = panelGL->setupMouseTimer();
|
|
||||||
connect(mouseTimer, &QTimer::timeout, [=] { if (Config::MouseHide) panelGL->setCursor(Qt::BlankCursor);});
|
|
||||||
|
|
||||||
if (!panelGL->isValid())
|
if (!panelGL->isValid())
|
||||||
hasOGL = false;
|
hasOGL = false;
|
||||||
|
@ -1807,17 +1887,14 @@ void MainWindow::createScreenPanel()
|
||||||
|
|
||||||
if (!hasOGL)
|
if (!hasOGL)
|
||||||
{
|
{
|
||||||
panelNative = new ScreenPanelNative(this);
|
ScreenPanelNative* panelNative = new ScreenPanelNative(this);
|
||||||
panel = panelNative;
|
panel = panelNative;
|
||||||
panel->show();
|
panelWidget = panelNative;
|
||||||
|
panelWidget->show();
|
||||||
panelNative->setMouseTracking(true);
|
|
||||||
mouseTimer = panelNative->setupMouseTimer();
|
|
||||||
connect(mouseTimer, &QTimer::timeout, [=] { if (Config::MouseHide) panelNative->setCursor(Qt::BlankCursor);});
|
|
||||||
}
|
}
|
||||||
setCentralWidget(panel);
|
setCentralWidget(panelWidget);
|
||||||
|
|
||||||
connect(this, SIGNAL(screenLayoutChange()), panel, SLOT(onScreenLayoutChanged()));
|
connect(this, SIGNAL(screenLayoutChange()), panelWidget, SLOT(onScreenLayoutChanged()));
|
||||||
emit screenLayoutChange();
|
emit screenLayoutChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1825,7 +1902,7 @@ QOpenGLContext* MainWindow::getOGLContext()
|
||||||
{
|
{
|
||||||
if (!hasOGL) return nullptr;
|
if (!hasOGL) return nullptr;
|
||||||
|
|
||||||
QOpenGLWidget* glpanel = (QOpenGLWidget*)panel;
|
QOpenGLWidget* glpanel = dynamic_cast<QOpenGLWidget*>(panel);
|
||||||
return glpanel->context();
|
return glpanel->context();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1967,6 +2044,16 @@ void MainWindow::dropEvent(QDropEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::focusInEvent(QFocusEvent* event)
|
||||||
|
{
|
||||||
|
audioMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::focusOutEvent(QFocusEvent* event)
|
||||||
|
{
|
||||||
|
audioMute();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onAppStateChanged(Qt::ApplicationState state)
|
void MainWindow::onAppStateChanged(Qt::ApplicationState state)
|
||||||
{
|
{
|
||||||
if (state == Qt::ApplicationInactive)
|
if (state == Qt::ApplicationInactive)
|
||||||
|
@ -2639,6 +2726,23 @@ void MainWindow::onOpenTitleManager()
|
||||||
TitleManagerDialog* dlg = TitleManagerDialog::openDlg(this);
|
TitleManagerDialog* dlg = TitleManagerDialog::openDlg(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onMPNewInstance()
|
||||||
|
{
|
||||||
|
//QProcess::startDetached(QApplication::applicationFilePath());
|
||||||
|
QProcess newinst;
|
||||||
|
newinst.setProgram(QApplication::applicationFilePath());
|
||||||
|
newinst.setArguments(QApplication::arguments().mid(1, QApplication::arguments().length()-1));
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
newinst.setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args)
|
||||||
|
{
|
||||||
|
args->flags |= CREATE_NEW_CONSOLE;
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
newinst.startDetached();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onOpenEmuSettings()
|
void MainWindow::onOpenEmuSettings()
|
||||||
{
|
{
|
||||||
emuThread->emuPause();
|
emuThread->emuPause();
|
||||||
|
@ -2779,6 +2883,22 @@ void MainWindow::onAudioSettingsFinished(int res)
|
||||||
micOpen();
|
micOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onOpenMPSettings()
|
||||||
|
{
|
||||||
|
emuThread->emuPause();
|
||||||
|
|
||||||
|
MPSettingsDialog* dlg = MPSettingsDialog::openDlg(this);
|
||||||
|
connect(dlg, &MPSettingsDialog::finished, this, &MainWindow::onMPSettingsFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onMPSettingsFinished(int res)
|
||||||
|
{
|
||||||
|
audioMute();
|
||||||
|
LocalMP::SetRecvTimeout(Config::MPRecvTimeout);
|
||||||
|
|
||||||
|
emuThread->emuUnpause();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onOpenWifiSettings()
|
void MainWindow::onOpenWifiSettings()
|
||||||
{
|
{
|
||||||
emuThread->emuPause();
|
emuThread->emuPause();
|
||||||
|
@ -2789,12 +2909,6 @@ void MainWindow::onOpenWifiSettings()
|
||||||
|
|
||||||
void MainWindow::onWifiSettingsFinished(int res)
|
void MainWindow::onWifiSettingsFinished(int res)
|
||||||
{
|
{
|
||||||
if (Wifi::MPInited)
|
|
||||||
{
|
|
||||||
Platform::MP_DeInit();
|
|
||||||
Platform::MP_Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform::LAN_DeInit();
|
Platform::LAN_DeInit();
|
||||||
Platform::LAN_Init();
|
Platform::LAN_Init();
|
||||||
|
|
||||||
|
@ -2814,10 +2928,7 @@ void MainWindow::onOpenInterfaceSettings()
|
||||||
|
|
||||||
void MainWindow::onUpdateMouseTimer()
|
void MainWindow::onUpdateMouseTimer()
|
||||||
{
|
{
|
||||||
if (hasOGL)
|
panel->mouseTimer->setInterval(Config::MouseHideSeconds*1000);
|
||||||
panelGL->mouseTimer->setInterval(Config::MouseHideSeconds*1000);
|
|
||||||
else
|
|
||||||
panelNative->mouseTimer->setInterval(Config::MouseHideSeconds*1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onInterfaceSettingsFinished(int res)
|
void MainWindow::onInterfaceSettingsFinished(int res)
|
||||||
|
@ -2833,8 +2944,8 @@ void MainWindow::onChangeSavestateSRAMReloc(bool checked)
|
||||||
void MainWindow::onChangeScreenSize()
|
void MainWindow::onChangeScreenSize()
|
||||||
{
|
{
|
||||||
int factor = ((QAction*)sender())->data().toInt();
|
int factor = ((QAction*)sender())->data().toInt();
|
||||||
QSize diff = size() - panel->size();
|
QSize diff = size() - panelWidget->size();
|
||||||
resize(dynamic_cast<ScreenHandler*>(panel)->screenGetMinSize(factor) + diff);
|
resize(panel->screenGetMinSize(factor) + diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenRotation(QAction* act)
|
void MainWindow::onChangeScreenRotation(QAction* act)
|
||||||
|
@ -2892,18 +3003,19 @@ void MainWindow::onChangeScreenSizing(QAction* act)
|
||||||
emit screenLayoutChange();
|
emit screenLayoutChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeScreenAspectTop(QAction* act)
|
void MainWindow::onChangeScreenAspect(QAction* act)
|
||||||
{
|
{
|
||||||
int aspect = act->data().toInt();
|
int aspect = act->data().toInt();
|
||||||
Config::ScreenAspectTop = aspect;
|
QActionGroup* group = act->actionGroup();
|
||||||
|
|
||||||
emit screenLayoutChange();
|
if (group == grpScreenAspectTop)
|
||||||
}
|
{
|
||||||
|
Config::ScreenAspectTop = aspect;
|
||||||
void MainWindow::onChangeScreenAspectBot(QAction* act)
|
}
|
||||||
{
|
else
|
||||||
int aspect = act->data().toInt();
|
{
|
||||||
Config::ScreenAspectBot = aspect;
|
Config::ScreenAspectBot = aspect;
|
||||||
|
}
|
||||||
|
|
||||||
emit screenLayoutChange();
|
emit screenLayoutChange();
|
||||||
}
|
}
|
||||||
|
@ -3006,16 +3118,10 @@ void MainWindow::onUpdateVideoSettings(bool glchange)
|
||||||
emuThread->emuPause();
|
emuThread->emuPause();
|
||||||
|
|
||||||
if (hasOGL)
|
if (hasOGL)
|
||||||
{
|
|
||||||
emuThread->deinitOpenGL();
|
emuThread->deinitOpenGL();
|
||||||
delete panelGL;
|
delete panel;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete panelNative;
|
|
||||||
}
|
|
||||||
createScreenPanel();
|
createScreenPanel();
|
||||||
connect(emuThread, SIGNAL(windowUpdate()), panel, SLOT(repaint()));
|
connect(emuThread, SIGNAL(windowUpdate()), panelWidget, SLOT(repaint()));
|
||||||
if (hasOGL) emuThread->initOpenGL();
|
if (hasOGL) emuThread->initOpenGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3121,6 +3227,7 @@ int main(int argc, char** argv)
|
||||||
format.setSwapInterval(0);
|
format.setSwapInterval(0);
|
||||||
QSurfaceFormat::setDefaultFormat(format);
|
QSurfaceFormat::setDefaultFormat(format);
|
||||||
|
|
||||||
|
audioMuted = false;
|
||||||
audioSync = SDL_CreateCond();
|
audioSync = SDL_CreateCond();
|
||||||
audioSyncLock = SDL_CreateMutex();
|
audioSyncLock = SDL_CreateMutex();
|
||||||
|
|
||||||
|
@ -3176,6 +3283,8 @@ int main(int argc, char** argv)
|
||||||
emuThread->start();
|
emuThread->start();
|
||||||
emuThread->emuPause();
|
emuThread->emuPause();
|
||||||
|
|
||||||
|
audioMute();
|
||||||
|
|
||||||
QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged);
|
QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged);
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
|
@ -3221,7 +3330,7 @@ int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdsho
|
||||||
{
|
{
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
|
wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
char* nullarg = "";
|
char nullarg[] = {'\0'};
|
||||||
|
|
||||||
char** argv = new char*[argc];
|
char** argv = new char*[argc];
|
||||||
for (int i = 0; i < argc; i++)
|
for (int i = 0; i < argc; i++)
|
||||||
|
@ -3236,7 +3345,8 @@ int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdsho
|
||||||
|
|
||||||
if (argv_w) LocalFree(argv_w);
|
if (argv_w) LocalFree(argv_w);
|
||||||
|
|
||||||
/*if (AttachConsole(ATTACH_PARENT_PROCESS))
|
//if (AttachConsole(ATTACH_PARENT_PROCESS))
|
||||||
|
/*if (AllocConsole())
|
||||||
{
|
{
|
||||||
freopen("CONOUT$", "w", stdout);
|
freopen("CONOUT$", "w", stdout);
|
||||||
freopen("CONOUT$", "w", stderr);
|
freopen("CONOUT$", "w", stderr);
|
||||||
|
|
|
@ -101,7 +101,8 @@ class ScreenHandler
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ScreenHandler() {}
|
ScreenHandler(QWidget* widget);
|
||||||
|
virtual ~ScreenHandler();
|
||||||
QTimer* setupMouseTimer();
|
QTimer* setupMouseTimer();
|
||||||
void updateMouseTimer();
|
void updateMouseTimer();
|
||||||
QTimer* mouseTimer;
|
QTimer* mouseTimer;
|
||||||
|
@ -121,7 +122,7 @@ protected:
|
||||||
int screenKind[Frontend::MaxScreenTransforms];
|
int screenKind[Frontend::MaxScreenTransforms];
|
||||||
int numScreens;
|
int numScreens;
|
||||||
|
|
||||||
bool touching;
|
bool touching = false;
|
||||||
|
|
||||||
void showCursor();
|
void showCursor();
|
||||||
};
|
};
|
||||||
|
@ -133,7 +134,7 @@ class ScreenPanelNative : public QWidget, public ScreenHandler
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScreenPanelNative(QWidget* parent);
|
explicit ScreenPanelNative(QWidget* parent);
|
||||||
~ScreenPanelNative();
|
virtual ~ScreenPanelNative();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
@ -163,7 +164,7 @@ class ScreenPanelGL : public QOpenGLWidget, public ScreenHandler, protected QOpe
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScreenPanelGL(QWidget* parent);
|
explicit ScreenPanelGL(QWidget* parent);
|
||||||
~ScreenPanelGL();
|
virtual ~ScreenPanelGL();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
|
@ -225,6 +226,9 @@ protected:
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
|
|
||||||
|
void focusInEvent(QFocusEvent* event) override;
|
||||||
|
void focusOutEvent(QFocusEvent* event) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void screenLayoutChange();
|
void screenLayoutChange();
|
||||||
|
|
||||||
|
@ -254,6 +258,7 @@ private slots:
|
||||||
void onROMInfo();
|
void onROMInfo();
|
||||||
void onRAMInfo();
|
void onRAMInfo();
|
||||||
void onOpenTitleManager();
|
void onOpenTitleManager();
|
||||||
|
void onMPNewInstance();
|
||||||
|
|
||||||
void onOpenEmuSettings();
|
void onOpenEmuSettings();
|
||||||
void onEmuSettingsDialogFinished(int res);
|
void onEmuSettingsDialogFinished(int res);
|
||||||
|
@ -267,6 +272,8 @@ private slots:
|
||||||
void onOpenPathSettings();
|
void onOpenPathSettings();
|
||||||
void onUpdateAudioSettings();
|
void onUpdateAudioSettings();
|
||||||
void onAudioSettingsFinished(int res);
|
void onAudioSettingsFinished(int res);
|
||||||
|
void onOpenMPSettings();
|
||||||
|
void onMPSettingsFinished(int res);
|
||||||
void onOpenWifiSettings();
|
void onOpenWifiSettings();
|
||||||
void onWifiSettingsFinished(int res);
|
void onWifiSettingsFinished(int res);
|
||||||
void onFirmwareSettingsFinished(int res);
|
void onFirmwareSettingsFinished(int res);
|
||||||
|
@ -281,8 +288,7 @@ private slots:
|
||||||
void onChangeScreenLayout(QAction* act);
|
void onChangeScreenLayout(QAction* act);
|
||||||
void onChangeScreenSwap(bool checked);
|
void onChangeScreenSwap(bool checked);
|
||||||
void onChangeScreenSizing(QAction* act);
|
void onChangeScreenSizing(QAction* act);
|
||||||
void onChangeScreenAspectTop(QAction* act);
|
void onChangeScreenAspect(QAction* act);
|
||||||
void onChangeScreenAspectBot(QAction* act);
|
|
||||||
void onChangeIntegerScaling(bool checked);
|
void onChangeIntegerScaling(bool checked);
|
||||||
void onChangeScreenFiltering(bool checked);
|
void onChangeScreenFiltering(bool checked);
|
||||||
void onChangeShowOSD(bool checked);
|
void onChangeShowOSD(bool checked);
|
||||||
|
@ -318,9 +324,8 @@ private:
|
||||||
bool oldMax;
|
bool oldMax;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QWidget* panel;
|
ScreenHandler* panel;
|
||||||
ScreenPanelGL* panelGL;
|
QWidget* panelWidget;
|
||||||
ScreenPanelNative* panelNative;
|
|
||||||
|
|
||||||
QAction* actOpenROM;
|
QAction* actOpenROM;
|
||||||
QAction* actBootFirmware;
|
QAction* actBootFirmware;
|
||||||
|
@ -346,13 +351,18 @@ public:
|
||||||
QAction* actROMInfo;
|
QAction* actROMInfo;
|
||||||
QAction* actRAMInfo;
|
QAction* actRAMInfo;
|
||||||
QAction* actTitleManager;
|
QAction* actTitleManager;
|
||||||
|
QAction* actMPNewInstance;
|
||||||
|
|
||||||
QAction* actEmuSettings;
|
QAction* actEmuSettings;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
QAction* actPreferences;
|
||||||
|
#endif
|
||||||
QAction* actPowerManagement;
|
QAction* actPowerManagement;
|
||||||
QAction* actInputConfig;
|
QAction* actInputConfig;
|
||||||
QAction* actVideoSettings;
|
QAction* actVideoSettings;
|
||||||
QAction* actCameraSettings;
|
QAction* actCameraSettings;
|
||||||
QAction* actAudioSettings;
|
QAction* actAudioSettings;
|
||||||
|
QAction* actMPSettings;
|
||||||
QAction* actWifiSettings;
|
QAction* actWifiSettings;
|
||||||
QAction* actFirmwareSettings;
|
QAction* actFirmwareSettings;
|
||||||
QAction* actPathSettings;
|
QAction* actPathSettings;
|
||||||
|
@ -370,9 +380,9 @@ public:
|
||||||
QAction* actScreenSizing[6];
|
QAction* actScreenSizing[6];
|
||||||
QAction* actIntegerScaling;
|
QAction* actIntegerScaling;
|
||||||
QActionGroup* grpScreenAspectTop;
|
QActionGroup* grpScreenAspectTop;
|
||||||
QAction* actScreenAspectTop[4];
|
QAction** actScreenAspectTop;
|
||||||
QActionGroup* grpScreenAspectBot;
|
QActionGroup* grpScreenAspectBot;
|
||||||
QAction* actScreenAspectBot[4];
|
QAction** actScreenAspectBot;
|
||||||
QAction* actScreenFiltering;
|
QAction* actScreenFiltering;
|
||||||
QAction* actShowOSD;
|
QAction* actShowOSD;
|
||||||
QAction* actLimitFramerate;
|
QAction* actLimitFramerate;
|
||||||
|
|
|
@ -0,0 +1,488 @@
|
||||||
|
/*
|
||||||
|
* s e m _ t i m e d w a i t
|
||||||
|
*
|
||||||
|
* Function:
|
||||||
|
* Implements a version of sem_timedwait().
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Not all systems implement sem_timedwait(), which is a version of
|
||||||
|
* sem_wait() with a timeout. Mac OS X is one example, at least up to
|
||||||
|
* and including version 10.6 (Leopard). If such a function is needed,
|
||||||
|
* this code provides a reasonable implementation, which I think is
|
||||||
|
* compatible with the standard version, although possibly less
|
||||||
|
* efficient. It works by creating a thread that interrupts a normal
|
||||||
|
* sem_wait() call after the specified timeout.
|
||||||
|
*
|
||||||
|
* Call:
|
||||||
|
*
|
||||||
|
* The Linux man pages say:
|
||||||
|
*
|
||||||
|
* #include <semaphore.h>
|
||||||
|
*
|
||||||
|
* int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
|
||||||
|
*
|
||||||
|
* sem_timedwait() is the same as sem_wait(), except that abs_timeout
|
||||||
|
* specifies a limit on the amount of time that the call should block if
|
||||||
|
* the decrement cannot be immediately performed. The abs_timeout argument
|
||||||
|
* points to a structure that specifies an absolute timeout in seconds and
|
||||||
|
* nanoseconds since the Epoch (00:00:00, 1 January 1970). This structure
|
||||||
|
* is defined as follows:
|
||||||
|
*
|
||||||
|
* struct timespec {
|
||||||
|
* time_t tv_sec; Seconds
|
||||||
|
* long tv_nsec; Nanoseconds [0 .. 999999999]
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* If the timeout has already expired by the time of the call, and the
|
||||||
|
* semaphore could not be locked immediately, then sem_timedwait() fails
|
||||||
|
* with a timeout error (errno set to ETIMEDOUT).
|
||||||
|
* If the operation can be performed immediately, then sem_timedwait()
|
||||||
|
* never fails with a timeout error, regardless of the value of abs_timeout.
|
||||||
|
* Furthermore, the validity of abs_timeout is not checked in this case.
|
||||||
|
*
|
||||||
|
* Limitations:
|
||||||
|
*
|
||||||
|
* The mechanism used involves sending a SIGUSR2 signal to the thread
|
||||||
|
* calling sem_timedwait(). The handler for this signal is set to a null
|
||||||
|
* routine which does nothing, and with any flags for the signal
|
||||||
|
* (eg SA_RESTART) cleared. Note that this effective disabling of the
|
||||||
|
* SIGUSR2 signal is a side-effect of using this routine, and means it
|
||||||
|
* may not be a completely transparent plug-in replacement for a
|
||||||
|
* 'normal' sig_timedwait() call. Since OS X does not declare the
|
||||||
|
* sem_timedwait() call in its standard include files, the relevant
|
||||||
|
* declaration (shown above in the man pages extract) will probably have
|
||||||
|
* to be added to any code that uses this.
|
||||||
|
*
|
||||||
|
* Compiling:
|
||||||
|
* This compiles and runs cleanly on OS X (10.6) with gcc with the
|
||||||
|
* -Wall -ansi -pedantic flags. On Linux, using -ansi causes a sweep of
|
||||||
|
* compiler complaints about the timespec structure, but it compiles
|
||||||
|
* and works fine with just -Wall -pedantic. (Since Linux provides
|
||||||
|
* sem_timedwait() anyway, this really isn't needed on Linux.) However,
|
||||||
|
* since Linux provides sem_timedwait anyway, the sem_timedwait()
|
||||||
|
* code in this file is only compiled on OS X, and is a null on other
|
||||||
|
* systems.
|
||||||
|
*
|
||||||
|
* Testing:
|
||||||
|
* This file contains a test program that exercises the sem_timedwait
|
||||||
|
* code. It is compiled if the pre-processor variable TEST is defined.
|
||||||
|
* For more details, see the comments for the test routine at the end
|
||||||
|
* of the file.
|
||||||
|
*
|
||||||
|
* Author: Keith Shortridge, AAO.
|
||||||
|
*
|
||||||
|
* History:
|
||||||
|
* 8th Sep 2009. Original version. KS.
|
||||||
|
* 24th Sep 2009. Added test that the calling thread still exists before
|
||||||
|
* trying to set the timed-out flag. KS.
|
||||||
|
* 2nd Oct 2009. No longer restores the original SIGUSR2 signal handler.
|
||||||
|
* See comments in the body of the code for more details.
|
||||||
|
* Prototypes for now discontinued internal routines removed.
|
||||||
|
* 12th Aug 2010. Added the cleanup handler, so that this code no longer
|
||||||
|
* leaks resources if the calling thread is cancelled. KS.
|
||||||
|
* 21st Sep 2011. Added copyright notice below. Modified header comments
|
||||||
|
* to describe the use of SIGUSR2 more accurately in the
|
||||||
|
* light of the 2/10/09 change above. Now undefs DEBUG
|
||||||
|
* before defining it, to avoid any possible clash. KS.
|
||||||
|
* 14th Feb 2012. Tidied out a number of TABs that had got into the
|
||||||
|
* code. KS.
|
||||||
|
* 6th May 2013. Copyright notice modified to one based on the MIT licence,
|
||||||
|
* which is more permissive than the previous notice. KS.
|
||||||
|
*
|
||||||
|
* Copyright (c) Australian Astronomical Observatory (AAO), (2013).
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include "sem_timedwait.h"
|
||||||
|
|
||||||
|
/* Some useful definitions - TRUE, FALSE, and DEBUG */
|
||||||
|
|
||||||
|
#undef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#undef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#undef DEBUG
|
||||||
|
#define DEBUG printf
|
||||||
|
|
||||||
|
/* A structure of type timeoutDetails is passed to the thread used to
|
||||||
|
* implement the timeout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct timespec delay; /* Specifies the delay, relative to now */
|
||||||
|
pthread_t callingThread; /* The thread doing the sem_wait call */
|
||||||
|
volatile short *timedOutShort; /* Address of a flag set to indicate that
|
||||||
|
* the timeout was triggered. */
|
||||||
|
} timeoutDetails;
|
||||||
|
|
||||||
|
/* A structure of type cleanupDetails is passed to the thread cleanup
|
||||||
|
* routine which is called at the end of the routine or if the thread calling
|
||||||
|
* it is cancelled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pthread_t *threadIdAddr; /* Address of the variable that holds
|
||||||
|
* the Id of the timeout thread. */
|
||||||
|
struct sigaction *sigHandlerAddr; /* Address of the old signal action
|
||||||
|
* handler. */
|
||||||
|
volatile short *timedOutShort; /* Address of a flag set to indicate that
|
||||||
|
* the timeout was triggered. */
|
||||||
|
} cleanupDetails;
|
||||||
|
|
||||||
|
/* Forward declarations of internal routines */
|
||||||
|
|
||||||
|
static void* timeoutThreadMain (void* passedPtr);
|
||||||
|
static int triggerSignal (int Signal, pthread_t Thread);
|
||||||
|
static void ignoreSignal (int Signal);
|
||||||
|
static void timeoutThreadCleanup (void* passedPtr);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* s e m _ t i m e d w a i t
|
||||||
|
*
|
||||||
|
* This is the main code for the sem_timedwait() implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int sem_timedwait (
|
||||||
|
sem_t *sem,
|
||||||
|
const struct timespec *abs_timeout)
|
||||||
|
{
|
||||||
|
int result = 0; /* Code returned by this routine 0 or -1 */
|
||||||
|
|
||||||
|
/* "Under no circumstances shall the function fail if the semaphore
|
||||||
|
* can be locked immediately". So we try to get it quickly to see if we
|
||||||
|
* can avoid all the timeout overheads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sem_trywait(sem) == 0) {
|
||||||
|
|
||||||
|
/* Yes, got it immediately. */
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* No, we've got to do it with a sem_wait() call and a thread to run
|
||||||
|
* the timeout. First, work out the time from now to the specified
|
||||||
|
* timeout, which we will pass to the timeout thread in a way that can
|
||||||
|
* be used to pass to nanosleep(). So we need this in seconds and
|
||||||
|
* nanoseconds. Along the way, we check for an invalid passed time,
|
||||||
|
* and for one that's already expired.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000)) {
|
||||||
|
|
||||||
|
/* Passed time is invalid */
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
struct timeval currentTime; /* Time now */
|
||||||
|
long secsToWait,nsecsToWait; /* Seconds and nsec to delay */
|
||||||
|
gettimeofday (¤tTime,NULL);
|
||||||
|
secsToWait = abs_timeout->tv_sec - currentTime.tv_sec;
|
||||||
|
nsecsToWait = (abs_timeout->tv_nsec - (currentTime.tv_usec * 1000));
|
||||||
|
while (nsecsToWait < 0) {
|
||||||
|
nsecsToWait += 1000000000;
|
||||||
|
secsToWait--;
|
||||||
|
}
|
||||||
|
if ((secsToWait < 0) || ((secsToWait == 0) && (nsecsToWait < 0))) {
|
||||||
|
|
||||||
|
/* Time has passed. Report an immediate timeout. */
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
errno = ETIMEDOUT;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* We're going to have to do a sem_wait() with a timeout thread.
|
||||||
|
* The thread will wait the specified time, then will issue a
|
||||||
|
* SIGUSR2 signal that will interrupt the sem_wait() call.
|
||||||
|
* We pass the thread the id of the current thread, the delay,
|
||||||
|
* and the address of a flag to set on a timeout, so we can
|
||||||
|
* distinguish an interrupt caused by the timeout thread from
|
||||||
|
* one caused by some other signal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
volatile short timedOut; /* Flag to set on timeout */
|
||||||
|
timeoutDetails details; /* All the stuff the thread must know */
|
||||||
|
struct sigaction oldSignalAction; /* Current signal setting */
|
||||||
|
pthread_t timeoutThread; /* Id of timeout thread */
|
||||||
|
cleanupDetails cleaningDetails; /* What the cleanup routine needs */
|
||||||
|
int oldCancelState; /* Previous cancellation state */
|
||||||
|
int ignoreCancelState; /* Used in call, but ignored */
|
||||||
|
int createStatus; /* Status of pthread_create() call */
|
||||||
|
|
||||||
|
/* If the current thread is cancelled (and CML does do this)
|
||||||
|
* we don't want to leave our timer thread running - if we've
|
||||||
|
* started the thread we want to make sure we join it in order
|
||||||
|
* to release its resources. So we set a cleanup handler to
|
||||||
|
* do this. We pass it the address of the structure that will
|
||||||
|
* hold all it needs to know. While we set all this up,
|
||||||
|
* we prevent ourselves being cancelled, so all this data is
|
||||||
|
* coherent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE,&oldCancelState);
|
||||||
|
timeoutThread = (pthread_t) 0;
|
||||||
|
cleaningDetails.timedOutShort = &timedOut;
|
||||||
|
cleaningDetails.threadIdAddr = &timeoutThread;
|
||||||
|
cleaningDetails.sigHandlerAddr = &oldSignalAction;
|
||||||
|
pthread_cleanup_push (timeoutThreadCleanup,&cleaningDetails);
|
||||||
|
|
||||||
|
/* Set up the details for the thread. Clear the timeout flag,
|
||||||
|
* record the current SIGUSR2 action settings so we can restore
|
||||||
|
* them later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details.delay.tv_sec = secsToWait;
|
||||||
|
details.delay.tv_nsec = nsecsToWait;
|
||||||
|
details.callingThread = pthread_self();
|
||||||
|
details.timedOutShort = &timedOut;
|
||||||
|
timedOut = FALSE;
|
||||||
|
sigaction (SIGUSR2,NULL,&oldSignalAction);
|
||||||
|
|
||||||
|
/* Start up the timeout thread. Once we've done that, we can
|
||||||
|
* restore the previous cancellation state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
createStatus = pthread_create(&timeoutThread,NULL,
|
||||||
|
timeoutThreadMain, (void*)&details);
|
||||||
|
pthread_setcancelstate (oldCancelState,&ignoreCancelState);
|
||||||
|
|
||||||
|
if (createStatus < 0) {
|
||||||
|
|
||||||
|
/* Failed to create thread. errno will already be set properly */
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Thread created OK. This is where we wait for the semaphore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sem_wait(sem) == 0) {
|
||||||
|
|
||||||
|
/* Got the semaphore OK. We return zero, and all's well. */
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* If we got a -1 error from sem_wait(), it may be because
|
||||||
|
* it was interrupted by a timeout, or failed for some
|
||||||
|
* other reason. We check for the expected timeout
|
||||||
|
* condition, which is an 'interrupted' status and the
|
||||||
|
* timeout flag set by the timeout thread. We report that as
|
||||||
|
* a timeout error. Anything else is some other error and
|
||||||
|
* errno is already set properly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = -1;
|
||||||
|
if (errno == EINTR) {
|
||||||
|
if (timedOut) errno = ETIMEDOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The cleanup routine - timeoutThreadCleanup() - packages up
|
||||||
|
* any tidying up that is needed, including joining with the
|
||||||
|
* timer thread. This will be called if the current thread is
|
||||||
|
* cancelled, but we need it to happen anyway, so we set the
|
||||||
|
* execute flag true here as we remove it from the list of
|
||||||
|
* cleanup routines to be called. So normally, this line amounts
|
||||||
|
* to calling timeoutThreadCleanup().
|
||||||
|
*/
|
||||||
|
|
||||||
|
pthread_cleanup_pop (TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* t i m e o u t T h r e a d C l e a n u p
|
||||||
|
*
|
||||||
|
* This internal routine tidies up at the end of a sem_timedwait() call.
|
||||||
|
* It is set as a cleanup routine for the current thread (not the timer
|
||||||
|
* thread) so it is executed even if the thread is cancelled. This is
|
||||||
|
* important, as we need to tidy up the timeout thread. If we took the
|
||||||
|
* semaphore (in other words, if we didn't timeout) then the timer thread
|
||||||
|
* will still be running, sitting in its nanosleep() call, and we need
|
||||||
|
* to cancel it. If the timer thread did signal a timeout then it will
|
||||||
|
* now be closing down. In either case, we need to join it (using a call
|
||||||
|
* to pthread_join()) or its resources will never be released.
|
||||||
|
* The single argument is a pointer to a cleanupDetails structure that has
|
||||||
|
* all the routine needs to know.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void timeoutThreadCleanup (void* passedPtr)
|
||||||
|
{
|
||||||
|
/* Get what we need from the structure we've been passed. */
|
||||||
|
|
||||||
|
cleanupDetails *detailsPtr = (cleanupDetails*) passedPtr;
|
||||||
|
short timedOut = *(detailsPtr->timedOutShort);
|
||||||
|
pthread_t timeoutThread = *(detailsPtr->threadIdAddr);
|
||||||
|
|
||||||
|
/* If we created the thread, stop it - doesn't matter if it's no longer
|
||||||
|
* running, pthread_cancel can handle that. We make sure we wait for it
|
||||||
|
* to complete, because it is this pthread_join() call that releases any
|
||||||
|
* memory the thread may have allocated. Note that cancelling a thread is
|
||||||
|
* generally not a good idea, because of the difficulty of cleaning up
|
||||||
|
* after it, but this is a very simple thread that does nothing but call
|
||||||
|
* nanosleep(), and that we can cancel quite happily.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!timedOut) pthread_cancel(timeoutThread);
|
||||||
|
pthread_join(timeoutThread,NULL);
|
||||||
|
|
||||||
|
/* The code originally restored the old action handler, which generally
|
||||||
|
* was the default handler that caused the task to exit. Just occasionally,
|
||||||
|
* there seem to be cases where the signal is still queued and ready to
|
||||||
|
* trigger even though the thread that presumably sent it off just before
|
||||||
|
* it was cancelled has finished. I had thought that once we'd joined
|
||||||
|
* that thread, we could be sure of not seeing the signal, but that seems
|
||||||
|
* not to be the case, and so restoring a handler that will allow the task
|
||||||
|
* to crash is not a good idea, and so the line below has been commented
|
||||||
|
* out.
|
||||||
|
*
|
||||||
|
* sigaction (SIGUSR2,detailsPtr->sigHandlerAddr,NULL);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* t i m e o u t T h r e a d M a i n
|
||||||
|
*
|
||||||
|
* This internal routine is the main code for the timeout thread.
|
||||||
|
* The single argument is a pointer to a timeoutDetails structure that has
|
||||||
|
* all the thread needs to know - thread to signal, delay time, and the
|
||||||
|
* address of a flag to set if it triggers a timeout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void* timeoutThreadMain (void* passedPtr)
|
||||||
|
{
|
||||||
|
void* Return = (void*) 0;
|
||||||
|
|
||||||
|
/* We grab all the data held in the calling thread right now. In some
|
||||||
|
* cases, we find that the calling thread has vanished and released
|
||||||
|
* its memory, including the details structure, by the time the timeout
|
||||||
|
* expires, and then we get an access violation when we try to set the
|
||||||
|
* 'timed out' flag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
timeoutDetails details = *((timeoutDetails*) passedPtr);
|
||||||
|
struct timespec requestedDelay = details.delay;
|
||||||
|
|
||||||
|
/* We do a nanosleep() for the specified delay, and then trigger a
|
||||||
|
* timeout. Note that we allow for the case where the nanosleep() is
|
||||||
|
* interrupted, and restart it for the remaining time. If the
|
||||||
|
* thread that is doing the sem_wait() call gets the semaphore, it
|
||||||
|
* will cancel this thread, which is fine as we aren't doing anything
|
||||||
|
* other than a sleep and a signal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct timespec remainingDelay;
|
||||||
|
if (nanosleep (&requestedDelay,&remainingDelay) == 0) {
|
||||||
|
break;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
requestedDelay = remainingDelay;
|
||||||
|
} else {
|
||||||
|
Return = (void*) errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've completed the delay without being cancelled, so we now trigger
|
||||||
|
* the timeout by sending a signal to the calling thread. And that's it,
|
||||||
|
* although we set the timeout flag first to indicate that it was us
|
||||||
|
* that interrupted the sem_wait() call. One precaution: before we
|
||||||
|
* try to set the timed-out flag, make sure the calling thread still
|
||||||
|
* exists - this may not be the case if things are closing down a bit
|
||||||
|
* messily. We check this quickly using a zero test signal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (pthread_kill(details.callingThread,0) == 0) {
|
||||||
|
*(details.timedOutShort) = TRUE;
|
||||||
|
if (triggerSignal (SIGUSR2,details.callingThread) < 0) {
|
||||||
|
Return = (void*) errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* t r i g g e r S i g n a l
|
||||||
|
*
|
||||||
|
* This is a general purpose routine that sends a specified signal to
|
||||||
|
* a specified thread, setting up a signal handler that does nothing,
|
||||||
|
* and then giving the signal. The only effect will be to interrupt any
|
||||||
|
* operation that is currently blocking - in this case, we expect this to
|
||||||
|
* be a sem_wait() call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int triggerSignal (int Signal, pthread_t Thread)
|
||||||
|
{
|
||||||
|
int Result = 0;
|
||||||
|
struct sigaction SignalDetails;
|
||||||
|
SignalDetails.sa_handler = ignoreSignal;
|
||||||
|
SignalDetails.sa_flags = 0;
|
||||||
|
(void) sigemptyset(&SignalDetails.sa_mask);
|
||||||
|
if ((Result = sigaction(Signal,&SignalDetails,NULL)) == 0) {
|
||||||
|
Result = pthread_kill(Thread,Signal);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
|
* i g n o r e S i g n a l
|
||||||
|
*
|
||||||
|
* And this is the signal handler that does nothing. (It clears its argument,
|
||||||
|
* but this has no effect and prevents a compiler warning about an unused
|
||||||
|
* argument.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void ignoreSignal (int Signal) {
|
||||||
|
Signal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef __SEM_TIMEDWAIT_H
|
||||||
|
#define __SEM_TIMEDWAIT_H
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef MELONDLDI_H
|
#ifndef MELONDLDI_H
|
||||||
#define MELONDLDI_H
|
#define MELONDLDI_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
const u8 melonDLDI[] =
|
const u8 melonDLDI[] =
|
||||||
{
|
{
|
||||||
0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x09, 0x00, 0x00,
|
0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x09, 0x00, 0x00,
|
||||||
|
|
|
@ -58,6 +58,7 @@ else()
|
||||||
-pedantic
|
-pedantic
|
||||||
-pedantic-errors
|
-pedantic-errors
|
||||||
-Wfatal-errors
|
-Wfatal-errors
|
||||||
|
-Wno-error=maybe-uninitialized
|
||||||
-Wno-missing-braces
|
-Wno-missing-braces
|
||||||
-Wno-unused-parameter)
|
-Wno-unused-parameter)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <utility>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
|
@ -7,7 +7,7 @@ $app_name = "melonDS"
|
||||||
$build_dmg = false
|
$build_dmg = false
|
||||||
$build_dir = ""
|
$build_dir = ""
|
||||||
$bundle = ""
|
$bundle = ""
|
||||||
$fallback_rpaths = ["/usr/local/lib", "/opt/local/lib"]
|
$fallback_rpaths = []
|
||||||
|
|
||||||
def frameworks_dir
|
def frameworks_dir
|
||||||
File.join($bundle, "Contents", "Frameworks")
|
File.join($bundle, "Contents", "Frameworks")
|
||||||
|
@ -56,7 +56,7 @@ def expand_load_path(lib, path)
|
||||||
file = $fallback_rpaths
|
file = $fallback_rpaths
|
||||||
.map { |it| File.join(it, file_name) }
|
.map { |it| File.join(it, file_name) }
|
||||||
.find { |it| File.exist? it }
|
.find { |it| File.exist? it }
|
||||||
if file == nil
|
if file == nil
|
||||||
path = File.join(File.dirname(lib), file_name)
|
path = File.join(File.dirname(lib), file_name)
|
||||||
file = path if File.exist? path
|
file = path if File.exist? path
|
||||||
end
|
end
|
||||||
|
@ -89,15 +89,17 @@ def install_name_tool(exec, action, path1, path2 = nil)
|
||||||
args = ["-#{action.to_s}", path1]
|
args = ["-#{action.to_s}", path1]
|
||||||
args << path2 if path2 != nil
|
args << path2 if path2 != nil
|
||||||
|
|
||||||
out, status = Open3.capture2e("install_name_tool", *args, exec)
|
Open3.popen3("install_name_tool", *args, exec) do |stdin, stdout, stderr, thread|
|
||||||
if status != 0
|
print stdout.read
|
||||||
puts out
|
err = stderr.read
|
||||||
exit status
|
unless err.match? "code signature"
|
||||||
|
print err
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def strip(lib)
|
def strip(lib)
|
||||||
out, _ = Open3.capture2("strip", "-SNTx", lib)
|
out, _ = Open3.capture2("strip", "-no_code_signature_warning", "-Sx", lib)
|
||||||
print out
|
print out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -182,6 +184,18 @@ qt_major = $1
|
||||||
qt_dir = $2
|
qt_dir = $2
|
||||||
qt_dir = File.absolute_path("#{qt_dir}/../../..")
|
qt_dir = File.absolute_path("#{qt_dir}/../../..")
|
||||||
|
|
||||||
|
for lib in get_load_libs(executable) do
|
||||||
|
next if system_lib? lib
|
||||||
|
|
||||||
|
path = File.dirname(lib)
|
||||||
|
|
||||||
|
if path.match? ".framework"
|
||||||
|
path = path.sub(/\/[^\/]+\.framework.*/, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
$fallback_rpaths << path unless $fallback_rpaths.include? path
|
||||||
|
end
|
||||||
|
|
||||||
$fallback_rpaths << File.join(qt_dir, "lib")
|
$fallback_rpaths << File.join(qt_dir, "lib")
|
||||||
|
|
||||||
plugin_paths = [
|
plugin_paths = [
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Based on Dolphin's BuildMacOSUniversalBinary.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import filecmp
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def lipo(path0, path1, dst):
|
||||||
|
if subprocess.call(["lipo", "-create", "-output", dst, path0, path1]) != 0:
|
||||||
|
print(f"WARNING: {path0} and {path1} cannot be lipo'd")
|
||||||
|
|
||||||
|
shutil.copy(path0, dst)
|
||||||
|
|
||||||
|
|
||||||
|
def recursive_merge_binaries(src0, src1, dst):
|
||||||
|
"""
|
||||||
|
Merges two build trees together for different architectures into a single
|
||||||
|
universal binary.
|
||||||
|
|
||||||
|
The rules for merging are:
|
||||||
|
|
||||||
|
1) Files that exist in either src tree are copied into the dst tree
|
||||||
|
2) Files that exist in both trees and are identical are copied over
|
||||||
|
unmodified
|
||||||
|
3) Files that exist in both trees and are non-identical are lipo'd
|
||||||
|
4) Symlinks are created in the destination tree to mirror the hierarchy in
|
||||||
|
the source trees
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Check that all files present in the folder are of the same type and that
|
||||||
|
# links link to the same relative location
|
||||||
|
for newpath0 in glob.glob(src0+"/*"):
|
||||||
|
filename = os.path.basename(newpath0)
|
||||||
|
newpath1 = os.path.join(src1, filename)
|
||||||
|
if not os.path.exists(newpath1):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if os.path.islink(newpath0) and os.path.islink(newpath1):
|
||||||
|
if os.path.relpath(newpath0, src0) == os.path.relpath(newpath1, src1):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if os.path.isdir(newpath0) and os.path.isdir(newpath1):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# isfile() can be true for links so check that both are not links
|
||||||
|
# before checking if they are both files
|
||||||
|
if (not os.path.islink(newpath0)) and (not os.path.islink(newpath1)):
|
||||||
|
if os.path.isfile(newpath0) and os.path.isfile(newpath1):
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise Exception(f"{newpath0} and {newpath1} cannot be " +
|
||||||
|
"merged into a universal binary because they are of " +
|
||||||
|
"incompatible types. Perhaps the installed libraries" +
|
||||||
|
" are from different versions for each architecture")
|
||||||
|
|
||||||
|
for newpath0 in glob.glob(src0+"/*"):
|
||||||
|
filename = os.path.basename(newpath0)
|
||||||
|
newpath1 = os.path.join(src1, filename)
|
||||||
|
new_dst_path = os.path.join(dst, filename)
|
||||||
|
if os.path.islink(newpath0):
|
||||||
|
# Symlinks will be fixed after files are resolved
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not os.path.exists(newpath1):
|
||||||
|
if os.path.isdir(newpath0):
|
||||||
|
shutil.copytree(newpath0, new_dst_path)
|
||||||
|
else:
|
||||||
|
shutil.copy(newpath0, new_dst_path)
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
if os.path.isdir(newpath1):
|
||||||
|
os.makedirs(new_dst_path)
|
||||||
|
recursive_merge_binaries(newpath0, newpath1, new_dst_path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if filecmp.cmp(newpath0, newpath1):
|
||||||
|
shutil.copy(newpath0, new_dst_path)
|
||||||
|
else:
|
||||||
|
lipo(newpath0, newpath1, new_dst_path)
|
||||||
|
|
||||||
|
# Loop over files in src1 and copy missing things over to dst
|
||||||
|
for newpath1 in glob.glob(src1+"/*"):
|
||||||
|
filename = os.path.basename(newpath1)
|
||||||
|
newpath0 = os.path.join(src0, filename)
|
||||||
|
new_dst_path = os.path.join(dst, filename)
|
||||||
|
if (not os.path.exists(newpath0)) and (not os.path.islink(newpath1)):
|
||||||
|
if os.path.isdir(newpath1):
|
||||||
|
shutil.copytree(newpath1, new_dst_path)
|
||||||
|
else:
|
||||||
|
shutil.copy(newpath1, new_dst_path)
|
||||||
|
|
||||||
|
# Fix up symlinks for path0
|
||||||
|
for newpath0 in glob.glob(src0+"/*"):
|
||||||
|
filename = os.path.basename(newpath0)
|
||||||
|
new_dst_path = os.path.join(dst, filename)
|
||||||
|
if os.path.islink(newpath0):
|
||||||
|
relative_path = os.path.relpath(os.path.realpath(newpath0), src0)
|
||||||
|
os.symlink(relative_path, new_dst_path)
|
||||||
|
# Fix up symlinks for path1
|
||||||
|
for newpath1 in glob.glob(src1+"/*"):
|
||||||
|
filename = os.path.basename(newpath1)
|
||||||
|
new_dst_path = os.path.join(dst, filename)
|
||||||
|
newpath0 = os.path.join(src0, filename)
|
||||||
|
if os.path.islink(newpath1) and not os.path.exists(newpath0):
|
||||||
|
relative_path = os.path.relpath(os.path.realpath(newpath1), src1)
|
||||||
|
os.symlink(relative_path, new_dst_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
recursive_merge_binaries(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||||
|
|
Loading…
Reference in New Issue