Update to SDL3 APIs, fix bpps, add SDL audio/video, add Metal video, fix Quartz drawing

Implement SDL3 for the SDL port if the CMake definition ENABLE_SDL3 is
set.
Implement setting the color depth for both wxWidgets and the SDL port.
Fix the coloring issues in the SDL port for OpenGL.
Implement 8 bit color support.
Update and fix the wx port SDL sound driver.
Implement SDL video in the wx port.
Silence GL deprecations on macOS.
Add SDL renderer selection.
Fix filter for bit depths other than 32 bit.
Fix GDK backend for Linux.
Add Metal renderer for macOS.
Fix Quartz drawing.
This commit is contained in:
Andy Vandijck 2025-05-04 11:39:45 +02:00 committed by Rafael Kitover
parent 3a1780145c
commit f975809e3c
107 changed files with 5023 additions and 722 deletions

View File

@ -74,6 +74,16 @@ set(CMAKE_C_STANDARD_REQUIRED True)
project(VBA-M C CXX) project(VBA-M C CXX)
if(APPLE)
include(CheckLanguage)
include(MetalShaderSupport)
check_language(Metal)
if(CMAKE_Metal_COMPILER)
enable_language(Metal)
endif()
endif()
include(CTest) include(CTest)
include(FetchContent) include(FetchContent)
include(GNUInstallDirs) include(GNUInstallDirs)

View File

@ -0,0 +1,85 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
# CMakeDetermine(LANG)Compiler.cmake -> this should find the compiler for LANG and configure CMake(LANG)Compiler.cmake.in
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
if(NOT CMAKE_Metal_COMPILER_NAMES)
set(CMAKE_Metal_COMPILER_NAMES metal)
endif()
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
set(CMAKE_Metal_COMPILER_XCODE_TYPE sourcecode.metal)
execute_process(COMMAND xcrun --find metal
OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_VARIABLE _xcrun_err RESULT_VARIABLE _xcrun_result
)
if(_xcrun_result EQUAL 0 AND EXISTS "${_xcrun_out}")
set(CMAKE_Metal_COMPILER "${_xcrun_out}")
else()
_cmake_find_compiler_path(Metal)
endif()
else()
if(CMAKE_Metal_COMPILER)
_cmake_find_compiler_path(Metal)
else()
set(CMAKE_Metal_COMPILER_INIT NOTFOUND)
if(NOT $ENV{METALC} STREQUAL "")
get_filename_component(CMAKE_Metal_COMPILER_INIT $ENV{METALC} PROGRAM PROGRAM_ARGS CMAKE_Metal_FLAGS_ENV_INIT)
if(CMAKE_Metal_FLAGS_ENV_INIT)
set(CMAKE_Metal_COMPILER_ARG1 "${CMAKE_Metal_FLAGS_ENV_INIT}" CACHE STRING "Arguments to the Metal compiler")
endif()
if(NOT EXISTS ${CMAKE_Metal_COMPILER_INIT})
message(FATAL_ERROR "Could not find compiler set in environment variable METALC\n$ENV{METALC}.\n${CMAKE_Metal_COMPILER_INIT}")
endif()
endif()
if(NOT CMAKE_Metal_COMPILER_INIT)
set(CMAKE_Metal_COMPILER_LIST metal ${_CMAKE_TOOLCHAIN_PREFIX}metal)
endif()
_cmake_find_compiler(Metal)
endif()
mark_as_advanced(CMAKE_Metal_COMPILER)
endif()
# For Metal we need to explicitly query the version.
if(CMAKE_Metal_COMPILER AND NOT CMAKE_Metal_COMPILER_VERSION)
execute_process(
COMMAND "${CMAKE_Metal_COMPILER}" --version
OUTPUT_VARIABLE output ERROR_VARIABLE output
RESULT_VARIABLE result
TIMEOUT 10
)
message(CONFIGURE_LOG
"Running the Metal compiler: \"${CMAKE_Metal_COMPILER}\" --version\n"
"${output}\n"
)
if(output MATCHES [[metal version ([0-9]+\.[0-9]+(\.[0-9]+)?)]])
set(CMAKE_Metal_COMPILER_VERSION "${CMAKE_MATCH_1}")
if(NOT CMAKE_Metal_COMPILER_ID)
set(CMAKE_Metal_COMPILER_ID "Apple")
endif()
endif()
endif()
if(NOT _CMAKE_TOOLCHAIN_LOCATION)
get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Metal_COMPILER}" PATH)
endif ()
set(_CMAKE_PROCESSING_LANGUAGE "Metal")
include(CMakeFindBinUtils)
unset(_CMAKE_PROCESSING_LANGUAGE)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in
${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake
)
set(CMAKE_Metal_COMPILER_ENV_VAR "METALC")

View File

@ -0,0 +1,27 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
# CMake(LANG)Compiler.cmake.in -> used by CMakeDetermine(LANG)Compiler.cmake
# This file is used to store compiler information and is copied down into try
# compile directories so that try compiles do not need to re-determine and test
# the LANG
set(CMAKE_Metal_COMPILER "@CMAKE_Metal_COMPILER@")
set(CMAKE_Metal_COMPILER_ID "@CMAKE_Metal_COMPILER_ID@")
set(CMAKE_Metal_COMPILER_VERSION "@CMAKE_Metal_COMPILER_VERSION@")
set(CMAKE_Metal_COMPILER_LOADED 1)
set(CMAKE_Metal_COMPILER_WORKS "@CMAKE_Metal_COMPILER_WORKS@")
set(CMAKE_Metal_COMPILER_ENV_VAR "METALC")
set(CMAKE_Metal_COMPILER_ID_RUN "@CMAKE_Metal_COMPILER_ID_RUN@")
set(CMAKE_Metal_SOURCE_FILE_EXTENSIONS metal)
set(CMAKE_Metal_OUTPUT_EXTENSION ".air")
set(CMAKE_STATIC_LIBRARY_PREFIX_Metal "")
set(CMAKE_STATIC_LIBRARY_SUFFIX_Metal ".metal-ar")
set(CMAKE_SHARED_LIBRARY_PREFIX_Metal "")
set(CMAKE_SHARED_LIBRARY_SUFFIX_Metal ".metallib")
set(CMAKE_SHARED_MODULE_PREFIX_Metal "")
set(CMAKE_SHARED_MODULE_SUFFIX_Metal ".metallib")
set(CMAKE_EXECUTABLE_SUFFIX_Metal ".metallib")

View File

@ -0,0 +1,85 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
# CMake(LANG)Information.cmake -> set up rule variables for LANG :
# CMAKE_(LANG)_CREATE_SHARED_LIBRARY
# CMAKE_(LANG)_CREATE_SHARED_MODULE
# CMAKE_(LANG)_CREATE_STATIC_LIBRARY
# CMAKE_(LANG)_COMPILE_OBJECT
# CMAKE_(LANG)_LINK_EXECUTABLE
include(CMakeCommonLanguageInclude)
set(CMAKE_Metal_FLAGS_INIT "-ffast-math")
set(CMAKE_Metal_FLAGS_DEBUG_INIT "-gline-tables-only -frecord-sources")
set(CMAKE_Metal_FLAGS_RELWITHDEBINFO_INIT "-gline-tables-only -frecord-sources")
cmake_initialize_per_config_variable(CMAKE_Metal_FLAGS "Flags used by the Metal compiler")
set(CMAKE_INCLUDE_FLAG_Metal "-I ")
set(CMAKE_Metal_COMPILER_ARG1 "")
set(CMAKE_Metal_DEFINE_FLAG -D)
set(CMAKE_Metal_FRAMEWORK_SEARCH_FLAG "-F ")
set(CMAKE_Metal_LIBRARY_PATH_FLAG "-L ")
set(CMAKE_Metal_SYSROOT_FLAG "-isysroot")
set(CMAKE_Metal_COMPILE_OPTIONS_TARGET "-target ")
set(CMAKE_DEPFILE_FLAGS_Metal "-MMD -MT dependencies -MF <DEP_FILE>")
if(CMAKE_GENERATOR MATCHES "Makefiles")
set(CMAKE_Metal_DEPFILE_FORMAT gcc)
set(CMAKE_Metal_DEPENDS_USE_COMPILER TRUE)
endif()
set(CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "${CMAKE_Metal_COMPILER}")
if(CMAKE_Metal_COMPILER_TARGET)
list(APPEND CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "-target" "${CMAKE_Metal_COMPILER_TARGET}")
endif()
# now define the following rule variables
# CMAKE_Metal_CREATE_SHARED_LIBRARY
# CMAKE_Metal_CREATE_SHARED_MODULE
# CMAKE_Metal_COMPILE_OBJECT
# CMAKE_Metal_LINK_EXECUTABLE
# variables supplied by the generator at use time
# <TARGET>
# <TARGET_BASE> the target without the suffix
# <OBJECTS>
# <OBJECT>
# <LINK_LIBRARIES>
# <FLAGS>
# <LINK_FLAGS>
# Metal compiler information
# <CMAKE_Metal_COMPILER>
# <CMAKE_SHARED_LIBRARY_CREATE_Metal_FLAGS>
# <CMAKE_SHARED_MODULE_CREATE_Metal_FLAGS>
# <CMAKE_Metal_LINK_FLAGS>
if(NOT CMAKE_Metal_COMPILE_OBJECT)
set(CMAKE_Metal_COMPILE_OBJECT
"<CMAKE_Metal_COMPILER> -c <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>"
)
endif()
if(NOT CMAKE_Metal_CREATE_SHARED_LIBRARY)
set(CMAKE_Metal_CREATE_SHARED_LIBRARY
"<CMAKE_Metal_COMPILER> <CMAKE_SHARED_LIBRARY_Metal_FLAGS> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_Metal_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
)
endif()
if(NOT CMAKE_Metal_CREATE_SHARED_MODULE)
set(CMAKE_Metal_CREATE_SHARED_MODULE
"${CMAKE_Metal_CREATE_SHARED_LIBRARY}"
)
endif()
if(NOT CMAKE_Metal_LINK_EXECUTABLE)
# Metal shaders don't really have "executables", but we need this for the try_compile to work properly, so we'll just have it output a metallib file
set(CMAKE_Metal_LINK_EXECUTABLE
"<CMAKE_Metal_COMPILER> <FLAGS> <CMAKE_Metal_LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
)
endif()
set(CMAKE_Metal_INFORMATION_LOADED 1)

View File

@ -0,0 +1,78 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
# CMakeTest(LANG)Compiler.cmake -> test the compiler and set:
# SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "")
if(CMAKE_Metal_COMPILER_FORCED)
# The compiler configuration was forced by the user.
# Assume the user has configured all compiler information.
set(CMAKE_Metal_COMPILER_WORKS TRUE)
return()
endif()
include(CMakeTestCompilerCommon)
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
if(XCODE_VERSION VERSION_GREATER 7.0)
set(CMAKE_Metal_COMPILER_WORKS 1)
endif()
endif()
# This file is used by EnableLanguage in cmGlobalGenerator to
# determine that that selected Metal compiler can actually compile
# and link the most basic of programs. If not, a fatal error
# is set and cmake stops processing commands and will not generate
# any makefiles or projects.
if(NOT CMAKE_Metal_COMPILER_WORKS)
PrintTestCompilerStatus("Metal")
__TestCompiler_setTryCompileTargetType()
string(CONCAT __TestCompiler_testMetalCompilerSource
"#ifndef __METAL_VERSION__\n"
"# error \"The CMAKE_Metal_COMPILER is not a Metal compiler\"\n"
"#endif\n"
"#import <metal_stdlib>\n"
"using namespace metal;\n"
)
# Clear result from normal variable.
unset(CMAKE_Metal_COMPILER_WORKS)
# Puts test result in cache variable.
try_compile(CMAKE_Metal_COMPILER_WORKS
SOURCE_FROM_VAR testMetalCompiler.metal __TestCompiler_testMetalCompilerSource
OUTPUT_VARIABLE __CMAKE_Metal_COMPILER_OUTPUT
)
unset(__TestCompiler_testMetalCompilerSource)
# Move result from cache to normal variable.
set(CMAKE_Metal_COMPILER_WORKS ${CMAKE_Metal_COMPILER_WORKS})
unset(CMAKE_Metal_COMPILER_WORKS CACHE)
__TestCompiler_restoreTryCompileTargetType()
set(METAL_TEST_WAS_RUN 1)
endif()
if(NOT CMAKE_Metal_COMPILER_WORKS)
PrintTestCompilerResult(CHECK_FAIL "broken")
string(REPLACE "\n" "\n " _output "${__CMAKE_Metal_COMPILER_OUTPUT}")
message(FATAL_ERROR "The Metal compiler\n \"${CMAKE_Metal_COMPILER}\"\n"
"is not able to compile a simple test program.\nIt fails "
"with the following output:\n ${_output}\n\n"
"CMake will not be able to correctly generate this project."
)
else()
if(METAL_TEST_WAS_RUN)
PrintTestCompilerResult(CHECK_PASS "works")
endif()
# Re-configure to save learned information.
configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in
${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake
@ONLY
)
include(${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake)
endif()
unset(__CMAKE_Metal_COMPILER_OUTPUT)

169
cmake/CheckLanguage.cmake Normal file
View File

@ -0,0 +1,169 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
CheckLanguage
-------------
Check whether a language can be enabled by the :command:`enable_language`
or :command:`project` commands:
.. command:: check_language
.. code-block:: cmake
check_language(<lang>)
Try enabling language ``<lang>`` in a test project and record results
in the cache:
:variable:`CMAKE_<LANG>_COMPILER`
If the language can be enabled, this variable is set to the compiler
that was found. If the language cannot be enabled, this variable is
set to ``NOTFOUND``.
If this variable is already set, either explicitly or cached by
a previous call, the check is skipped.
:variable:`CMAKE_<LANG>_HOST_COMPILER`
This variable is set when ``<lang>`` is ``CUDA`` or ``HIP``.
If the check detects an explicit host compiler that is required for
compilation, this variable will be set to that compiler.
If the check detects that no explicit host compiler is needed,
this variable will be cleared.
If this variable is already set, its value is preserved only if
:variable:`CMAKE_<LANG>_COMPILER` is also set.
Otherwise, the check runs and overwrites
:variable:`CMAKE_<LANG>_HOST_COMPILER` with a new result.
Note that :variable:`CMAKE_<LANG>_HOST_COMPILER` documents it should
not be set without also setting
:variable:`CMAKE_<LANG>_COMPILER` to a NVCC compiler.
:variable:`CMAKE_<LANG>_PLATFORM <CMAKE_HIP_PLATFORM>`
This variable is set to the detected GPU platform when ``<lang>`` is ``HIP``.
If the variable is already set its value is always preserved. Only compatible values
will be considered for :variable:`CMAKE_<LANG>_COMPILER`.
For example:
.. code-block:: cmake
check_language(Fortran)
if(CMAKE_Fortran_COMPILER)
enable_language(Fortran)
else()
message(STATUS "No Fortran support")
endif()
#]=======================================================================]
# This file has been modified to take into account the CMAKE_MODULES path when trying to build the test project
# Ref https://gitlab.kitware.com/cmake/cmake/-/issues/26020
# This was merged in to CMake 3.30.0, so we only need this for older versions
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.30)
include(${CMAKE_ROOT}/Modules/CheckLanguage.cmake)
else()
include_guard(GLOBAL)
block(SCOPE_FOR POLICIES)
cmake_policy(SET CMP0126 NEW)
macro(check_language lang)
if(NOT DEFINED CMAKE_${lang}_COMPILER)
set(_desc "Looking for a ${lang} compiler")
message(CHECK_START "${_desc}")
file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang})
set(extra_compiler_variables)
if("${lang}" MATCHES "^(CUDA|HIP)$" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
set(extra_compiler_variables "set(CMAKE_${lang}_HOST_COMPILER \\\"\${CMAKE_${lang}_HOST_COMPILER}\\\")")
endif()
if("${lang}" STREQUAL "HIP")
list(APPEND extra_compiler_variables "set(CMAKE_${lang}_PLATFORM \\\"\${CMAKE_${lang}_PLATFORM}\\\")")
endif()
list(TRANSFORM extra_compiler_variables PREPEND "\"")
list(TRANSFORM extra_compiler_variables APPEND "\\n\"")
list(JOIN extra_compiler_variables "\n " extra_compiler_variables)
set(_cl_content
"cmake_minimum_required(VERSION ${CMAKE_VERSION})
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
project(Check${lang} ${lang})
file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
\"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\"
${extra_compiler_variables}
)"
)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt"
"${_cl_content}")
if(CMAKE_GENERATOR_INSTANCE)
set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
else()
set(_D_CMAKE_GENERATOR_INSTANCE "")
endif()
if(CMAKE_GENERATOR MATCHES "^(Xcode$|Green Hills MULTI$|Visual Studio)")
set(_D_CMAKE_MAKE_PROGRAM "")
else()
set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
endif()
if(CMAKE_TOOLCHAIN_FILE)
set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
else()
set(_D_CMAKE_TOOLCHAIN_FILE "")
endif()
if(CMAKE_${lang}_PLATFORM)
set(_D_CMAKE_LANG_PLATFORM "-DCMAKE_${lang}_PLATFORM:STRING=${CMAKE_${lang}_PLATFORM}")
else()
set(_D_CMAKE_LANG_PLATFORM "")
endif()
execute_process(
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}
COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
-A "${CMAKE_GENERATOR_PLATFORM}"
-T "${CMAKE_GENERATOR_TOOLSET}"
${_D_CMAKE_GENERATOR_INSTANCE}
${_D_CMAKE_MAKE_PROGRAM}
${_D_CMAKE_TOOLCHAIN_FILE}
${_D_CMAKE_LANG_PLATFORM}
OUTPUT_VARIABLE _cl_output
ERROR_VARIABLE _cl_output
RESULT_VARIABLE _cl_result
)
include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/result.cmake OPTIONAL)
if(CMAKE_${lang}_COMPILER AND "${_cl_result}" STREQUAL "0")
message(CONFIGURE_LOG
"${_desc} passed with the following output:\n"
"${_cl_output}\n")
set(_CHECK_COMPILER_STATUS CHECK_PASS)
else()
set(CMAKE_${lang}_COMPILER NOTFOUND)
set(_CHECK_COMPILER_STATUS CHECK_FAIL)
message(CONFIGURE_LOG
"${_desc} failed with the following output:\n"
"${_cl_output}\n")
endif()
message(${_CHECK_COMPILER_STATUS} "${CMAKE_${lang}_COMPILER}")
set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler")
mark_as_advanced(CMAKE_${lang}_COMPILER)
if(CMAKE_${lang}_HOST_COMPILER)
message(STATUS "Looking for a ${lang} host compiler - ${CMAKE_${lang}_HOST_COMPILER}")
set(CMAKE_${lang}_HOST_COMPILER "${CMAKE_${lang}_HOST_COMPILER}" CACHE FILEPATH "${lang} host compiler")
mark_as_advanced(CMAKE_${lang}_HOST_COMPILER)
endif()
if(CMAKE_${lang}_PLATFORM)
set(CMAKE_${lang}_PLATFORM "${CMAKE_${lang}_PLATFORM}" CACHE STRING "${lang} platform")
mark_as_advanced(CMAKE_${lang}_PLATFORM)
endif()
endif()
endmacro()
endblock()
endif()

View File

@ -11,11 +11,23 @@ if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
set(OpenGL_GL_PREFERENCE LEGACY) set(OpenGL_GL_PREFERENCE LEGACY)
endif() endif()
find_package(OpenGL REQUIRED) if(NOT DISABLE_OPENGL)
find_package(SDL2 REQUIRED) find_package(OpenGL)
# Add libsamplerate to SDL2 with vcpkg if(NOT OpenGL_FOUND)
unset(SDL2_LIBRARY_TEMP) set(CMAKE_C_FLAGS "-DNO_OPENGL -DNO_OGL ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-DNO_OPENGL -DNO_OGL ${CMAKE_CXX_FLAGS}")
endif()
endif()
if(ENABLE_SDL3)
find_package(SDL3 REQUIRED)
else()
find_package(SDL2 REQUIRED)
endif()
# Add libsamplerate to SDL3 with vcpkg
unset(SDL_LIBRARY_TEMP)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg") if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
if(WIN32) if(WIN32)
unset(arch_suffix) unset(arch_suffix)
@ -28,16 +40,24 @@ if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
endif() endif()
set(installed_prefix ${_VCPKG_INSTALLED_DIR}/${WINARCH}-windows${arch_suffix}/${path_prefix}) set(installed_prefix ${_VCPKG_INSTALLED_DIR}/${WINARCH}-windows${arch_suffix}/${path_prefix})
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${installed_prefix}/lib/samplerate.lib) SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${installed_prefix}/lib/samplerate.lib)
else() else()
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} -lsamplerate) SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} -lsamplerate)
endif() endif()
endif() endif()
if(VBAM_STATIC) if(ENABLE_SDL3)
set(VBAM_SDL2_LIBS SDL2::SDL2-static ${SDL2_LIBRARY_TEMP}) if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL3::SDL3-static ${SDL_LIBRARY_TEMP})
else()
set(VBAM_SDL_LIBS SDL3::SDL3 ${SDL_LIBRARY_TEMP})
endif()
else() else()
set(VBAM_SDL2_LIBS SDL2::SDL2 ${SDL2_LIBRARY_TEMP}) if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL2::SDL2-static ${SDL_LIBRARY_TEMP})
else()
set(VBAM_SDL_LIBS SDL2::SDL2 ${SDL_LIBRARY_TEMP})
endif()
endif() endif()
if(ENABLE_FFMPEG) if(ENABLE_FFMPEG)

View File

@ -0,0 +1,53 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENCE.txt or https://cmake.org/licensing for details.
function(add_metal_shader_library TARGET)
cmake_parse_arguments(PARSE_ARGV 1 _amsl
""
"STANDARD"
""
)
add_library(${TARGET} MODULE ${_amsl_UNPARSED_ARGUMENTS})
set_target_properties(${TARGET} PROPERTIES
DEBUG_POSTFIX ""
XCODE_PRODUCT_TYPE com.apple.product-type.metal-library
XCODE_ATTRIBUTE_MTL_FAST_MATH "YES"
XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=Debug] "INCLUDE_SOURCE"
XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=RelWithDebInfo] "INCLUDE_SOURCE"
XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "$(HEADER_SEARCH_PATHS)"
)
if(_amsl_STANDARD AND _amsl_STANDARD MATCHES "metal([0-9]+)\.([0-9]+)")
target_compile_options(${TARGET}
PRIVATE "-std=${_amsl_STANDARD}"
)
set_target_properties(${TARGET} PROPERTIES
XCODE_ATTRIBUTE_MTL_LANGUAGE_REVISION "Metal${CMAKE_MATCH_1}${CMAKE_MATCH_2}"
)
endif()
endfunction()
function(target_embed_metal_shader_libraries TARGET)
cmake_parse_arguments(PARSE_ARGV 1 _temsl
""
""
""
)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.28 AND ${CMAKE_GENERATOR} STREQUAL "Xcode")
set_target_properties(${TARGET} PROPERTIES
XCODE_EMBED_RESOURCES "${_temsl_UNPARSED_ARGUMENTS}"
)
else()
foreach(SHADERLIB IN LISTS _temsl_UNPARSED_ARGUMENTS)
add_dependencies(${TARGET} ${SHADERLIB})
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${SHADERLIB}>" "$<TARGET_BUNDLE_CONTENT_DIR:${TARGET}>/Resources/$<TARGET_FILE_NAME:${SHADERLIB}>"
VERBATIM
)
endforeach()
endif()
endfunction()

View File

@ -9,15 +9,28 @@ else()
endif() endif()
set(ENABLE_SDL_DEFAULT ${BUILD_DEFAULT}) set(ENABLE_SDL_DEFAULT ${BUILD_DEFAULT})
if(WIN32 OR APPLE) if(WIN32 OR APPLE)
set(ENABLE_SDL_DEFAULT OFF) set(ENABLE_SDL_DEFAULT OFF)
endif() endif()
option(ENABLE_SDL3 "Use SDL3" OFF)
option(DISABLE_OPENGL "Disable OpenGL" OFF)
option(ENABLE_SDL "Build the SDL port" ${ENABLE_SDL_DEFAULT}) option(ENABLE_SDL "Build the SDL port" ${ENABLE_SDL_DEFAULT})
option(ENABLE_WX "Build the wxWidgets port" ${BUILD_DEFAULT}) option(ENABLE_WX "Build the wxWidgets port" ${BUILD_DEFAULT})
option(ENABLE_DEBUGGER "Enable the debugger" ON) option(ENABLE_DEBUGGER "Enable the debugger" ON)
option(ENABLE_ASAN "Enable -fsanitize=address by default. Requires debug build with GCC/Clang" OFF) option(ENABLE_ASAN "Enable -fsanitize=address by default. Requires debug build with GCC/Clang" OFF)
if(ENABLE_SDL3)
set(CMAKE_C_FLAGS "-DENABLE_SDL3 ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-DENABLE_SDL3 ${CMAKE_CXX_FLAGS}")
endif()
if(DISABLE_OPENGL)
set(CMAKE_C_FLAGS "-DNO_OPENGL -DNO_OGL ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-DNO_OPENGL -DNO_OGL ${CMAKE_CXX_FLAGS}")
endif()
# Static linking # Static linking
set(VBAM_STATIC_DEFAULT OFF) set(VBAM_STATIC_DEFAULT OFF)
if(VCPKG_TARGET_TRIPLET MATCHES -static OR CMAKE_TOOLCHAIN_FILE MATCHES "mxe|-static") if(VCPKG_TARGET_TRIPLET MATCHES -static OR CMAKE_TOOLCHAIN_FILE MATCHES "mxe|-static")
@ -30,6 +43,8 @@ option(VBAM_STATIC "Try to link all libraries statically" ${VBAM_STATIC_DEFAULT}
if(VBAM_STATIC) if(VBAM_STATIC)
set(SDL2_STATIC ON) set(SDL2_STATIC ON)
set(SDL3_STATIC ON)
set(SFML_STATIC_LIBRARIES ON)
set(FFMPEG_STATIC ON) set(FFMPEG_STATIC ON)
set(OPENAL_STATIC ON) set(OPENAL_STATIC ON)
set_property(GLOBAL PROPERTY LINK_SEARCH_START_STATIC ON) set_property(GLOBAL PROPERTY LINK_SEARCH_START_STATIC ON)

View File

@ -68,6 +68,8 @@ if(CMAKE_VERSION VERSION_LESS "3.25")
endif() endif()
endif() endif()
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/std:c++17>)
set(CMAKE_RC_FLAGS "-c65001 /DWIN32" CACHE STRING "" FORCE) set(CMAKE_RC_FLAGS "-c65001 /DWIN32" CACHE STRING "" FORCE)
# We need to explicitly set all of these to override the CMake defaults. # We need to explicitly set all of these to override the CMake defaults.

View File

@ -361,6 +361,14 @@ msgstr "Няма намерени използваеми добавки в/ъв
msgid "Plugin" msgid "Plugin"
msgstr "Добавка" msgstr "Добавка"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Битове на пиксел"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Битове на пиксел:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -361,6 +361,14 @@ msgstr "N'eo ket bet kavet an astenn rpi implijadus e-barzh %s"
msgid "Plugin" msgid "Plugin"
msgstr "Astenn" msgstr "Astenn"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -365,6 +365,14 @@ msgstr "V %s nenalezeny žádné použitelné zásuvné moduly rpi"
msgid "Plugin" msgid "Plugin"
msgstr "Zásuvný modul" msgstr "Zásuvný modul"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Počet bitů na pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Počet bitů na pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -378,6 +378,14 @@ msgstr "Keine anwendbaren RPI-Plugins in %s gefunden"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits pro Pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits pro Pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -362,6 +362,14 @@ msgstr "Δεν βρέθηκαν χρήσιμες επεκτάσεις rpi στο
msgid "Plugin" msgid "Plugin"
msgstr "Επέκταση" msgstr "Επέκταση"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits ανά pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits ανά pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1560,6 +1560,14 @@ msgstr ""
msgid "Using interframe blending: %s" msgid "Using interframe blending: %s"
msgstr "" msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per pixel:"
#: dialogs/game-boy-config.cpp:142 xrc/GameBoyAdvanceConfig.xrc:122 #: dialogs/game-boy-config.cpp:142 xrc/GameBoyAdvanceConfig.xrc:122
#: xrc/GameBoyConfig.xrc:138 xrc/GameBoyConfig.xrc:159 #: xrc/GameBoyConfig.xrc:138 xrc/GameBoyConfig.xrc:159
msgid "(None)" msgid "(None)"

View File

@ -382,6 +382,14 @@ msgstr "No se encontraron complementos rpi usables en %s"
msgid "Plugin" msgid "Plugin"
msgstr "Complemento" msgstr "Complemento"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por píxel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -374,6 +374,14 @@ msgstr "No usable rpi plugins found in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por píxel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1553,6 +1553,14 @@ msgstr "No usable rpi plugins found in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per píxel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1549,6 +1549,14 @@ msgstr "No usable rpi plugins found in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per píxel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1549,6 +1549,14 @@ msgstr "No usable rpi plugins found in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per píxel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1563,6 +1563,14 @@ msgstr "Extension rpi utilisable non trouvée dans %s"
msgid "Plugin" msgid "Plugin"
msgstr "Extension" msgstr "Extension"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits par pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits par pixel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -369,6 +369,14 @@ msgstr "Aucun plugin RPI utilisable n'a été trouvé dans %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits par pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits par pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -364,6 +364,14 @@ msgstr "Non se atoparon complementos rpi aproveitábeis en %s"
msgid "Plugin" msgid "Plugin"
msgstr "Complemento" msgstr "Complemento"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por píxel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por píxel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -362,6 +362,14 @@ msgstr "לא נמצא תוסף rpi הניתן לשימוש ב-%s"
msgid "Plugin" msgid "Plugin"
msgstr "תוסף" msgstr "תוסף"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "סיביות לפיקסל"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "סיביות לפיקסל:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1549,6 +1549,14 @@ msgstr "A %s helyen nincs használható RPI bővítmény"
msgid "Plugin" msgid "Plugin"
msgstr "Bővítmény" msgstr "Bővítmény"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bit per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bit per pixel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -363,6 +363,14 @@ msgstr "A %s helyen nincs használható RPI bővítmény"
msgid "Plugin" msgid "Plugin"
msgstr "Bővítmény" msgstr "Bővítmény"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bit per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bit per pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -366,6 +366,14 @@ msgstr "Tidak menemukan plugin rpi yang dapat digunakan di %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bit per piksel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bit per piksel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -378,6 +378,14 @@ msgstr "Non sono stati trovati plugin rpi utilizzabili in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bit per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bit per pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -370,6 +370,14 @@ msgstr "%s に使用可能なrpiプラグインが見つかりませんでした
msgid "Plugin" msgid "Plugin"
msgstr "プラグイン" msgstr "プラグイン"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "ピクセルあたりのビット数"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "ピクセルあたりのビット数:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -362,6 +362,14 @@ msgstr ""
msgid "Plugin" msgid "Plugin"
msgstr "" msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr ""
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1552,6 +1552,14 @@ msgstr "%s에서 사용가능한 rpi 플러그인을 찾을 수 없음"
msgid "Plugin" msgid "Plugin"
msgstr "플러그인" msgstr "플러그인"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "픽셀당 비트"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "픽셀당 비트:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -365,6 +365,14 @@ msgstr "%s에서 사용가능한 rpi 플러그인을 찾을 수 없음"
msgid "Plugin" msgid "Plugin"
msgstr "플러그인" msgstr "플러그인"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "픽셀당 비트"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "픽셀당 비트:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -361,6 +361,14 @@ msgstr "Tiada pemalam rpi boleh guna ditemui dalam %s"
msgid "Plugin" msgid "Plugin"
msgstr "Pemalam" msgstr "Pemalam"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bit setiap piksel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bit setiap piksel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -364,6 +364,14 @@ msgstr "Ingen brukbare rpi plugins funnet i %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per piksel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per piksel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -365,6 +365,14 @@ msgstr "Geen bruikbare rpi plugin gevonden in %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plug-in" msgstr "Plug-in"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits per pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1552,6 +1552,14 @@ msgstr "Nie znaleziono użytecznych wtyczek rpi w %s"
msgid "Plugin" msgid "Plugin"
msgstr "Wtyczka" msgstr "Wtyczka"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bity na piksel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bity na piksel:"
#: dialogs/display-config.cpp:417 #: dialogs/display-config.cpp:417
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -361,6 +361,14 @@ msgstr "Nie znaleziono użytecznych wtyczek rpi w %s"
msgid "Plugin" msgid "Plugin"
msgstr "Wtyczka" msgstr "Wtyczka"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bity na piksel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bity na piksel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -390,6 +390,14 @@ msgstr "Nenhum plugin rpi usável foi encontrado em %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -362,6 +362,14 @@ msgstr ""
msgid "Plugin" msgid "Plugin"
msgstr "" msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bits por pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bits por pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -377,6 +377,14 @@ msgstr "Не найдено подходящих rpi-плагинов в %s"
msgid "Plugin" msgid "Plugin"
msgstr "Плагин" msgstr "Плагин"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Бит на пиксель"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Бит на пиксель:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -369,6 +369,14 @@ msgstr "Inga användbara rpi plugins funna i %s"
msgid "Plugin" msgid "Plugin"
msgstr "Plugin" msgstr "Plugin"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Bitar per pixel"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Bitar per pixel:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -370,6 +370,14 @@ msgstr "%s'da kullanılabilir bir rpi eklentisi bulunamadı"
msgid "Plugin" msgid "Plugin"
msgstr "Eklenti" msgstr "Eklenti"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Piksel başına bit sayısı"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Piksel başına bit sayısı:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -362,6 +362,14 @@ msgstr "Не знайдено придатних rpi-плаґінів у %s."
msgid "Plugin" msgid "Plugin"
msgstr "Плаґін" msgstr "Плаґін"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "Біт на піксель"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "Біт на піксель:"
#: dialogs/display-config.cpp:407 #: dialogs/display-config.cpp:407
#, c-format #, c-format
msgid "Using pixel filter: %s" msgid "Using pixel filter: %s"

View File

@ -1046,6 +1046,14 @@ msgstr ""
msgid "Invalid value for Default magnification." msgid "Invalid value for Default magnification."
msgstr "" msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr ""
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr ""
#: dialogs/display-config.cpp:331 xrc/DisplayConfig.xrc:86 #: dialogs/display-config.cpp:331 xrc/DisplayConfig.xrc:86
#: xrc/DisplayConfig.xrc:136 xrc/DisplayConfig.xrc:222 #: xrc/DisplayConfig.xrc:136 xrc/DisplayConfig.xrc:222
#: xrc/GameBoyAdvanceConfig.xrc:32 xrc/GameBoyAdvanceConfig.xrc:204 #: xrc/GameBoyAdvanceConfig.xrc:32 xrc/GameBoyAdvanceConfig.xrc:204

View File

@ -360,6 +360,14 @@ msgstr "浏览"
msgid "Invalid value for Default magnification." msgid "Invalid value for Default magnification."
msgstr "无效的默认放大倍数值。" msgstr "无效的默认放大倍数值。"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth"
msgstr "每像素位数"
#: xrc/DisplayConfig.xrc
msgid "Bit Depth:"
msgstr "每像素位数:"
#: dialogs/display-config.cpp:331 xrc/DisplayConfig.xrc:86 #: dialogs/display-config.cpp:331 xrc/DisplayConfig.xrc:86
#: xrc/DisplayConfig.xrc:136 xrc/DisplayConfig.xrc:222 #: xrc/DisplayConfig.xrc:136 xrc/DisplayConfig.xrc:222
#: xrc/GameBoyAdvanceConfig.xrc:32 xrc/GameBoyAdvanceConfig.xrc:204 #: xrc/GameBoyAdvanceConfig.xrc:32 xrc/GameBoyAdvanceConfig.xrc:204

View File

@ -226,6 +226,9 @@ recording::MediaRet recording::MediaRecorder::setup_video_stream_info(int width,
{ {
switch (depth) switch (depth)
{ {
case 8:
pixfmt = AV_PIX_FMT_RGB8;
break;
case 16: case 16:
// FIXME: test & make endian-neutral // FIXME: test & make endian-neutral
pixfmt = AV_PIX_FMT_RGB565LE; pixfmt = AV_PIX_FMT_RGB565LE;
@ -250,6 +253,9 @@ recording::MediaRet recording::MediaRecorder::setup_video_stream_info(int width,
linesize = pixsize * width; linesize = pixsize * width;
switch (pixsize) switch (pixsize)
{ {
case 1:
tbord = 1; rbord = 2;
break;
case 2: case 2:
// 16-bit: 2 @ right, 1 @ top // 16-bit: 2 @ right, 1 @ top
tbord = 1; rbord = 2; tbord = 1; rbord = 2;

View File

@ -45,11 +45,11 @@ void lq2x(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp,
// in any case, they are worthless, since all renderers do "simple" or // in any case, they are worthless, since all renderers do "simple" or
// better by default // better by default
void Simple2x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple2x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
void Simple2x(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple2x16(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
void Simple3x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple3x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
void Simple3x(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple3x16(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
void Simple4x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple4x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
void Simple4x(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void Simple4x16(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
// note: 16-bit input for asm version only! // note: 16-bit input for asm version only!
void hq3x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h); void hq3x32(uint8_t* src, uint32_t spitch, uint8_t*, uint8_t* dst, uint32_t dstp, int w, int h);
// this takes 32-bit input // this takes 32-bit input

View File

@ -5,6 +5,7 @@ extern int systemRedShift;
extern int systemGreenShift; extern int systemGreenShift;
extern int systemBlueShift; extern int systemBlueShift;
extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000]; extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000]; extern uint32_t systemColorMap32[0x10000];
@ -27,6 +28,13 @@ inline void swap(short& a, short& b)
void gbafilter_update_colors(bool lcd) { void gbafilter_update_colors(bool lcd) {
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) |
((((i & 0x3e0) >> 5) << 0) & 0x1C) |
((((i & 0x7c00) >> 10) >> 3) & 0x3));
}
} break;
case 16: { case 16: {
for (int i = 0; i < 0x10000; i++) { for (int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
@ -237,6 +245,15 @@ void gbafilter_pad(uint8_t* buf, int count)
void UpdateSystemColorMaps(int lcd) void UpdateSystemColorMaps(int lcd)
{ {
switch(systemColorDepth) { switch(systemColorDepth) {
case 8:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap8[i] = (((i & 0x1f) << systemRedShift) & 0xE0) |
((((i & 0x3e0) >> 5) << systemGreenShift) & 0x1C) |
((((i & 0x7c00) >> 10) << systemBlueShift) & 0x3);
}
}
break;
case 16: case 16:
{ {
for(int i = 0; i < 0x10000; i++) { for(int i = 0; i < 0x10000; i++) {

View File

@ -159,6 +159,51 @@ static void SmartIB_MMX(uint8_t *srcPtr, uint32_t srcPitch, int width, int start
} }
#endif #endif
void SmartIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{
(void)width; // unused param
if(frm1 == NULL) {
InterframeFilterInit();
}
uint16_t colorMask = ~RGB_LOW_BITS_MASK;
uint8_t *src0 = (uint8_t *)srcPtr + starty * srcPitch;
uint8_t *src1 = (uint8_t *)frm1 + srcPitch * starty;
uint8_t *src2 = (uint8_t *)frm2 + srcPitch * starty;
uint8_t *src3 = (uint8_t *)frm3 + srcPitch * starty;
int sPitch = srcPitch;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
uint16_t color = src0[pos] == 0xff ? 0x7fff : ((src0[pos] & 0xe0) << 7) | ((src0[pos] & 0x1c) << 5) | ((src0[pos] & 0x3) << 3);
uint16_t color2 = src1[pos] == 0xff ? 0x7fff : ((src1[pos] & 0xe0) << 7) | ((src1[pos] & 0x1c) << 5) | ((src1[pos] & 0x3) << 3);
uint16_t color_dst = ((color & colorMask) >> 1) + ((color2 & colorMask) >> 1);
src0[pos] =
(src1[pos] != src2[pos]) &&
(src3[pos] != color) &&
((color == src2[pos]) || (src1[pos] == src3[pos]))
? (uint8_t)(((color_dst >> 7) & 0xe0) | ((color_dst >> 5) & 0x1c) | ((color_dst >> 3) & 0x3)) :
(uint8_t)(((color >> 7) & 0xe0) | ((color >> 5) & 0x1c) | ((color >> 3) & 0x3));
src3[pos] = (uint8_t)(((color >> 7) & 0xe0) | ((color >> 5) & 0x1c) | ((color >> 3) & 0x3)); /* oldest buffer now holds newest frame */
pos++;
}
/* Swap buffers around */
uint8_t *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
void SmartIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int height)
{
SmartIB8(srcPtr, srcPitch, width, 0, height);
}
void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height) void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{ {
(void)width; // unused param (void)width; // unused param
@ -207,6 +252,64 @@ void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int height)
SmartIB(srcPtr, srcPitch, width, 0, height); SmartIB(srcPtr, srcPitch, width, 0, height);
} }
void SmartIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{
(void)width; // unused param
if(frm1 == NULL) {
InterframeFilterInit();
}
uint8_t colorMask = 0xfe;
uint8_t *src0 = (uint8_t *)srcPtr + starty * srcPitch / 3;
uint8_t *src1 = (uint8_t *)frm1 + srcPitch * starty / 3;
uint8_t *src2 = (uint8_t *)frm2 + srcPitch * starty / 3;
uint8_t *src3 = (uint8_t *)frm3 + srcPitch * starty / 3;
int sPitch = srcPitch / 3;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
uint8_t color = src0[pos];
uint8_t color2 = src0[pos+1];
uint8_t color3 = src0[pos+2];
src0[pos] =
(src1[pos] != src2[pos]) &&
(src3[pos] != color) &&
((color == src2[pos]) || (src1[pos] == src3[pos]))
? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) :
color;
src0[pos+1] =
(src1[pos+1] != src2[pos+1]) &&
(src3[pos+1] != color2) &&
((color2 == src2[pos+1]) || (src1[pos+1] == src3[pos+1]))
? (((color2 & colorMask) >> 1) + ((src1[pos+1] & colorMask) >> 1)) :
color2;
src0[pos+2] =
(src1[pos+2] != src2[pos+2]) &&
(src3[pos+2] != color3) &&
((color3 == src2[pos+2]) || (src1[pos+1] == src3[pos+2]))
? (((color3 & colorMask) >> 1) + ((src1[pos+2] & colorMask) >> 1)) :
color3;
src3[pos] = color; /* oldest buffer now holds newest frame */
src3[pos+1] = color2; /* oldest buffer now holds newest frame */
src3[pos+2] = color3; /* oldest buffer now holds newest frame */
pos += 3;
}
/* Swap buffers around */
uint8_t *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
void SmartIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int height)
{
SmartIB24(srcPtr, srcPitch, width, 0, height);
}
#ifdef MMX #ifdef MMX
static void SmartIB32_MMX(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height) static void SmartIB32_MMX(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{ {
@ -443,6 +546,70 @@ static void MotionBlurIB_MMX(uint8_t *srcPtr, uint32_t srcPitch, int width, int
} }
#endif #endif
void MotionBlurIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{
(void)width; // unused param
if(frm1 == NULL) {
InterframeFilterInit();
}
uint8_t colorMask = 0xfe;
uint8_t *src0 = (uint8_t *)srcPtr + starty * srcPitch / 3;
uint8_t *src1 = (uint8_t *)frm1 + starty * srcPitch / 3;
int sPitch = srcPitch / 3;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
uint8_t color = src0[pos];
uint8_t color2 = src0[pos+1];
uint8_t color3 = src0[pos+2];
src0[pos] = ((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1);
src0[pos+1] = ((color2 & colorMask) >> 1) + ((src1[pos+1] & colorMask) >> 1);
src0[pos+2] = ((color3 & colorMask) >> 1) + ((src1[pos+2] & colorMask) >> 1);
src1[pos] = color;
src1[pos+1] = color2;
src1[pos+2] = color3;
pos += 3;
}
}
void MotionBlurIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int height)
{
MotionBlurIB24(srcPtr, srcPitch, width, 0, height);
}
void MotionBlurIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{
(void)width; // unused param
if(frm1 == NULL) {
InterframeFilterInit();
}
uint16_t colorMask = ~RGB_LOW_BITS_MASK;
uint8_t *src0 = (uint8_t *)srcPtr + starty * srcPitch;
uint8_t *src1 = (uint8_t *)frm1 + starty * srcPitch;
int sPitch = srcPitch;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
uint16_t color = src0[pos] == 0xff ? 0x7fff : ((src0[pos] & 0xe0) << 7) | ((src0[pos] & 0x1c) << 5) | ((src0[pos] & 0x3) << 3);
uint16_t color2 = src1[pos] == 0xff ? 0x7fff : ((src1[pos] & 0xe0) << 7) | ((src1[pos] & 0x1c) << 5) | ((src1[pos] & 0x3) << 3);
uint16_t color_dst = ((color & colorMask) >> 1) + ((color2 & colorMask) >> 1);
src0[pos] = (uint8_t)(((color_dst >> 7) & 0xe0) | ((color_dst >> 5) & 0x1c) | ((color_dst >> 3) & 0x3));
src1[pos] = (uint8_t)(((color >> 7) & 0xe0) | ((color >> 5) & 0x1c) | ((color >> 3) & 0x3));
pos++;
}
}
void MotionBlurIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int height)
{
MotionBlurIB8(srcPtr, srcPitch, width, 0, height);
}
void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height) void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height)
{ {
(void)width; // unused param (void)width; // unused param

View File

@ -14,8 +14,12 @@ void InterframeCleanup();
// all 4 are MMX-accelerated if enabled // all 4 are MMX-accelerated if enabled
void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height); void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void SmartIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void SmartIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void SmartIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height); void SmartIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height); void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void MotionBlurIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void MotionBlurIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
void MotionBlurIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height); void MotionBlurIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int starty, int height);
#ifdef MMX #ifdef MMX
@ -27,8 +31,12 @@ static void MotionBlurIB32_MMX(uint8_t *srcPtr, uint32_t srcPitch, int width, in
//Options for if start is 0 //Options for if start is 0
void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int height); void SmartIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void SmartIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void SmartIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void SmartIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int height); void SmartIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int height); void MotionBlurIB(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void MotionBlurIB8(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void MotionBlurIB24(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
void MotionBlurIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int height); void MotionBlurIB32(uint8_t *srcPtr, uint32_t srcPitch, int width, int height);
#endif //VBAM_COMPONENTS_FILTERS_INTERFRAME_INTERFRAME_H_ #endif //VBAM_COMPONENTS_FILTERS_INTERFRAME_INTERFRAME_H_

View File

@ -10,6 +10,8 @@ extern "C" {
#include "core/base/system.h" #include "core/base/system.h"
#include "core/base/message.h" #include "core/base/message.h"
bool no_border = false;
bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) { bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
static constexpr size_t kNumChannels = 3; static constexpr size_t kNumChannels = 3;
uint8_t* writeBuffer = new uint8_t[w * h * kNumChannels]; uint8_t* writeBuffer = new uint8_t[w * h * kNumChannels];
@ -20,6 +22,27 @@ bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
int sizeY = h; int sizeY = h;
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
uint8_t* pixU8 = (uint8_t*)pix + (w);
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
// White color fix
if (*pixU8 == 0xff) {
*b++ = 0xff;
*b++ = 0xff;
*b++ = 0xff;
} else {
*b++ = (((*pixU8 >> 5) & 0x7) << 5);
*b++ = (((*pixU8 >> 2) & 0x7) << 5);
*b++ = ((*pixU8 & 0x3) << 6);
}
}
if (no_border == false) {
pixU8 += 2;
}
}
} break;
case 16: { case 16: {
uint16_t* p = (uint16_t*)(pix + (w + 2) * 2); // skip first black line uint16_t* p = (uint16_t*)(pix + (w + 2) * 2); // skip first black line
for (int y = 0; y < sizeY; y++) { for (int y = 0; y < sizeY; y++) {
@ -125,6 +148,40 @@ bool utilWriteBMPFile(const char* fileName, int w, int h, uint8_t* pix) {
int sizeY = h; int sizeY = h;
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
uint8_t* pixU8 = 0;
if (no_border == false) {
pixU8 = (uint8_t*)pix + ((w + 2) * (h));
} else {
pixU8 = (uint8_t*)pix + ((w) * (h));
}
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
// White color fix
if (*pixU8 == 0xff) {
*b++ = 0xff;
*b++ = 0xff;
*b++ = 0xff;
} else {
*b++ = ((*pixU8 & 0x3) << 6);
*b++ = (((*pixU8 >> 2) & 0x7) << 5);
*b++ = (((*pixU8 >> 5) & 0x7) << 5);
}
}
if (no_border == false) {
pixU8++;
pixU8++;
pixU8 -= 2 * (w + 2);
} else {
pixU8 -= 2 * (w);
}
fwrite(writeBuffer, 1, 3 * w, fp);
b = writeBuffer;
}
} break;
case 16: { case 16: {
uint16_t* p = (uint16_t*)(pix + (w + 2) * (h) * 2); // skip first black line uint16_t* p = (uint16_t*)(pix + (w + 2) * (h) * 2); // skip first black line
for (int y = 0; y < sizeY; y++) { for (int y = 0; y < sizeY; y++) {

View File

@ -10,4 +10,6 @@
bool utilWritePNGFile(const char*, int, int, uint8_t*); bool utilWritePNGFile(const char*, int, int, uint8_t*);
bool utilWriteBMPFile(const char*, int, int, uint8_t*); bool utilWriteBMPFile(const char*, int, int, uint8_t*);
extern bool no_border;
#endif // VBAM_CORE_BASE_IMAGE_UTIL_H_ #endif // VBAM_CORE_BASE_IMAGE_UTIL_H_

View File

@ -20,6 +20,10 @@
#include "core/base/internal/memgzio.h" #include "core/base/internal/memgzio.h"
#if __STDC_WANT_SECURE_LIB__
#define vsnprintf vsprintf_s
#endif
#ifndef local #ifndef local
#define local static #define local static
#endif #endif
@ -213,7 +217,7 @@ local int memPrintf(MEMFILE *f, const char *format, ...)
int len; int len;
va_start(list, format); va_start(list, format);
len = vsprintf(buffer, format, list); len = vsnprintf(buffer, sizeof(buffer), format, list);
va_end(list); va_end(list);
return (int)memWrite(buffer, 1, len, f); return (int)memWrite(buffer, 1, len, f);

View File

@ -110,6 +110,7 @@ extern void systemFrame();
extern void systemGbBorderOn(); extern void systemGbBorderOn();
extern void (*dbgOutput)(const char* s, uint32_t addr); extern void (*dbgOutput)(const char* s, uint32_t addr);
extern void (*dbgSignal)(int sig, int number); extern void (*dbgSignal)(int sig, int number);
extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000]; extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000]; extern uint32_t systemColorMap32[0x10000];
extern uint16_t systemGbPalette[24]; extern uint16_t systemGbPalette[24];

View File

@ -3887,6 +3887,41 @@ int gbGetNextEvent(int _clockTicks)
void gbDrawLine() void gbDrawLine()
{ {
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
#ifdef __LIBRETRO__
uint8_t* dest = (uint8_t*)g_pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
+ gbBorderColumnSkip;
#else
uint8_t* dest = (uint8_t*)g_pix + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (size_t x = 0; x < kGBWidth;) {
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
*dest++ = systemColorMap8[gbLineMix[x++]];
}
if (gbBorderOn)
dest += gbBorderColumnSkip;
#ifndef __LIBRETRO__
*dest++ = 0; // for filters that read one pixel more
#endif
} break;
case 16: { case 16: {
#ifdef __LIBRETRO__ #ifdef __LIBRETRO__
uint16_t* dest = (uint16_t*)g_pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip) uint16_t* dest = (uint16_t*)g_pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)

View File

@ -4,6 +4,10 @@
#include "core/gb/gbGlobals.h" #include "core/gb/gbGlobals.h"
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
typedef struct { typedef struct {
uint8_t mask; uint8_t mask;
uint8_t value; uint8_t value;
@ -132,12 +136,12 @@ static char* addStr(char* p, const char* s)
return p; return p;
} }
int gbDis(char* buffer, uint16_t address) int gbDis(char* buffer, int buflen, uint16_t address)
{ {
char* p = buffer; char* p = buffer;
uint16_t instr = 1; uint16_t instr = 1;
uint16_t addr = address; uint16_t addr = address;
sprintf(p, "%04x ", address); snprintf(p, buflen, "%04x ", address);
p += 12; p += 12;
uint8_t opcode = GB_READ(address); uint8_t opcode = GB_READ(address);
@ -183,7 +187,7 @@ int gbDis(char* buffer, uint16_t address)
disp = GB_READ(address); disp = GB_READ(address);
if (disp >= 0) if (disp >= 0)
*p++ = '+'; *p++ = '+';
p += sprintf(p, "%d", disp); p += snprintf(p, buflen, "%d", disp);
instr++; instr++;
break; break;
case 'd': case 'd':

View File

@ -3,6 +3,6 @@
#include <cstdint> #include <cstdint>
int gbDis(char*, uint16_t); int gbDis(char* buffer, int buflen, uint16_t address);
#endif // VBAM_CORE_GB_GBDIS_H_ #endif // VBAM_CORE_GB_GBDIS_H_

View File

@ -54,6 +54,11 @@ inline void gbSgbDraw16Bit(uint16_t* p, uint16_t v)
*p = systemColorMap16[v]; *p = systemColorMap16[v];
} }
inline void gbSgbDraw8Bit(uint8_t* p, uint16_t v)
{
*p = systemColorMap8[v];
}
void gbSgbReset() void gbSgbReset()
{ {
gbSgbPacketTimeout = 0; gbSgbPacketTimeout = 0;
@ -112,6 +117,18 @@ void gbSgbShutdown()
void gbSgbFillScreen(uint16_t color) void gbSgbFillScreen(uint16_t color)
{ {
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
for (int y = 0; y < 144; y++) {
#ifdef __LIBRETRO__
int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
#else
int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 2) + gbBorderColumnSkip;
#endif
uint8_t* dest = (uint8_t*)g_pix + yLine;
for (int x = 0; x < 160; x++)
gbSgbDraw8Bit(dest++, color);
}
} break;
case 16: { case 16: {
for (int y = 0; y < 144; y++) { for (int y = 0; y < 144; y++) {
#ifdef __LIBRETRO__ #ifdef __LIBRETRO__
@ -198,7 +215,7 @@ void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
uint32_t* dest32 = (uint32_t*)g_pix + ((y + 1) * (256 + 1)) + x; uint32_t* dest32 = (uint32_t*)g_pix + ((y + 1) * (256 + 1)) + x;
#endif #endif
uint8_t* dest8 = (uint8_t*)g_pix + ((y * 256) + x) * 3; uint8_t* dest8 = (uint8_t*)g_pix + ((y * 256) + x) * 3;
uint8_t* dest8b = (uint8_t*)g_pix + ((y * 256) + x);
uint8_t* tileAddress = &gbSgbBorderChar[tile * 32]; uint8_t* tileAddress = &gbSgbBorderChar[tile * 32];
uint8_t* tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; uint8_t* tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
@ -258,6 +275,12 @@ void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
} }
switch (systemColorDepth) { switch (systemColorDepth) {
case 8:
#ifdef __LIBRETRO__
gbSgbDraw8Bit(dest8b + yyy * 256 + xxx, cc);
#else
gbSgbDraw8Bit(dest8b + yyy * (256 + 2) + xxx, cc);
#endif
case 16: case 16:
#ifdef __LIBRETRO__ #ifdef __LIBRETRO__
gbSgbDraw16Bit(dest + yyy * 256 + xxx, cc); gbSgbDraw16Bit(dest + yyy * 256 + xxx, cc);

View File

@ -3958,6 +3958,38 @@ void CPULoop(int ticks)
if (frameCount >= framesToSkip) { if (frameCount >= framesToSkip) {
(*renderLine)(); (*renderLine)();
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
#ifdef __LIBRETRO__
uint8_t* dest = (uint8_t*)g_pix + 240 * VCOUNT;
#else
uint8_t* dest = (uint8_t*)g_pix + 242 * (VCOUNT + 1);
#endif
for (int x = 0; x < 240;) {
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
}
// for filters that read past the screen
#ifndef __LIBRETRO__
*dest++ = 0;
#endif
} break;
case 16: { case 16: {
#ifdef __LIBRETRO__ #ifdef __LIBRETRO__
uint16_t* dest = (uint16_t*)g_pix + 240 * VCOUNT; uint16_t* dest = (uint16_t*)g_pix + 240 * VCOUNT;

View File

@ -9,6 +9,10 @@
#include "core/gba/gbaInline.h" #include "core/gba/gbaInline.h"
#include "core/gba/gbaGlobals.h" #include "core/gba/gbaGlobals.h"
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
/** /**
* Gameshark code types: (based on AR v1.0) * Gameshark code types: (based on AR v1.0)
* *
@ -2615,15 +2619,15 @@ void cheatsReadGame(gzFile file, int version)
if (!cheatsList[i].codestring[0]) { if (!cheatsList[i].codestring[0]) {
switch (cheatsList[i].size) { switch (cheatsList[i].size) {
case 0: case 0:
sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%02x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
case 1: case 1:
sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%04x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
case 2: case 2:
sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%08x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
} }
@ -2759,15 +2763,15 @@ bool cheatsLoadCheatList(const char* file)
if (!cheatsList[i].codestring[0]) { if (!cheatsList[i].codestring[0]) {
switch (cheatsList[i].size) { switch (cheatsList[i].size) {
case 0: case 0:
sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%02x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
case 1: case 1:
sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%04x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
case 2: case 2:
sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, snprintf(cheatsList[i].codestring, sizeof(cheatsList[i].codestring), "%08x:%08x", cheatsList[i].address,
cheatsList[i].value); cheatsList[i].value);
break; break;
} }

View File

@ -38,8 +38,12 @@
#include "core/gba/internal/gbaSockClient.h" #include "core/gba/internal/gbaSockClient.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#else
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
#endif
#ifdef UPDATE_REG #ifdef UPDATE_REG
#undef UPDATE_REG #undef UPDATE_REG
@ -58,9 +62,9 @@ const char* MakeInstanceFilename(const char* Input)
free(result); free(result);
} }
result = (char*)malloc(strlen(Input) + 3); result = (char*)malloc(strlen(Input) + 4);
char* p = strrchr((char*)Input, '.'); char* p = strrchr((char*)Input, '.');
sprintf(result, "%.*s-%d.%s", (int)(p - Input), Input, vbaid + 1, p + 1); snprintf(result, strlen(Input) + 3, "%.*s-%d.%s", (int)(p - Input), Input, vbaid + 1, p + 1);
return result; return result;
} }
@ -852,7 +856,7 @@ void CableServer::Recv(void)
} }
if (inbuffer[1] == -32) { if (inbuffer[1] == -32) {
char message[30]; char message[30];
sprintf(message, _("Player %d disconnected."), i + 2); snprintf(message, sizeof(message), _("Player %d disconnected."), i + 2);
systemScreenMessage(message); systemScreenMessage(message);
outbuffer[0] = 4; outbuffer[0] = 4;
outbuffer[1] = -32; outbuffer[1] = -32;
@ -916,7 +920,7 @@ bool CableServer::RecvGB(void)
if (inbuffer[1] == -32) { if (inbuffer[1] == -32) {
char message[30]; char message[30];
sprintf(message, _("Player %d disconnected."), i + 2); snprintf(message, sizeof(message), _("Player %d disconnected."), i + 2);
systemScreenMessage(message); systemScreenMessage(message);
for (i = 1; i < lanlink.numslaves; i++) { for (i = 1; i < lanlink.numslaves; i++) {
tcpsocket[i].disconnect(); tcpsocket[i].disconnect();
@ -1570,7 +1574,7 @@ void RFUServer::Recv(void)
sf::Socket::Status status = tcpsocket[i + 1].receive(packet); sf::Socket::Status status = tcpsocket[i + 1].receive(packet);
if (status == sf::Socket::Status::Disconnected) { if (status == sf::Socket::Status::Disconnected) {
char message[30]; char message[30];
sprintf(message, _("Player %d disconnected."), i + 1); snprintf(message, sizeof(message), _("Player %d disconnected."), i + 1);
systemScreenMessage(message); systemScreenMessage(message);
//tcpsocket[i + 1].disconnect(); //tcpsocket[i + 1].disconnect();
//CloseLink(); //CloseLink();
@ -2902,7 +2906,7 @@ static void UpdateCableIPC(int)
if (f < (1 << transfer_direction) - 1) if (f < (1 << transfer_direction) - 1)
linkmem->numgbas = transfer_direction - 1; linkmem->numgbas = transfer_direction - 1;
char message[30]; char message[30];
sprintf(message, _("Player %d disconnected."), transfer_direction - 1); snprintf(message, sizeof(message), _("Player %d disconnected."), transfer_direction - 1);
systemScreenMessage(message); systemScreenMessage(message);
} }
transfer_direction = linkmem->trgbas + 1; transfer_direction = linkmem->trgbas + 1;

File diff suppressed because it is too large Load Diff

View File

@ -79,6 +79,7 @@ void systemGbBorderOn() {}
void (*dbgOutput)(const char* s, uint32_t addr); void (*dbgOutput)(const char* s, uint32_t addr);
void (*dbgSignal)(int sig, int number); void (*dbgSignal)(int sig, int number);
uint8_t systemColorMap8[0x10000];
uint16_t systemColorMap16[0x10000]; uint16_t systemColorMap16[0x10000];
uint32_t systemColorMap32[0x10000]; uint32_t systemColorMap32[0x10000];
uint16_t systemGbPalette[24]; uint16_t systemGbPalette[24];

View File

@ -66,7 +66,7 @@ endif
ifneq (,$(findstring unix,$(platform))) ifneq (,$(findstring unix,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC fpic := -fPIC
SHARED := -shared -Wl,-version-script=$(LIBRETRO_DIR)/link.T -Wl,-no-undefined SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
TILED_RENDERING=1 TILED_RENDERING=1
# Classic Platforms #################### # Classic Platforms ####################
@ -222,7 +222,7 @@ else ifeq ($(platform), theos_ios)
else ifeq ($(platform), qnx) else ifeq ($(platform), qnx)
TARGET := $(TARGET_NAME)_libretro_$(platform).so TARGET := $(TARGET_NAME)_libretro_$(platform).so
fpic := -fPIC fpic := -fPIC
SHARED := -lcpp -lm -shared -Wl,-version-script=$(LIBRETRO_DIR)/link.T -Wl,-no-undefined SHARED := -lcpp -lm -shared -Wl,-no-undefined
CC = qcc -Vgcc_ntoarmv7le CC = qcc -Vgcc_ntoarmv7le
CXX = QCC -Vgcc_ntoarmv7le_cpp CXX = QCC -Vgcc_ntoarmv7le_cpp
AR = QCC -Vgcc_ntoarmv7le AR = QCC -Vgcc_ntoarmv7le
@ -344,7 +344,7 @@ else ifeq ($(platform), switch)
else ifneq (,$(findstring armv,$(platform))) else ifneq (,$(findstring armv,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so TARGET := $(TARGET_NAME)_libretro.so
SHARED := -shared -Wl,--no-undefined SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
TILED_RENDERING=1 TILED_RENDERING=1
fpic := -fPIC fpic := -fPIC
ifneq (,$(findstring cortexa8,$(platform))) ifneq (,$(findstring cortexa8,$(platform)))
@ -533,7 +533,7 @@ else
TARGET := $(TARGET_NAME)_libretro.dll TARGET := $(TARGET_NAME)_libretro.dll
CC ?= gcc CC ?= gcc
CXX ?= g++ CXX ?= g++
SHARED := -shared -static-libgcc -static-libstdc++ -Wl,-no-undefined -Wl,-version-script=$(LIBRETRO_DIR)/link.T SHARED := -shared -static-libgcc -static-libstdc++ -Wl,-no-undefined
TILED_RENDERING=1 TILED_RENDERING=1
endif endif

View File

@ -27,6 +27,11 @@
#include "core/gba/gbaRtc.h" #include "core/gba/gbaRtc.h"
#include "core/gba/gbaSound.h" #include "core/gba/gbaSound.h"
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#define vsnprintf vsprintf_s
#endif
#define FRAMERATE (16777216.0 / 280896.0) // 59.73 #define FRAMERATE (16777216.0 / 280896.0) // 59.73
#define SAMPLERATE 32768.0 #define SAMPLERATE 32768.0
@ -68,6 +73,7 @@ static IMAGE_TYPE type = IMAGE_UNKNOWN;
static bool libretro_supports_bitmasks = false; static bool libretro_supports_bitmasks = false;
// global vars // global vars
uint8_t systemColorMap8[0x10000];
uint16_t systemColorMap16[0x10000]; uint16_t systemColorMap16[0x10000];
uint32_t systemColorMap32[0x10000]; uint32_t systemColorMap32[0x10000];
int RGB_LOW_BITS_MASK = 0x821; // used for 16bit inter-frame filters int RGB_LOW_BITS_MASK = 0x821; // used for 16bit inter-frame filters
@ -1526,7 +1532,7 @@ void retro_cheat_set(unsigned index, bool enabled, const char* code)
int i = 0; int i = 0;
codeLine = (char *)calloc(codeLineSize, sizeof(char)); codeLine = (char *)calloc(codeLineSize, sizeof(char));
sprintf(name, "cheat_%d", index); snprintf(name, sizeof(name), "cheat_%d", index);
for (cursor = 0;; cursor++) { for (cursor = 0;; cursor++) {
if (ISHEXDEC) { if (ISHEXDEC) {
codeLine[codePos++] = toupper(code[cursor]); codeLine[codePos++] = toupper(code[cursor]);
@ -1791,7 +1797,7 @@ void systemMessage(const char* fmt, ...)
char buffer[256]; char buffer[256];
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vsprintf(buffer, fmt, ap); vsnprintf(buffer, sizeof(buffer), fmt, ap);
if (log_cb) if (log_cb)
log_cb(RETRO_LOG_INFO, "%s\n", buffer); log_cb(RETRO_LOG_INFO, "%s\n", buffer);
va_end(ap); va_end(ap);
@ -1802,7 +1808,7 @@ void systemMessage(int, const char* fmt, ...)
char buffer[256]; char buffer[256];
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vsprintf(buffer, fmt, ap); vsnprintf(buffer, sizeof(buffer), fmt, ap);
if (log_cb) if (log_cb)
log_cb(RETRO_LOG_INFO, "%s\n", buffer); log_cb(RETRO_LOG_INFO, "%s\n", buffer);
va_end(ap); va_end(ap);

5
src/libretro/link.T Normal file
View File

@ -0,0 +1,5 @@
{
global: retro_*;
local: *;
};

View File

@ -40,9 +40,15 @@ if(ENABLE_LIRC)
set(LIRC_CLIENT_LIBRARY lirc_client) set(LIRC_CLIENT_LIBRARY lirc_client)
endif() endif()
target_include_directories(vbam if(ENABLE_SDL3)
PRIVATE ${SDL2_INCLUDE_DIRS} target_include_directories(vbam
) PRIVATE ${SDL3_INCLUDE_DIRS}
)
else()
target_include_directories(vbam
PRIVATE ${SDL2_INCLUDE_DIRS}
)
endif()
target_link_libraries(vbam target_link_libraries(vbam
vbam-core vbam-core
@ -52,12 +58,16 @@ target_link_libraries(vbam
vbam-components-filters-interframe vbam-components-filters-interframe
vbam-components-user-config vbam-components-user-config
${OPENGL_LIBRARIES} ${OPENGL_LIBRARIES}
${VBAM_SDL2_LIBS} ${VBAM_SDL_LIBS}
nonstd-lib nonstd-lib
) )
if(WIN32) if(WIN32)
target_link_libraries(vbam ${SDL2_LIBRARY} ${SDL2MAIN_LIBRARY}) if(ENABLE_SDL3)
target_link_libraries(vbam ${SDL3_LIBRARY})
else()
target_link_libraries(vbam ${SDL2_LIBRARY} ${SDL2MAIN_LIBRARY})
endif()
endif() endif()
if(ENABLE_LIRC) if(ENABLE_LIRC)
@ -66,7 +76,7 @@ if(ENABLE_LIRC)
endif() endif()
if(WIN32) if(WIN32)
target_link_libraries(vbam wsock32 ws2_32 winmm version imm32 ${SDL2MAIN_LIBRARY}) target_link_libraries(vbam wsock32 ws2_32 winmm version imm32)
endif() endif()
# Installation scripts. # Installation scripts.

View File

@ -16,6 +16,10 @@
#include <direct.h> #include <direct.h>
#include <io.h> #include <io.h>
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
#define getcwd _getcwd #define getcwd _getcwd
#define stat _stat #define stat _stat
#define mkdir(X,Y) (_mkdir(X)) #define mkdir(X,Y) (_mkdir(X))
@ -138,6 +142,8 @@ int rewindTimer = 0;
int showSpeed; int showSpeed;
int showSpeedTransparent; int showSpeedTransparent;
int userColorDepth = 0;
const char* preparedCheatCodes[MAX_CHEATS]; const char* preparedCheatCodes[MAX_CHEATS];
// allow up to 100 IPS/UPS/PPF patches given on commandline // allow up to 100 IPS/UPS/PPF patches given on commandline
@ -168,6 +174,7 @@ struct option argOptions[] = {
{ "capture-format", required_argument, 0, OPT_CAPTURE_FORMAT }, { "capture-format", required_argument, 0, OPT_CAPTURE_FORMAT },
{ "cheat", required_argument, 0, OPT_CHEAT }, { "cheat", required_argument, 0, OPT_CHEAT },
{ "cheats-enabled", no_argument, &coreOptions.cheatsEnabled, 1 }, { "cheats-enabled", no_argument, &coreOptions.cheatsEnabled, 1 },
{ "color-depth", required_argument, 0, 'z'},
{ "color-option", no_argument, 0, OPT_GB_COLOR_OPTION }, { "color-option", no_argument, 0, OPT_GB_COLOR_OPTION },
{ "config", required_argument, 0, 'c' }, { "config", required_argument, 0, 'c' },
{ "cpu-disable-sfx", no_argument, &coreOptions.cpuDisableSfx, 1 }, { "cpu-disable-sfx", no_argument, &coreOptions.cpuDisableSfx, 1 },
@ -457,7 +464,7 @@ const char* FindConfigFile(const char *name)
mkdir(fullDir, 0755); mkdir(fullDir, 0755);
if (fullDir) { if (fullDir) {
sprintf(path, "%s%c%s", fullDir, kFileSep, name); snprintf(path, sizeof(path), "%s%c%s", fullDir, kFileSep, name);
if (FileExists(path)) if (FileExists(path))
{ {
return path; return path;
@ -467,7 +474,7 @@ const char* FindConfigFile(const char *name)
#ifdef _WIN32 #ifdef _WIN32
char *home = getenv("USERPROFILE"); char *home = getenv("USERPROFILE");
if (home != NULL) { if (home != NULL) {
sprintf(path, "%s%c%s", home, kFileSep, name); snprintf(path, "%s%c%s", home, kFileSep, name);
if (FileExists(path)) if (FileExists(path))
{ {
return path; return path;
@ -484,10 +491,10 @@ const char* FindConfigFile(const char *name)
char *tok = strtok(buffer, PATH_SEP); char *tok = strtok(buffer, PATH_SEP);
while (tok) { while (tok) {
sprintf(env_path, "%s%c%s", tok, kFileSep, EXE_NAME); snprintf(env_path, 4096, "%s%c%s", tok, kFileSep, EXE_NAME);
if (FileExists(env_path)) { if (FileExists(env_path)) {
static char path2[2048]; static char path2[2048];
sprintf(path2, "%s%c%s", tok, kFileSep, name); snprintf(path2, sizeof(path2), "%s%c%s", tok, kFileSep, name);
if (FileExists(path2)) { if (FileExists(path2)) {
return path2; return path2;
} }
@ -502,7 +509,7 @@ const char* FindConfigFile(const char *name)
char *p = strrchr(buffer, kFileSep); char *p = strrchr(buffer, kFileSep);
if (p) { if (p) {
*p = 0; *p = 0;
sprintf(path, "%s%c%s", buffer, kFileSep, name); snprintf(path, sizeof(path), "%s%c%s", buffer, kFileSep, name);
if (FileExists(path)) if (FileExists(path))
{ {
return path; return path;
@ -510,13 +517,13 @@ const char* FindConfigFile(const char *name)
} }
} }
#else // ! _WIN32 #else // ! _WIN32
sprintf(path, "%s%c%s", PKGDATADIR, kFileSep, name); snprintf(path, sizeof(path), "%s%c%s", PKGDATADIR, kFileSep, name);
if (FileExists(path)) if (FileExists(path))
{ {
return path; return path;
} }
sprintf(path, "%s%c%s", SYSCONF_INSTALL_DIR, kFileSep, name); snprintf(path, sizeof(path), "%s%c%s", SYSCONF_INSTALL_DIR, kFileSep, name);
if (FileExists(path)) if (FileExists(path))
{ {
return path; return path;
@ -745,6 +752,20 @@ int ReadOpts(int argc, char ** argv)
case 'F': case 'F':
fullScreen = 1; fullScreen = 1;
break; break;
case 'z':
if (optarg != NULL) {
userColorDepth = atoi(optarg);
if ((userColorDepth != 8) && (userColorDepth != 16) && (userColorDepth != 24) && (userColorDepth != 32)) {
fprintf(stderr, "Wrong color depth (%d bit)\n", userColorDepth);
userColorDepth = 0;
} else {
log("Set color depth to %d bit\n", userColorDepth);
}
} else {
userColorDepth = 0;
}
break;
case 'f': case 'f':
if (optarg) { if (optarg) {
filter = (Filter)atoi(optarg); filter = (Filter)atoi(optarg);

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,9 @@
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#ifndef ENABLE_SDL3
#include <SDL_events.h> #include <SDL_events.h>
#endif
#include "core/gba/gbaGlobals.h" #include "core/gba/gbaGlobals.h"
#include "core/gba/gbaSound.h" #include "core/gba/gbaSound.h"
@ -37,9 +39,23 @@ SoundSDL::SoundSDL():
initialized(false) initialized(false)
{} {}
#ifndef ENABLE_SDL3
void SoundSDL::soundCallback(void* data, uint8_t* stream, int len) { void SoundSDL::soundCallback(void* data, uint8_t* stream, int len) {
reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<uint16_t*>(stream), len); reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<uint16_t*>(stream), len);
} }
#else
void SoundSDL::soundCallback(void* data, SDL_AudioStream *stream, int additional_length, int length) {
uint16_t streamdata[8192];
(void)additional_length;
while (length > 0)
{
reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<uint16_t*>(streamdata), length > sizeof(streamdata) ? sizeof(streamdata) : length);
SDL_PutAudioStreamData(stream, streamdata, length > sizeof(streamdata) ? sizeof(streamdata) : length);
length -= sizeof(streamdata);
}
}
#endif
bool SoundSDL::should_wait() { bool SoundSDL::should_wait() {
return emulating && !coreOptions.speedup && current_rate && !gba_joybus_active; return emulating && !coreOptions.speedup && current_rate && !gba_joybus_active;
@ -65,7 +81,11 @@ void SoundSDL::read(uint16_t* stream, int length) {
if (!buffer_size()) { if (!buffer_size()) {
if (should_wait()) if (should_wait())
#ifndef ENABLE_SDL3
SDL_SemWait(data_available); SDL_SemWait(data_available);
#else
SDL_WaitSemaphore(data_available);
#endif
else else
return; return;
} }
@ -76,7 +96,11 @@ void SoundSDL::read(uint16_t* stream, int length) {
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
#ifndef ENABLE_SDL3
SDL_SemPost(data_read); SDL_SemPost(data_read);
#else
SDL_SignalSemaphore(data_read);
#endif
} }
void SoundSDL::write(uint16_t * finalWave, int length) { void SoundSDL::write(uint16_t * finalWave, int length) {
@ -85,8 +109,16 @@ void SoundSDL::write(uint16_t * finalWave, int length) {
SDL_LockMutex(mutex); SDL_LockMutex(mutex);
#ifndef ENABLE_SDL3
if (SDL_GetAudioDeviceStatus(sound_device) != SDL_AUDIO_PLAYING) if (SDL_GetAudioDeviceStatus(sound_device) != SDL_AUDIO_PLAYING)
SDL_PauseAudioDevice(sound_device, 0); SDL_PauseAudioDevice(sound_device, 0);
#else
if (SDL_AudioDevicePaused(sound_device) == true)
{
SDL_ResumeAudioStreamDevice(sound_stream);
SDL_ResumeAudioDevice(sound_device);
}
#endif
std::size_t samples = length / 4; std::size_t samples = length / 4;
std::size_t avail; std::size_t avail;
@ -99,10 +131,18 @@ void SoundSDL::write(uint16_t * finalWave, int length) {
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
#ifndef ENABLE_SDL3
SDL_SemPost(data_available); SDL_SemPost(data_available);
#else
SDL_SignalSemaphore(data_available);
#endif
if (should_wait()) if (should_wait())
SDL_SemWait(data_read); #ifndef ENABLE_SDL3
SDL_SemWait(data_read);
#else
SDL_WaitSemaphore(data_read);
#endif
else else
// Drop the remainder of the audio data // Drop the remainder of the audio data
return; return;
@ -125,15 +165,50 @@ bool SoundSDL::init(long sampleRate) {
// for "no throttle" use regular rate, audio is just dropped // for "no throttle" use regular rate, audio is just dropped
audio.freq = current_rate ? static_cast<int>(sampleRate * (current_rate / 100.0)) : sampleRate; audio.freq = current_rate ? static_cast<int>(sampleRate * (current_rate / 100.0)) : sampleRate;
#ifndef ENABLE_SDL3
audio.format = AUDIO_S16SYS; audio.format = AUDIO_S16SYS;
#else
audio.format = SDL_AUDIO_S16;
#endif
audio.channels = 2; audio.channels = 2;
#ifndef ENABLE_SDL3
audio.samples = 2048; audio.samples = 2048;
audio.callback = soundCallback; audio.callback = soundCallback;
audio.userdata = this; audio.userdata = this;
if (!SDL_WasInit(SDL_INIT_AUDIO)) SDL_Init(SDL_INIT_AUDIO); if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
#else
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == false)
#endif
{
std::cerr << "Failed to init audio subsystem: " << SDL_GetError() << std::endl;
return false;
}
#ifndef ENABLE_SDL3
if (SDL_WasInit(SDL_INIT_AUDIO) < 0)
#else
if (SDL_WasInit(SDL_INIT_AUDIO) == false)
#endif
{
SDL_Init(SDL_INIT_AUDIO);
}
#ifndef ENABLE_SDL3
sound_device = SDL_OpenAudioDevice(NULL, 0, &audio, NULL, 0); sound_device = SDL_OpenAudioDevice(NULL, 0, &audio, NULL, 0);
#else
sound_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio, soundCallback, this);
if(sound_stream == NULL)
{
std::cerr << "Failed to open audio stream: " << SDL_GetError() << std::endl;
return false;
}
sound_device = SDL_GetAudioStreamDevice(sound_stream);
#endif
if(sound_device == 0) { if(sound_device == 0) {
std::cerr << "Failed to open audio: " << SDL_GetError() << std::endl; std::cerr << "Failed to open audio: " << SDL_GetError() << std::endl;
@ -147,7 +222,10 @@ bool SoundSDL::init(long sampleRate) {
data_read = SDL_CreateSemaphore(1); data_read = SDL_CreateSemaphore(1);
// turn off audio events because we are not processing them // turn off audio events because we are not processing them
#if SDL_VERSION_ATLEAST(2, 0, 4) #if SDL_VERSION_ATLEAST(3, 2, 0)
SDL_SetEventEnabled(SDL_EVENT_AUDIO_DEVICE_ADDED, false);
SDL_SetEventEnabled(SDL_EVENT_AUDIO_DEVICE_REMOVED, false);
#elif SDL_VERSION_ATLEAST(2, 0, 4)
SDL_EventState(SDL_AUDIODEVICEADDED, SDL_IGNORE); SDL_EventState(SDL_AUDIODEVICEADDED, SDL_IGNORE);
SDL_EventState(SDL_AUDIODEVICEREMOVED, SDL_IGNORE); SDL_EventState(SDL_AUDIODEVICEREMOVED, SDL_IGNORE);
#endif #endif
@ -164,8 +242,13 @@ void SoundSDL::deinit() {
SDL_LockMutex(mutex); SDL_LockMutex(mutex);
int is_emulating = emulating; int is_emulating = emulating;
emulating = 0; emulating = 0;
#ifndef ENABLE_SDL3
SDL_SemPost(data_available); SDL_SemPost(data_available);
SDL_SemPost(data_read); SDL_SemPost(data_read);
#else
SDL_SignalSemaphore(data_available);
SDL_SignalSemaphore(data_read);
#endif
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
SDL_Delay(100); SDL_Delay(100);

View File

@ -18,7 +18,11 @@
#ifndef VBAM_SDL_AUDIO_SDL_H_ #ifndef VBAM_SDL_AUDIO_SDL_H_
#define VBAM_SDL_AUDIO_SDL_H_ #define VBAM_SDL_AUDIO_SDL_H_
#ifndef ENABLE_SDL3
#include <SDL.h> #include <SDL.h>
#else
#include <SDL3/SDL.h>
#endif
#include "core/base/ringbuffer.h" #include "core/base/ringbuffer.h"
#include "core/base/sound_driver.h" #include "core/base/sound_driver.h"
@ -29,11 +33,16 @@ public:
~SoundSDL() override; ~SoundSDL() override;
private: private:
static void soundCallback(void* data, uint8_t* stream, int length); #ifdef ENABLE_SDL3
void read(uint16_t* stream, int length); static void soundCallback(void* data, SDL_AudioStream *stream, int additional_length, int length);
#else
static void soundCallback(void* data, uint8_t* stream, int len);
#endif
bool should_wait(); bool should_wait();
std::size_t buffer_size(); std::size_t buffer_size();
void deinit(); void deinit();
void read(uint16_t* stream, int length);
// SoundDriver implementation. // SoundDriver implementation.
bool init(long sampleRate) override; bool init(long sampleRate) override;
@ -47,9 +56,17 @@ private:
SDL_AudioDeviceID sound_device = 0; SDL_AudioDeviceID sound_device = 0;
#ifdef ENABLE_SDL3
SDL_AudioStream *sound_stream = NULL;
SDL_Mutex* mutex;
SDL_Semaphore* data_available;
SDL_Semaphore* data_read;
#else
SDL_mutex* mutex; SDL_mutex* mutex;
SDL_sem* data_available; SDL_semaphore* data_available;
SDL_sem* data_read; SDL_semaphore* data_read;
#endif
SDL_AudioSpec audio_spec; SDL_AudioSpec audio_spec;
unsigned short current_rate; unsigned short current_rate;

View File

@ -30,6 +30,10 @@
#include "core/gba/gbaSound.h" #include "core/gba/gbaSound.h"
#include "sdl/exprNode.h" #include "sdl/exprNode.h"
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
extern bool debugger; extern bool debugger;
extern int emulating; extern int emulating;
extern void sdlWriteState(int num); extern void sdlWriteState(int num);
@ -377,11 +381,11 @@ static const char* debuggerPrintType(Type* t)
strcpy(buffer, debuggerPrintType(t->pointer)); strcpy(buffer, debuggerPrintType(t->pointer));
else else
strcpy(buffer, "void"); strcpy(buffer, "void");
sprintf(buffer2, "%s *", buffer); snprintf(buffer2, sizeof(buffer2), "%s *", buffer);
return buffer2; return buffer2;
} else if (t->type == TYPE_reference) { } else if (t->type == TYPE_reference) {
strcpy(buffer, debuggerPrintType(t->pointer)); strcpy(buffer, debuggerPrintType(t->pointer));
sprintf(buffer2, "%s &", buffer); snprintf(buffer2, sizeof(buffer2), "%s &", buffer);
return buffer2; return buffer2;
} }
return t->name; return t->name;
@ -1364,7 +1368,7 @@ static void debuggerDisassembleArm(FILE* f, uint32_t pc, int count)
if (l > len) if (l > len)
len = l; len = l;
} }
sprintf(format, "%%08x %%-%ds %%s\n", len); snprintf(format, sizeof(format), "%%08x %%-%ds %%s\n", len);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
uint32_t addr = pc; uint32_t addr = pc;
pc += disArm(pc, buffer, 4096, 2); pc += disArm(pc, buffer, 4096, 2);
@ -1383,7 +1387,7 @@ static void debuggerDisassembleThumb(FILE* f, uint32_t pc, int count)
if (l > len) if (l > len)
len = l; len = l;
} }
sprintf(format, "%%08x %%-%ds %%s\n", len); snprintf(format, sizeof(format), "%%08x %%-%ds %%s\n", len);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
uint32_t addr = pc; uint32_t addr = pc;
@ -1781,7 +1785,7 @@ static void debuggerRegisters(int, char**)
((!(reg[16].I & 0x40)) ? '.' : 'F'), ((!(reg[16].I & 0x40)) ? '.' : 'F'),
(armState ? '.' : 'T'), (armState ? '.' : 'T'),
armMode); armMode);
sprintf(buffer, "%08x", armState ? reg[15].I - 4 : reg[15].I - 2); snprintf(buffer, sizeof(buffer), "%08x", armState ? reg[15].I - 4 : reg[15].I - 2);
command[1] = buffer; command[1] = buffer;
debuggerDisassemble(3, command); debuggerDisassemble(3, command);
} }

View File

@ -19,6 +19,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
/** Maximum value size for integers and doubles. */ /** Maximum value size for integers and doubles. */
#define MAXVALSZ 1024 #define MAXVALSZ 1024
@ -372,12 +376,12 @@ int main(int argc, char *argv[])
/* Set values in dictionary */ /* Set values in dictionary */
printf("setting %d values...\n", NVALS); printf("setting %d values...\n", NVALS);
for (i = 0; i < NVALS; i++) { for (i = 0; i < NVALS; i++) {
sprintf(cval, "%04d", i); snprintf(cval, sizeof(cval), "%04d", i);
dictionary_set(d, cval, "salut"); dictionary_set(d, cval, "salut");
} }
printf("getting %d values...\n", NVALS); printf("getting %d values...\n", NVALS);
for (i = 0; i < NVALS; i++) { for (i = 0; i < NVALS; i++) {
sprintf(cval, "%04d", i); snprintf(cval, sizeof(cval), "%04d", i);
val = dictionary_get(d, cval, DICT_INVALID_KEY); val = dictionary_get(d, cval, DICT_INVALID_KEY);
if (val == DICT_INVALID_KEY) { if (val == DICT_INVALID_KEY) {
printf("cannot get value for key [%s]\n", cval); printf("cannot get value for key [%s]\n", cval);
@ -385,7 +389,7 @@ int main(int argc, char *argv[])
} }
printf("unsetting %d values...\n", NVALS); printf("unsetting %d values...\n", NVALS);
for (i = 0; i < NVALS; i++) { for (i = 0; i < NVALS; i++) {
sprintf(cval, "%04d", i); snprintf(cval, sizeof(cval), "%04d", i);
dictionary_unset(d, cval); dictionary_unset(d, cval);
} }
if (d->n != 0) { if (d->n != 0) {

View File

@ -307,6 +307,9 @@ void sdlStretchx4(uint8_t* src, uint8_t* dest, int width) {
} }
} }
void (*sdlStretcher8[4])(uint8_t*, uint8_t*, int) = {
sdlStretchx1<uint8_t>, sdlStretchx2<uint8_t>, sdlStretchx3<uint8_t>, sdlStretchx4<uint8_t>};
void (*sdlStretcher16[4])(uint8_t*, uint8_t*, int) = { void (*sdlStretcher16[4])(uint8_t*, uint8_t*, int) = {
sdlStretchx1<uint16_t>, sdlStretchx2<uint16_t>, sdlStretchx3<uint16_t>, sdlStretchx4<uint16_t>}; sdlStretchx1<uint16_t>, sdlStretchx2<uint16_t>, sdlStretchx3<uint16_t>, sdlStretchx4<uint16_t>};
@ -391,6 +394,9 @@ bool sdlStretchInit(int colorDepth, int sizeMultiplier, int srcWidth) {
sdlMakeStretcher(srcWidth, sizeMultiplier); sdlMakeStretcher(srcWidth, sizeMultiplier);
#else #else
switch (colorDepth) { switch (colorDepth) {
case 8:
sdlStretcher = sdlStretcher8[sizeMultiplier];
break;
case 16: case 16:
sdlStretcher = sdlStretcher16[sizeMultiplier]; sdlStretcher = sdlStretcher16[sizeMultiplier];
break; break;
@ -493,33 +499,34 @@ void sdlStretch4x(uint8_t* srcPtr,
struct FilterDesc { struct FilterDesc {
char name[30]; char name[30];
int enlargeFactor; int enlargeFactor;
FilterFunc func8;
FilterFunc func16; FilterFunc func16;
FilterFunc func24; FilterFunc func24;
FilterFunc func32; FilterFunc func32;
}; };
const FilterDesc Filters[] = {{"Stretch 1x", 1, sdlStretch1x, sdlStretch1x, sdlStretch1x}, const FilterDesc Filters[] = {{"Stretch 1x", 1, sdlStretch1x, sdlStretch1x, sdlStretch1x, sdlStretch1x },
{"Stretch 2x", 2, sdlStretch2x, sdlStretch2x, sdlStretch2x}, {"Stretch 2x", 2, sdlStretch2x, sdlStretch2x, sdlStretch2x, sdlStretch2x},
{"2xSaI", 2, _2xSaI, 0, _2xSaI32}, {"2xSaI", 2, 0, _2xSaI, 0, _2xSaI32},
{"Super 2xSaI", 2, Super2xSaI, 0, Super2xSaI32}, {"Super 2xSaI", 2, 0, Super2xSaI, 0, Super2xSaI32},
{"Super Eagle", 2, SuperEagle, 0, SuperEagle32}, {"Super Eagle", 2, 0, SuperEagle, 0, SuperEagle32},
{"Pixelate", 2, Pixelate, 0, Pixelate32}, {"Pixelate", 2, 0, Pixelate, 0, Pixelate32},
{"AdvanceMAME Scale2x", 2, AdMame2x, 0, AdMame2x32}, {"AdvanceMAME Scale2x", 2, 0, AdMame2x, 0, AdMame2x32},
{"Bilinear", 2, Bilinear, 0, Bilinear32}, {"Bilinear", 2, 0, Bilinear, 0, Bilinear32},
{"Bilinear Plus", 2, BilinearPlus, 0, BilinearPlus32}, {"Bilinear Plus", 2, 0, BilinearPlus, 0, BilinearPlus32},
{"Scanlines", 2, Scanlines, 0, Scanlines32}, {"Scanlines", 2, 0, Scanlines, 0, Scanlines32},
{"TV Mode", 2, ScanlinesTV, 0, ScanlinesTV32}, {"TV Mode", 2, 0, ScanlinesTV, 0, ScanlinesTV32},
{"lq2x", 2, lq2x, 0, lq2x32}, {"lq2x", 2, 0, lq2x, 0, lq2x32},
{"hq2x", 2, hq2x, 0, hq2x32}, {"hq2x", 2, 0, hq2x, 0, hq2x32},
{"xbrz2x", 2, 0, 0, xbrz2x32}, {"xbrz2x", 2, 0, 0, 0, xbrz2x32},
{"Stretch 3x", 3, sdlStretch3x, sdlStretch3x, sdlStretch3x}, {"Stretch 3x", 3, sdlStretch3x, sdlStretch3x, sdlStretch3x, sdlStretch3x},
{"hq3x", 3, hq3x16, 0, hq3x32_32}, {"hq3x", 3, 0, hq3x16, 0, hq3x32_32},
{"xbrz3x", 3, 0, 0, xbrz3x32}, {"xbrz3x", 3, 0, 0, 0, xbrz3x32},
{"Stretch 4x", 4, sdlStretch4x, sdlStretch4x, sdlStretch4x}, {"Stretch 4x", 4, sdlStretch4x, sdlStretch4x, sdlStretch4x, sdlStretch4x},
{"hq4x", 4, hq4x16, 0, hq4x32_32}, {"hq4x", 4, 0, hq4x16, 0, hq4x32_32},
{"xbrz4x", 4, 0, 0, xbrz4x32}, {"xbrz4x", 4, 0, 0, 0, xbrz4x32},
{"xbrz5x", 5, 0, 0, xbrz5x32}, {"xbrz5x", 5, 0, 0, 0, xbrz5x32},
{"xbrz6x", 6, 0, 0, xbrz6x32}}; {"xbrz6x", 6, 0, 0, 0, xbrz6x32}};
int getFilterEnlargeFactor(const int f) { int getFilterEnlargeFactor(const int f) {
return Filters[f].enlargeFactor; return Filters[f].enlargeFactor;
@ -533,6 +540,9 @@ FilterFunc initFilter(const int f, const int colorDepth, const int srcWidth) {
FilterFunc func; FilterFunc func;
switch (colorDepth) { switch (colorDepth) {
case 8:
func = Filters[f].func8;
break;
case 15: case 15:
case 16: case 16:
func = Filters[f].func16; func = Filters[f].func16;
@ -585,26 +595,33 @@ FilterFunc initFilter(const int f, const int colorDepth, const int srcWidth) {
struct IFBFilterDesc { struct IFBFilterDesc {
char name[30]; char name[30];
IFBFilterFunc func8;
IFBFilterFunc func16; IFBFilterFunc func16;
IFBFilterFunc func24;
IFBFilterFunc func32; IFBFilterFunc func32;
}; };
const IFBFilterDesc IFBFilters[] = {{"No interframe blending", 0, 0}, const IFBFilterDesc IFBFilters[] = {{"No interframe blending", 0, 0, 0},
{"Interframe motion blur", MotionBlurIB, MotionBlurIB32}, {"Interframe motion blur", MotionBlurIB8, MotionBlurIB, MotionBlurIB24, MotionBlurIB32},
{"Smart interframe blending", SmartIB, SmartIB32}}; {"Smart interframe blending", SmartIB8, SmartIB, SmartIB24, SmartIB32}};
IFBFilterFunc initIFBFilter(const int f, const int colorDepth) { IFBFilterFunc initIFBFilter(const int f, const int colorDepth) {
IFBFilterFunc func; IFBFilterFunc func;
switch (colorDepth) { switch (colorDepth) {
case 8:
func = IFBFilters[f].func8;
break;
case 15: case 15:
case 16: case 16:
func = IFBFilters[f].func16; func = IFBFilters[f].func16;
break; break;
case 24:
func = IFBFilters[f].func24;
break;
case 32: case 32:
func = IFBFilters[f].func32; func = IFBFilters[f].func32;
break; break;
case 24:
default: default:
func = 0; func = 0;
break; break;

View File

@ -11,6 +11,10 @@
#include <ctype.h> #include <ctype.h>
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
/*---------------------------- Defines -------------------------------------*/ /*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ (1024) #define ASCIILINESZ (1024)
#define INI_INVALID_KEY ((char *)-1) #define INI_INVALID_KEY ((char *)-1)
@ -269,7 +273,7 @@ void iniparser_dumpsection_ini(dictionary *d, char *s, FILE *f)
seclen = (int)strlen(s); seclen = (int)strlen(s);
// fprintf(f, "\n[%s]\n", s); // fprintf(f, "\n[%s]\n", s);
fprintf(f, "[%s]\n", s); fprintf(f, "[%s]\n", s);
sprintf(keym, "%s:", s); snprintf(keym, sizeof(keym), "%s:", s);
for (j = 0; j < d->size; j++) { for (j = 0; j < d->size; j++) {
if (d->key[j] == NULL) if (d->key[j] == NULL)
continue; continue;
@ -303,7 +307,7 @@ int iniparser_getsecnkeys(dictionary *d, char *s)
return nkeys; return nkeys;
seclen = (int)strlen(s); seclen = (int)strlen(s);
sprintf(keym, "%s:", s); snprintf(keym, sizeof(keym), "%s:", s);
for (j = 0; j < d->size; j++) { for (j = 0; j < d->size; j++) {
if (d->key[j] == NULL) if (d->key[j] == NULL)
@ -349,7 +353,7 @@ char **iniparser_getseckeys(dictionary *d, char *s)
keys = (char **)malloc(nkeys * sizeof(char *)); keys = (char **)malloc(nkeys * sizeof(char *));
seclen = (int)strlen(s); seclen = (int)strlen(s);
sprintf(keym, "%s:", s); snprintf(keym, sizeof(keym), "%s:", s);
i = 0; i = 0;
@ -710,9 +714,9 @@ dictionary *iniparser_load(const char *ininame)
case LINE_VALUE: case LINE_VALUE:
if (strlen(section)) if (strlen(section))
sprintf(tmp, "%s:%s", section, key); snprintf(tmp, sizeof(tmp), "%s:%s", section, key);
else else
sprintf(tmp, "preferences:%s", key); snprintf(tmp, sizeof(tmp), "preferences:%s", key);
errs = dictionary_set(dict, tmp, val); errs = dictionary_set(dict, tmp, val);
break; break;

View File

@ -19,6 +19,8 @@
#include "sdl/ConfigManager.h" #include "sdl/ConfigManager.h"
#include <cstdlib>
#define SDLBUTTONS_NUM 14 #define SDLBUTTONS_NUM 14
static void sdlUpdateKey(uint32_t key, bool down); static void sdlUpdateKey(uint32_t key, bool down);
@ -63,11 +65,23 @@ static uint32_t joypad[5][SDLBUTTONS_NUM] = {
{ {
SDLK_LEFT, SDLK_RIGHT, SDLK_LEFT, SDLK_RIGHT,
SDLK_UP, SDLK_DOWN, SDLK_UP, SDLK_DOWN,
#ifdef ENABLE_SDL3
SDLK_Z, SDLK_X,
#else
SDLK_z, SDLK_x, SDLK_z, SDLK_x,
#endif
SDLK_RETURN, SDLK_BACKSPACE, SDLK_RETURN, SDLK_BACKSPACE,
#ifdef ENABLE_SDL3
SDLK_A, SDLK_S,
#else
SDLK_a, SDLK_s, SDLK_a, SDLK_s,
#endif
SDLK_SPACE, SDLK_F12, SDLK_SPACE, SDLK_F12,
#ifdef ENABLE_SDL3
SDLK_Q, SDLK_W,
#else
SDLK_q, SDLK_w, SDLK_q, SDLK_w,
#endif
} }
}; };
@ -106,18 +120,37 @@ static uint32_t sdlGetAxisCode(const SDL_Event& event)
uint32_t inputGetEventCode(const SDL_Event& event) uint32_t inputGetEventCode(const SDL_Event& event)
{ {
switch (event.type) { switch (event.type) {
#ifdef ENABLE_SDL3
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
return event.key.key;
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
return event.key.keysym.sym; return event.key.keysym.sym;
#endif
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_JOYSTICK_HAT_MOTION:
#else
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
#endif
return sdlGetHatCode(event); return sdlGetHatCode(event);
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
#else
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
#endif
return sdlGetButtonCode(event); return sdlGetButtonCode(event);
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
#else
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
#endif
return sdlGetAxisCode(event); return sdlGetAxisCode(event);
break; break;
default: default:
@ -348,18 +381,30 @@ static bool sdlCheckJoyKey(int key)
// joystick button // joystick button
int button = what - 128; int button = what - 128;
#ifdef ENABLE_SDL3
if (button >= SDL_GetNumJoystickButtons(sdlDevices[dev]))
#else
if (button >= SDL_JoystickNumButtons(sdlDevices[dev])) if (button >= SDL_JoystickNumButtons(sdlDevices[dev]))
#endif
return false; return false;
} else if (what < 0x20) { } else if (what < 0x20) {
// joystick axis // joystick axis
what >>= 1; what >>= 1;
#ifdef ENABLE_SDL3
if (what >= SDL_GetNumJoystickAxes(sdlDevices[dev]))
#else
if (what >= SDL_JoystickNumAxes(sdlDevices[dev])) if (what >= SDL_JoystickNumAxes(sdlDevices[dev]))
#endif
return false; return false;
} else if (what < 0x30) { } else if (what < 0x30) {
// joystick hat // joystick hat
what = (what & 15); what = (what & 15);
what >>= 2; what >>= 2;
#ifdef ENABLE_SDL3
if (what >= SDL_GetNumJoystickHats(sdlDevices[dev]))
#else
if (what >= SDL_JoystickNumHats(sdlDevices[dev])) if (what >= SDL_JoystickNumHats(sdlDevices[dev]))
#endif
return false; return false;
} }
@ -369,17 +414,23 @@ static bool sdlCheckJoyKey(int key)
void inputInitJoysticks() void inputInitJoysticks()
{ {
#ifdef ENABLE_SDL3
SDL_JoystickID *joysticks = SDL_GetJoysticks(&sdlNumDevices);
#else
sdlNumDevices = SDL_NumJoysticks();
#endif
bool usesJoy = false;
// The main joypad has to be entirely defined // The main joypad has to be entirely defined
for (int i = 0; i < SDLBUTTONS_NUM; i++) { for (int i = 0; i < SDLBUTTONS_NUM; i++) {
if (!joypad[PAD_MAIN][i]) if (!joypad[PAD_MAIN][i])
joypad[PAD_MAIN][i] = joypad[PAD_DEFAULT][i]; joypad[PAD_MAIN][i] = joypad[PAD_DEFAULT][i];
} }
sdlNumDevices = SDL_NumJoysticks();
if (sdlNumDevices) if (sdlNumDevices)
{
sdlDevices = (SDL_Joystick**)calloc(1, sdlNumDevices * sizeof(SDL_Joystick**)); sdlDevices = (SDL_Joystick**)calloc(1, sdlNumDevices * sizeof(SDL_Joystick**));
bool usesJoy = false; }
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
for (int i = 0; i < SDLBUTTONS_NUM; i++) { for (int i = 0; i < SDLBUTTONS_NUM; i++) {
@ -391,12 +442,17 @@ void inputInitJoysticks()
if (sdlDevices) { if (sdlDevices) {
if (dev < sdlNumDevices) { if (dev < sdlNumDevices) {
if (sdlDevices[dev] == NULL) { if (sdlDevices[dev] == NULL) {
#ifndef ENABLE_SDL3
sdlDevices[dev] = SDL_JoystickOpen(dev); sdlDevices[dev] = SDL_JoystickOpen(dev);
#else
sdlDevices[dev] = SDL_OpenJoystick(joysticks[dev]);
#endif
} }
ok = sdlCheckJoyKey(joypad[j][i]); ok = sdlCheckJoyKey(joypad[j][i]);
} else } else {
ok = false; ok = false;
}
} }
if (!ok) if (!ok)
@ -416,7 +472,11 @@ void inputInitJoysticks()
if (sdlDevices) { if (sdlDevices) {
if (dev < sdlNumDevices) { if (dev < sdlNumDevices) {
if (sdlDevices[dev] == NULL) { if (sdlDevices[dev] == NULL) {
#ifndef ENABLE_SDL3
sdlDevices[dev] = SDL_JoystickOpen(dev); sdlDevices[dev] = SDL_JoystickOpen(dev);
#else
sdlDevices[dev] = SDL_OpenJoystick(joysticks[dev]);
#endif
} }
ok = sdlCheckJoyKey(motion[i]); ok = sdlCheckJoyKey(motion[i]);
@ -432,34 +492,68 @@ void inputInitJoysticks()
} }
if (usesJoy) if (usesJoy)
{
#ifdef ENABLE_SDL3
SDL_SetJoystickEventsEnabled(true);
#else
SDL_JoystickEventState(SDL_ENABLE); SDL_JoystickEventState(SDL_ENABLE);
#endif
}
} }
void inputProcessSDLEvent(const SDL_Event& event) void inputProcessSDLEvent(const SDL_Event& event)
{ {
// fprintf(stdout, "%x\n", inputGetEventCode(event)); // fprintf(stdout, "%x\n", inputGetEventCode(event));
switch (event.type) { switch (event.type) {
#ifdef ENABLE_SDL3
case SDL_EVENT_KEY_DOWN:
if (!event.key.mod)
sdlUpdateKey(event.key.key, true);
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
if (!event.key.keysym.mod) if (!event.key.keysym.mod)
sdlUpdateKey(event.key.keysym.sym, true); sdlUpdateKey(event.key.keysym.sym, true);
#endif
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_KEY_UP:
if (!event.key.mod)
sdlUpdateKey(event.key.key, false);
#else
case SDL_KEYUP: case SDL_KEYUP:
if (!event.key.keysym.mod) if (!event.key.keysym.mod)
sdlUpdateKey(event.key.keysym.sym, false); sdlUpdateKey(event.key.keysym.sym, false);
#endif
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_JOYSTICK_HAT_MOTION:
#else
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
#endif
sdlUpdateJoyHat(event.jhat.which, sdlUpdateJoyHat(event.jhat.which,
event.jhat.hat, event.jhat.hat,
event.jhat.value); event.jhat.value);
break; break;
case SDL_JOYBUTTONDOWN: #ifdef ENABLE_SDL3
case SDL_JOYBUTTONUP: case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
sdlUpdateJoyButton(event.jbutton.which, sdlUpdateJoyButton(event.jbutton.which,
event.jbutton.button, event.jbutton.button,
event.jbutton.state == SDL_PRESSED); event.jbutton.down == true);
#else
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
sdlUpdateJoyButton(event.jbutton.which,
event.jbutton.button,
event.jbutton.state == SDL_PRESSED);
#endif
break; break;
#ifdef ENABLE_SDL3
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
#else
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
#endif
sdlUpdateJoyAxis(event.jaxis.which, sdlUpdateJoyAxis(event.jaxis.which,
event.jaxis.axis, event.jaxis.axis,
event.jaxis.value); event.jaxis.value);

View File

@ -20,7 +20,11 @@
#include <cstdint> #include <cstdint>
#include <SDL_events.h> #ifndef ENABLE_SDL3
#include <SDL.h>
#else
#include <SDL3/SDL.h>
#endif
enum EKey { enum EKey {
KEY_LEFT, KEY_LEFT,

42
src/wx/AAPLShaderTypes.h Normal file
View File

@ -0,0 +1,42 @@
/*
See the LICENSE.txt file for this samples licensing information.
Abstract:
Header containing types and enum constants shared between Metal shaders and C/ObjC source
*/
#ifndef AAPLShaderTypes_h
#define AAPLShaderTypes_h
#include <simd/simd.h>
// Buffer index values shared between shader and C code to ensure Metal shader buffer inputs match
// Metal API buffer set calls
typedef enum AAPLVertexInputIndex
{
AAPLVertexInputIndexVertices = 0,
AAPLVertexInputIndexViewportSize = 1,
} AAPLVertexInputIndex;
// Texture index values shared between shader and C code to ensure Metal shader buffer inputs match
// Metal API texture set calls
typedef enum AAPLTextureIndex
{
AAPLTextureIndexBaseColor = 0,
} AAPLTextureIndex;
// This structure defines the layout of each vertex in the array of vertices set as an input to the
// Metal vertex shader. Since this header is shared between the .metal shader and C code,
// you can be sure that the layout of the vertex array in the code matches the layout that
// the vertex shader expects
typedef struct
{
// Positions in pixel space. A value of 100 indicates 100 pixels from the origin/center.
vector_float2 position;
// 2D texture coordinate
vector_float2 textureCoordinate;
} AAPLVertex;
#endif /* AAPLShaderTypes_h */

76
src/wx/AAPLShaders.metal Normal file
View File

@ -0,0 +1,76 @@
/*
See the LICENSE.txt file for this samples licensing information.
Abstract:
Metal shaders used for this sample
*/
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
// Include header shared between this Metal shader code and C code executing Metal API commands
#include "AAPLShaderTypes.h"
struct RasterizerData
{
// The [[position]] attribute qualifier of this member indicates this value is
// the clip space position of the vertex when this structure is returned from
// the vertex shader
float4 position [[position]];
// Since this member does not have a special attribute qualifier, the rasterizer
// will interpolate its value with values of other vertices making up the triangle
// and pass that interpolated value to the fragment shader for each fragment in
// that triangle.
float2 textureCoordinate;
};
// Vertex Function
vertex RasterizerData
vertexShader(uint vertexID [[ vertex_id ]],
constant AAPLVertex *vertexArray [[ buffer(AAPLVertexInputIndexVertices) ]],
constant vector_uint2 *viewportSizePointer [[ buffer(AAPLVertexInputIndexViewportSize) ]])
{
RasterizerData out;
// Index into the array of positions to get the current vertex.
// Positions are specified in pixel dimensions (i.e. a value of 100 is 100 pixels from
// the origin)
float2 pixelSpacePosition = vertexArray[vertexID].position.xy;
// Get the viewport size and cast to float.
float2 viewportSize = float2(*viewportSizePointer);
// To convert from positions in pixel space to positions in clip-space,
// divide the pixel coordinates by half the size of the viewport.
// Z is set to 0.0 and w to 1.0 because this is 2D sample.
out.position = vector_float4(0.0, 0.0, 0.0, 1.0);
out.position.xy = pixelSpacePosition / viewportSize;
// Pass the input textureCoordinate straight to the output RasterizerData. This value will be
// interpolated with the other textureCoordinate values in the vertices that make up the
// triangle.
out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
return out;
}
// Fragment function
fragment float4
samplingShader(RasterizerData in [[stage_in]],
texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])
{
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear);
// Sample the texture to obtain a color
const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);
// return the color of the texture
return float4(colorSample);
}

View File

@ -8,6 +8,8 @@ include(VbamFunctions)
set(VBAM_WX_COMMON set(VBAM_WX_COMMON
audio/audio.cpp audio/audio.cpp
audio/audio.h audio/audio.h
audio/internal/sdl.cpp
audio/internal/sdl.h
audio/internal/openal.cpp audio/internal/openal.cpp
audio/internal/openal.h audio/internal/openal.h
background-input.cpp background-input.cpp
@ -156,6 +158,11 @@ if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
find_package(nanosvg) find_package(nanosvg)
endif() endif()
if(APPLE)
find_library(METAL Metal)
find_library(METALKIT MetalKit)
endif()
set(ENABLE_OPENGL TRUE) set(ENABLE_OPENGL TRUE)
find_package(wxWidgets COMPONENTS xrc xml html adv net core base gl ${wx_find_extra}) find_package(wxWidgets COMPONENTS xrc xml html adv net core base gl ${wx_find_extra})
@ -254,6 +261,11 @@ function(configure_wx_target target)
_add_compile_definitions(${wxWidgets_DEFINITIONS_DEBUG}) _add_compile_definitions(${wxWidgets_DEFINITIONS_DEBUG})
endif() endif()
# No Metal
if(NOT CMAKE_Metal_COMPILER)
_add_compile_definitions(NO_METAL)
endif()
# OpenAL. # OpenAL.
if(OPENAL_STATIC) if(OPENAL_STATIC)
_add_compile_definitions(AL_LIBTYPE_STATIC) _add_compile_definitions(AL_LIBTYPE_STATIC)
@ -294,8 +306,8 @@ function(configure_wx_target target)
_add_compile_definitions(NO_D3D) _add_compile_definitions(NO_D3D)
endif() endif()
# SDL2. # SDL.
_add_link_libraries(${VBAM_SDL2_LIBS}) _add_link_libraries(${VBAM_SDL_LIBS})
# OpenGL. # OpenGL.
if(ENABLE_OPENGL) if(ENABLE_OPENGL)
@ -303,6 +315,15 @@ function(configure_wx_target target)
else() else()
_add_compile_definitions(NO_OGL) _add_compile_definitions(NO_OGL)
endif() endif()
# Metal
if(APPLE)
if(CMAKE_Metal_COMPILER)
_add_link_libraries($<LINK_LIBRARY:WEAK_FRAMEWORK,${METAL}>)
_add_link_libraries($<LINK_LIBRARY:WEAK_FRAMEWORK,${METALKIT}>)
endif()
endif()
endfunction() endfunction()
# Sub-projects. # Sub-projects.
@ -320,7 +341,12 @@ add_executable(
) )
target_sources(visualboyadvance-m PRIVATE ${VBAM_WX_COMMON} ${VBAM_ICON_PATH}) target_sources(visualboyadvance-m PRIVATE ${VBAM_WX_COMMON} ${VBAM_ICON_PATH})
target_include_directories(visualboyadvance-m PRIVATE ${SDL2_INCLUDE_DIRS})
if(ENABLE_SDL3)
target_include_directories(visualboyadvance-m PRIVATE ${SDL3_INCLUDE_DIRS})
else()
target_include_directories(visualboyadvance-m PRIVATE ${SDL2_INCLUDE_DIRS})
endif()
target_link_libraries( target_link_libraries(
visualboyadvance-m visualboyadvance-m
@ -1047,3 +1073,27 @@ install(
if (UNIX) if (UNIX)
install(FILES ${CMAKE_SOURCE_DIR}/src/debian/visualboyadvance-m.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6) install(FILES ${CMAKE_SOURCE_DIR}/src/debian/visualboyadvance-m.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
endif() endif()
if(APPLE)
if(CMAKE_Metal_COMPILER)
set(VBAM_SHADER default.metallib)
set(ShaderBase_HEADERS
AAPLShaderTypes.h
)
set(ShaderBase_SOURCES
AAPLShaders.metal
)
add_metal_shader_library(default
STANDARD macos-metal1.1
${ShaderBase_SOURCES}
${ShaderBase_HEADERS}
)
target_embed_metal_shader_libraries(visualboyadvance-m
default
)
endif()
endif()

View File

@ -1,6 +1,7 @@
#include "wx/audio/audio.h" #include "wx/audio/audio.h"
#include "core/base/check.h" #include "core/base/check.h"
#include "wx/audio/internal/sdl.h"
#include "wx/audio/internal/openal.h" #include "wx/audio/internal/openal.h"
#if defined(__WXMSW__) #if defined(__WXMSW__)
@ -22,6 +23,9 @@ std::vector<AudioDevice> EnumerateAudioDevices(const config::AudioApi& audio_api
case config::AudioApi::kOpenAL: case config::AudioApi::kOpenAL:
return audio::internal::GetOpenALDevices(); return audio::internal::GetOpenALDevices();
case config::AudioApi::kSDL:
return audio::internal::GetSDLDevices();
#if defined(__WXMSW__) #if defined(__WXMSW__)
case config::AudioApi::kDirectSound: case config::AudioApi::kDirectSound:
return audio::internal::GetDirectSoundDevices(); return audio::internal::GetDirectSoundDevices();
@ -49,6 +53,9 @@ std::unique_ptr<SoundDriver> CreateSoundDriver(const config::AudioApi& api) {
case config::AudioApi::kOpenAL: case config::AudioApi::kOpenAL:
return audio::internal::CreateOpenALDriver(); return audio::internal::CreateOpenALDriver();
case config::AudioApi::kSDL:
return audio::internal::CreateSDLDriver();
#if defined(__WXMSW__) #if defined(__WXMSW__)
case config::AudioApi::kDirectSound: case config::AudioApi::kDirectSound:
return audio::internal::CreateDirectSoundDriver(); return audio::internal::CreateDirectSoundDriver();

View File

@ -0,0 +1,381 @@
#include "wx/audio/internal/sdl.h"
// === LOGALL writes very detailed informations to vba-trace.log ===
// #define LOGALL
// on win32 and mac, pointer typedefs only happen with AL_NO_PROTOTYPES
// on mac, ALC_NO_PROTOTYPES as well
// #define AL_NO_PROTOTYPES 1
// on mac, alc pointer typedefs ony happen for ALC if ALC_NO_PROTOTYPES
// unfortunately, there is a bug in the system headers (use of ALCvoid when
// void should be used; shame on Apple for introducing this error, and shame
// on Creative for making a typedef to void in the first place)
// #define ALC_NO_PROTOTYPES 1
#ifdef ENABLE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/translation.h>
#include <wx/utils.h>
#include "core/base/sound_driver.h"
#include "core/base/check.h"
#include "core/gba/gbaGlobals.h"
#include "core/gba/gbaSound.h"
#include "wx/config/option-proxy.h"
#ifndef LOGALL
// replace logging functions with comments
#ifdef winlog
#undef winlog
#endif
// https://stackoverflow.com/a/1306690/262458
#define winlog(x, ...) \
do { \
} while (0)
#define debugState() //
#endif
extern int emulating;
namespace audio {
namespace internal {
namespace {
class SDLAudio : public SoundDriver {
public:
SDLAudio();
~SDLAudio() override;
bool init(long sampleRate) override; // initialize the sound buffer queue
void deinit();
void setThrottle(unsigned short throttle_) override; // set game speed
void pause() override; // pause the secondary sound buffer
void reset() override; // stop and reset the secondary sound buffer
void resume() override; // play/resume the secondary sound buffer
void write(uint16_t* finalWave, int length) override; // write the emulated sound to a sound buffer
private:
SDL_AudioDeviceID sound_device = 0;
SDL_AudioSpec audio;
#ifdef ENABLE_SDL3
SDL_AudioStream *sound_stream = NULL;
SDL_Mutex* mutex;
#else
SDL_mutex* mutex;
#endif
#ifdef ENABLE_SDL3
SDL_AudioDeviceID *sdl_devices;
int sdl_devices_count = 0;
#else
unsigned short current_rate;
#endif
bool initialized = false;
};
SDLAudio::SDLAudio():
sound_device(0),
#ifndef ENABLE_SDL3
current_rate(static_cast<unsigned short>(coreOptions.throttle)),
#endif
initialized(false)
{}
void SDLAudio::deinit() {
if (!initialized)
return;
initialized = false;
SDL_LockMutex(mutex);
int is_emulating = emulating;
emulating = 0;
SDL_UnlockMutex(mutex);
SDL_DestroyMutex(mutex);
mutex = nullptr;
SDL_CloseAudioDevice(sound_device);
emulating = is_emulating;
}
SDLAudio::~SDLAudio() {
deinit();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
bool SDLAudio::init(long sampleRate) {
#ifdef ENABLE_SDL3
int current_device = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
sdl_devices = SDL_GetAudioPlaybackDevices(&sdl_devices_count);
const char *devs = NULL;
#endif
winlog("SDLAudio::init\n");
if (initialized) deinit();
SDL_memset(&audio, 0, sizeof(audio));
#ifdef ENABLE_SDL3
// for "no throttle" use regular rate, audio is just dropped
audio.freq = sampleRate;
audio.format = SDL_AUDIO_S16;
#else
// for "no throttle" use regular rate, audio is just dropped
audio.freq = current_rate ? static_cast<int>(sampleRate * ((float)current_rate / 100.0)) : sampleRate;
audio.format = AUDIO_S16SYS;
#endif
audio.channels = 2;
#ifdef ENABLE_SDL3
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == false) {
#else
audio.samples = 2048;
audio.callback = NULL;
audio.userdata = NULL;
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
#endif
return false;
}
#ifdef ENABLE_SDL3
if (SDL_WasInit(SDL_INIT_AUDIO) == false) {
#else
if (SDL_WasInit(SDL_INIT_AUDIO) < 0) {
#endif
SDL_Init(SDL_INIT_AUDIO);
}
#ifdef ENABLE_SDL3
#ifdef ONLY_DEFAULT_AUDIO_DEVICE
sound_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio, NULL, NULL);
#else
for (int i = 0; i < sdl_devices_count; i++) {
devs = SDL_GetAudioDeviceName(sdl_devices[i]);
const wxString device_name(devs, wxConvLibc);
if (device_name == OPTION(kSoundAudioDevice))
{
current_device = i;
break;
}
}
if (OPTION(kSoundAudioDevice) == _("Default device")) {
sound_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio, NULL, NULL);
} else {
sound_stream = SDL_OpenAudioDeviceStream(sdl_devices[current_device], &audio, NULL, NULL);
}
if(sound_stream == NULL) {
return false;
}
sound_device = SDL_GetAudioStreamDevice(sound_stream);
#endif
#else
#ifdef ONLY_DEFAULT_AUDIO_DEVICE
sound_device = SDL_OpenAudioDevice(NULL, 0, &audio, NULL, 0);
#else
const wxString device_name = OPTION(kSoundAudioDevice);
if (device_name == _("Default device")) {
sound_device = SDL_OpenAudioDevice(NULL, 0, &audio, NULL, 0);
} else {
sound_device = SDL_OpenAudioDevice(device_name.mb_str(), 0, &audio, NULL, 0);
}
#endif
#endif
if(sound_device == 0) {
return false;
}
mutex = SDL_CreateMutex();
// turn off audio events because we are not processing them
#ifdef ENABLE_SDL3
SDL_SetEventEnabled(SDL_EVENT_AUDIO_DEVICE_ADDED, false);
SDL_SetEventEnabled(SDL_EVENT_AUDIO_DEVICE_REMOVED, false);
#elif SDL_VERSION_ATLEAST(2, 0, 4)
SDL_EventState(SDL_AUDIODEVICEADDED, SDL_IGNORE);
SDL_EventState(SDL_AUDIODEVICEREMOVED, SDL_IGNORE);
#endif
return initialized = true;
}
void SDLAudio::setThrottle(unsigned short throttle_) {
if (!initialized)
return;
if (throttle_ == 0)
throttle_ = 450;
#ifdef ENABLE_SDL3
SDL_SetAudioStreamFrequencyRatio(sound_stream, (float)throttle_ / 100.0f);
#else
current_rate = throttle_;
reset();
#endif
}
void SDLAudio::resume() {
if (!initialized)
return;
winlog("SDLAudio::resume\n");
#ifdef ENABLE_SDL3
if (SDL_AudioDevicePaused(sound_device) == true) {
SDL_ResumeAudioStreamDevice(sound_stream);
SDL_ResumeAudioDevice(sound_device);
}
#else
if (SDL_GetAudioDeviceStatus(sound_device) != SDL_AUDIO_PLAYING) {
SDL_PauseAudioDevice(sound_device, 0);
}
#endif
}
void SDLAudio::pause() {
if (!initialized)
return;
winlog("SDLAudio::pause\n");
#ifdef ENABLE_SDL3
if (SDL_AudioDevicePaused(sound_device) == true) {
SDL_PauseAudioStreamDevice(sound_stream);
SDL_PauseAudioDevice(sound_device);
}
#else
if (SDL_GetAudioDeviceStatus(sound_device) != SDL_AUDIO_PLAYING) {
SDL_PauseAudioDevice(sound_device, 1);
}
#endif
}
void SDLAudio::reset() {
if (!initialized)
return;
winlog("SDLAudio::reset\n");
init(soundGetSampleRate());
}
void SDLAudio::write(uint16_t* finalWave, int length) {
int res = 0;
if (!initialized)
return;
SDL_LockMutex(mutex);
#ifdef ENABLE_SDL3
if (SDL_AudioDevicePaused(sound_device) == true) {
SDL_ResumeAudioStreamDevice(sound_stream);
SDL_ResumeAudioDevice(sound_device);
}
#else
if (SDL_GetAudioDeviceStatus(sound_device) != SDL_AUDIO_PLAYING) {
SDL_PauseAudioDevice(sound_device, 0);
}
#endif
#ifdef ENABLE_SDL3
res = (int)SDL_PutAudioStreamData(sound_stream, finalWave, length) == true;
while (res && SDL_GetAudioStreamQueued(sound_stream) > (2048 * audio.channels * sizeof(uint16_t))) {
SDL_Delay(1);
}
#else
res = SDL_QueueAudio(sound_device, finalWave, length) == 0;
while (res && SDL_GetQueuedAudioSize(sound_device) > (audio.samples * audio.channels * sizeof(uint16_t))) {
SDL_Delay(1);
}
#endif
winlog("SDL audio queue result: %d\n", res);
SDL_UnlockMutex(mutex);
}
} // namespace
std::vector<AudioDevice> GetSDLDevices() {
std::vector<AudioDevice> devices;
#ifdef ONLY_DEFAULT_AUDIO_DEVICE
devices.push_back({_("Default device"), wxEmptyString});
#else
#ifdef ENABLE_SDL3
const char *devs = NULL;
SDL_AudioDeviceID *sdl_devices = NULL;
int sdl_devices_count = 0;
SDL_InitSubSystem(SDL_INIT_AUDIO);
sdl_devices = SDL_GetAudioPlaybackDevices(&sdl_devices_count);
devices.push_back({_("Default device"), _("Default device")});
for (int i = 0; i < sdl_devices_count; i++)
{
devs = SDL_GetAudioDeviceName(sdl_devices[i]);
if (devs != NULL)
{
const wxString device_name(devs, wxConvLibc);
devices.push_back({device_name, device_name});
}
}
#else
const char *devs = NULL;
int sdl_devices_count = 0;
SDL_InitSubSystem(SDL_INIT_AUDIO);
sdl_devices_count = SDL_GetNumAudioDevices(0);
devices.push_back({_("Default device"), _("Default device")});
for (int i = 0; i < sdl_devices_count; i++)
{
devs = SDL_GetAudioDeviceName(i, 0);
const wxString device_name(devs, wxConvLibc);
devices.push_back({device_name, device_name});
}
#endif
#endif
return devices;
}
std::unique_ptr<SoundDriver> CreateSDLDriver() {
winlog("newSDL\n");
return std::make_unique<SDLAudio>();
}
} // namespace internal
} // namespace audio

View File

@ -0,0 +1,18 @@
#ifndef WX_AUDIO_INTERNAL_SDL_H_
#define WX_AUDIO_INTERNAL_SDL_H_
#include "wx/audio/audio.h"
namespace audio {
namespace internal {
// Returns the set of OpenAL devices.
std::vector<AudioDevice> GetSDLDevices();
// Creates an OpenAL sound driver.
std::unique_ptr<SoundDriver> CreateSDLDriver();
} // namespace internal
} // namespace audio
#endif // WX_AUDIO_INTERNAL_SDL_H_

View File

@ -2134,6 +2134,9 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
return; return;
} }
const uint32_t bitdepth = OPTION(kBitDepth);
systemColorDepth = (int)((bitdepth + 1) << 3);
const int frame_skip = OPTION(kPrefFrameSkip); const int frame_skip = OPTION(kPrefFrameSkip);
if (frame_skip != -1) { if (frame_skip != -1) {
systemFrameSkip = frame_skip; systemFrameSkip = frame_skip;
@ -2381,6 +2384,11 @@ EVT_HANDLER(NoStatusMsg, "Disable on-screen status messages")
GetMenuOptionConfig("NoStatusMsg", config::OptionID::kPrefDisableStatus); GetMenuOptionConfig("NoStatusMsg", config::OptionID::kPrefDisableStatus);
} }
EVT_HANDLER(BitDepth, "Bit depth")
{
GetMenuOptionConfig("BitDepth", config::OptionID::kBitDepth);
}
EVT_HANDLER(FrameSkipAuto, "Auto Skip frames.") EVT_HANDLER(FrameSkipAuto, "Auto Skip frames.")
{ {
GetMenuOptionConfig("FrameSkipAuto", config::OptionID::kPrefAutoFrameSkip); GetMenuOptionConfig("FrameSkipAuto", config::OptionID::kPrefAutoFrameSkip);

View File

@ -72,10 +72,14 @@ static const std::array<wxString, kNbInterframes> kInterframeStrings = {
static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = { static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
"simple", "simple",
"opengl", "opengl",
"sdl_video",
#if defined(__WXMSW__) && !defined(NO_D3D) #if defined(__WXMSW__) && !defined(NO_D3D)
"direct3d", "direct3d",
#elif defined(__WXMAC__) #elif defined(__WXMAC__)
"quartz2d", "quartz2d",
#ifndef NO_METAL
"metal",
#endif
#endif #endif
}; };
@ -84,6 +88,7 @@ static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
// error since kNbAudioApis is automatically updated. // error since kNbAudioApis is automatically updated.
static const std::array<wxString, kNbAudioApis> kAudioApiStrings = { static const std::array<wxString, kNbAudioApis> kAudioApiStrings = {
"openal", "openal",
"sdl_audio",
#if defined(__WXMSW__) #if defined(__WXMSW__)
"directsound", "directsound",
#endif #endif
@ -137,10 +142,16 @@ std::array<Option, kNbOptions>& Option::All() {
Interframe interframe = Interframe::kNone; Interframe interframe = Interframe::kNone;
bool keep_on_top = false; bool keep_on_top = false;
int32_t max_threads = 0; int32_t max_threads = 0;
#if defined(__WXMAC__) && !defined(NO_METAL)
RenderMethod render_method = RenderMethod::kMetal;
#else
#if defined(NO_OGL) #if defined(NO_OGL)
RenderMethod render_method = RenderMethod::kSimple; //RenderMethod render_method = RenderMethod::kSimple;
RenderMethod render_method = RenderMethod::kSDL;
#else #else
RenderMethod render_method = RenderMethod::kOpenGL; RenderMethod render_method = RenderMethod::kOpenGL;
#endif
#endif #endif
double video_scale = 3; double video_scale = 3;
bool retain_aspect = true; bool retain_aspect = true;
@ -228,6 +239,8 @@ std::array<Option, kNbOptions>& Option::All() {
bool dsound_hw_accel = false; bool dsound_hw_accel = false;
bool upmix = false; bool upmix = false;
int32_t volume = 100; int32_t volume = 100;
uint32_t bitdepth = 3;
wxString sdlrenderer = wxString("default");
}; };
static OwnedOptions g_owned_opts; static OwnedOptions g_owned_opts;
@ -243,11 +256,13 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kDispFilter, &g_owned_opts.filter), Option(OptionID::kDispFilter, &g_owned_opts.filter),
Option(OptionID::kDispFilterPlugin, &g_owned_opts.filter_plugin), Option(OptionID::kDispFilterPlugin, &g_owned_opts.filter_plugin),
Option(OptionID::kDispIFB, &g_owned_opts.interframe), Option(OptionID::kDispIFB, &g_owned_opts.interframe),
Option(OptionID::kBitDepth, &g_owned_opts.bitdepth, 0, 3),
Option(OptionID::kDispKeepOnTop, &g_owned_opts.keep_on_top), Option(OptionID::kDispKeepOnTop, &g_owned_opts.keep_on_top),
Option(OptionID::kDispMaxThreads, &g_owned_opts.max_threads, 0, 256), Option(OptionID::kDispMaxThreads, &g_owned_opts.max_threads, 0, 256),
Option(OptionID::kDispRenderMethod, &g_owned_opts.render_method), Option(OptionID::kDispRenderMethod, &g_owned_opts.render_method),
Option(OptionID::kDispScale, &g_owned_opts.video_scale, 1, 6), Option(OptionID::kDispScale, &g_owned_opts.video_scale, 1, 6),
Option(OptionID::kDispStretch, &g_owned_opts.retain_aspect), Option(OptionID::kDispStretch, &g_owned_opts.retain_aspect),
Option(OptionID::kSDLRenderer, &g_owned_opts.sdlrenderer),
/// GB /// GB
Option(OptionID::kGBBiosFile, &g_owned_opts.gb_bios), Option(OptionID::kGBBiosFile, &g_owned_opts.gb_bios),
@ -383,6 +398,7 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
OptionData{"Display/Filter", "", _("Full-screen filter to apply")}, OptionData{"Display/Filter", "", _("Full-screen filter to apply")},
OptionData{"Display/FilterPlugin", "", _("Filter plugin library")}, OptionData{"Display/FilterPlugin", "", _("Filter plugin library")},
OptionData{"Display/IFB", "", _("Interframe blending function")}, OptionData{"Display/IFB", "", _("Interframe blending function")},
OptionData{"Display/BitDepth", "BitDepth", _("Bit depth")},
OptionData{"Display/KeepOnTop", "KeepOnTop", _("Keep window on top")}, OptionData{"Display/KeepOnTop", "KeepOnTop", _("Keep window on top")},
OptionData{"Display/MaxThreads", "Multithread", OptionData{"Display/MaxThreads", "Multithread",
_("Maximum number of threads to run filters in")}, _("Maximum number of threads to run filters in")},
@ -390,6 +406,7 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
_("Render method; if unsupported, simple method will be used")}, _("Render method; if unsupported, simple method will be used")},
OptionData{"Display/Scale", "", _("Default scale factor")}, OptionData{"Display/Scale", "", _("Default scale factor")},
OptionData{"Display/Stretch", "RetainAspect", _("Retain aspect ratio when resizing")}, OptionData{"Display/Stretch", "RetainAspect", _("Retain aspect ratio when resizing")},
OptionData{"Display/SDLRenderer", "", _("SDL renderer")},
/// GB /// GB
OptionData{"GB/BiosFile", "", _("BIOS file to use for Game Boy, if enabled")}, OptionData{"GB/BiosFile", "", _("BIOS file to use for Game Boy, if enabled")},

View File

@ -11,11 +11,13 @@ enum class OptionID {
kDispFilter, kDispFilter,
kDispFilterPlugin, kDispFilterPlugin,
kDispIFB, kDispIFB,
kBitDepth,
kDispKeepOnTop, kDispKeepOnTop,
kDispMaxThreads, kDispMaxThreads,
kDispRenderMethod, kDispRenderMethod,
kDispScale, kDispScale,
kDispStretch, kDispStretch,
kSDLRenderer,
/// GB /// GB
kGBBiosFile, kGBBiosFile,

View File

@ -15,11 +15,13 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kDispFilter*/ Option::Type::kFilter, /*kDispFilter*/ Option::Type::kFilter,
/*kDispFilterPlugin*/ Option::Type::kString, /*kDispFilterPlugin*/ Option::Type::kString,
/*kDispIFB*/ Option::Type::kInterframe, /*kDispIFB*/ Option::Type::kInterframe,
/*kBitDepth*/ Option::Type::kUnsigned,
/*kDispKeepOnTop*/ Option::Type::kBool, /*kDispKeepOnTop*/ Option::Type::kBool,
/*kDispMaxThreads*/ Option::Type::kInt, /*kDispMaxThreads*/ Option::Type::kInt,
/*kDispRenderMethod*/ Option::Type::kRenderMethod, /*kDispRenderMethod*/ Option::Type::kRenderMethod,
/*kDispScale*/ Option::Type::kDouble, /*kDispScale*/ Option::Type::kDouble,
/*kDispStretch*/ Option::Type::kBool, /*kDispStretch*/ Option::Type::kBool,
/*kSDLRenderer*/ Option::Type::kString,
/// GB /// GB
/*kGBBiosFile*/ Option::Type::kString, /*kGBBiosFile*/ Option::Type::kString,

View File

@ -268,6 +268,9 @@ TEST(OptionTest, Enum) {
EXPECT_TRUE(option->SetRenderMethod(config::RenderMethod::kSimple)); EXPECT_TRUE(option->SetRenderMethod(config::RenderMethod::kSimple));
EXPECT_EQ(option->GetRenderMethod(), config::RenderMethod::kSimple); EXPECT_EQ(option->GetRenderMethod(), config::RenderMethod::kSimple);
EXPECT_TRUE(option->SetRenderMethod(config::RenderMethod::kSDL));
EXPECT_EQ(option->GetRenderMethod(), config::RenderMethod::kSDL);
EXPECT_TRUE(option->SetEnumString("opengl")); EXPECT_TRUE(option->SetEnumString("opengl"));
EXPECT_EQ(option->GetRenderMethod(), config::RenderMethod::kOpenGL); EXPECT_EQ(option->GetRenderMethod(), config::RenderMethod::kOpenGL);
} }

View File

@ -66,10 +66,14 @@ static constexpr size_t kNbInterframes = static_cast<size_t>(Interframe::kLast);
enum class RenderMethod { enum class RenderMethod {
kSimple = 0, kSimple = 0,
kOpenGL, kOpenGL,
kSDL,
#if defined(__WXMSW__) && !defined(NO_D3D) #if defined(__WXMSW__) && !defined(NO_D3D)
kDirect3d, kDirect3d,
#elif defined(__WXMAC__) #elif defined(__WXMAC__)
kQuartz2d, kQuartz2d,
#ifndef NO_METAL
kMetal,
#endif
#endif #endif
// Do not add anything under here. // Do not add anything under here.
@ -80,6 +84,7 @@ static constexpr size_t kNbRenderMethods = static_cast<size_t>(RenderMethod::kLa
// Values for kAudioApi. // Values for kAudioApi.
enum class AudioApi { enum class AudioApi {
kOpenAL, kOpenAL,
kSDL,
#if defined(__WXMSW__) #if defined(__WXMSW__)
kDirectSound, kDirectSound,
#endif // __WXMSW__ #endif // __WXMSW__

View File

@ -22,10 +22,58 @@
#include "wx/widgets/render-plugin.h" #include "wx/widgets/render-plugin.h"
#include "wx/wxvbam.h" #include "wx/wxvbam.h"
#ifdef ENABLE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif
namespace dialogs { namespace dialogs {
namespace { namespace {
class SDLDevicesValidator : public widgets::OptionValidator {
public:
SDLDevicesValidator() : widgets::OptionValidator(config::OptionID::kSDLRenderer) {}
~SDLDevicesValidator() override = default;
private:
// OptionValidator implementation.
wxObject* Clone() const override { return new SDLDevicesValidator(); }
bool IsWindowValueValid() override { return true; }
bool WriteToWindow() override {
wxChoice* choice = wxDynamicCast(GetWindow(), wxChoice);
VBAM_CHECK(choice);
const wxString& device_id = option()->GetString();
for (size_t i = 0; i < choice->GetCount(); i++) {
const wxString& choide_id =
dynamic_cast<wxStringClientData*>(choice->GetClientObject(i))->GetData();
if (device_id == choide_id) {
choice->SetSelection(i);
return true;
}
}
choice->SetSelection(0);
return true;
}
bool WriteToOption() override {
const wxChoice* choice = wxDynamicCast(GetWindow(), wxChoice);
VBAM_CHECK(choice);
const int selection = choice->GetSelection();
if (selection == wxNOT_FOUND) {
return option()->SetString(wxEmptyString);
}
return option()->SetString(
dynamic_cast<wxStringClientData*>(choice->GetClientObject(selection))->GetData());
}
};
// Custom validator for the kDispScale option. We rely on the existing // Custom validator for the kDispScale option. We rely on the existing
// wxFloatingPointValidator validator for this. // wxFloatingPointValidator validator for this.
class ScaleValidator : public wxFloatingPointValidator<double>, class ScaleValidator : public wxFloatingPointValidator<double>,
@ -234,6 +282,10 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
std::bind(&DisplayConfig::OnInterframeChanged, std::bind(&DisplayConfig::OnInterframeChanged,
this, this,
std::placeholders::_1)) { std::placeholders::_1)) {
GetValidatedChild("BitDepth")
->SetValidator(
widgets::OptionChoiceValidator(config::OptionID::kBitDepth));
// Speed // Speed
GetValidatedChild("FrameSkip") GetValidatedChild("FrameSkip")
->SetValidator( ->SetValidator(
@ -253,14 +305,24 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
->SetValidator(wxGenericValidator(&gopts.max_scale)); ->SetValidator(wxGenericValidator(&gopts.max_scale));
// Basic // Basic
GetValidatedChild("OutputSimple") wxWindow *render_method = GetValidatedChild("OutputSimple");
->SetValidator(RenderValidator(config::RenderMethod::kSimple)); render_method->SetValidator(RenderValidator(config::RenderMethod::kSimple));
render_method = GetValidatedChild("OutputSDL");
render_method->SetValidator(RenderValidator(config::RenderMethod::kSDL));
#if defined(__WXMAC__) #if defined(__WXMAC__)
GetValidatedChild("OutputQuartz2D") render_method = GetValidatedChild("OutputQuartz2D");
->SetValidator(RenderValidator(config::RenderMethod::kQuartz2d)); render_method->SetValidator(RenderValidator(config::RenderMethod::kQuartz2d));
#ifndef NO_METAL
render_method = GetValidatedChild("OutputMetal");
render_method->SetValidator(RenderValidator(config::RenderMethod::kMetal));
#else
GetValidatedChild("OutputMetal")->Hide();
#endif
#else #else
GetValidatedChild("OutputQuartz2D")->Hide(); GetValidatedChild("OutputQuartz2D")->Hide();
GetValidatedChild("OutputMetal")->Hide();
#endif #endif
#ifdef NO_OGL #ifdef NO_OGL
@ -270,22 +332,25 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
if (IsWayland()) { if (IsWayland()) {
GetValidatedChild("OutputOpenGL")->Hide(); GetValidatedChild("OutputOpenGL")->Hide();
} else { } else {
GetValidatedChild("OutputOpenGL") render_method = GetValidatedChild("OutputOpenGL");
->SetValidator(RenderValidator(config::RenderMethod::kOpenGL)); render_method->SetValidator(RenderValidator(config::RenderMethod::kOpenGL));
} }
#else #else
GetValidatedChild("OutputOpenGL") render_method = GetValidatedChild("OutputOpenGL");
->SetValidator(RenderValidator(config::RenderMethod::kOpenGL)); render_method->SetValidator(RenderValidator(config::RenderMethod::kOpenGL));
#endif // NO_OGL #endif // NO_OGL
#if defined(__WXMSW__) && !defined(NO_D3D) #if defined(__WXMSW__) && !defined(NO_D3D)
// Enable the Direct3D option on Windows. // Enable the Direct3D option on Windows.
GetValidatedChild("OutputDirect3D") render_method = GetValidatedChild("OutputDirect3D");
->SetValidator(RenderValidator(config::RenderMethod::kDirect3d)); render_method->SetValidator(RenderValidator(config::RenderMethod::kDirect3d));
#else #else
GetValidatedChild("OutputDirect3D")->Hide(); GetValidatedChild("OutputDirect3D")->Hide();
#endif #endif
sdlrenderer_selector_ = GetValidatedChild<wxChoice>("SDLRenderer");
sdlrenderer_selector_->SetValidator(SDLDevicesValidator());
filter_selector_ = GetValidatedChild<wxChoice>("Filter"); filter_selector_ = GetValidatedChild<wxChoice>("Filter");
filter_selector_->SetValidator(FilterValidator()); filter_selector_->SetValidator(FilterValidator());
filter_selector_->Bind(wxEVT_CHOICE, &DisplayConfig::UpdatePlugin, this, filter_selector_->Bind(wxEVT_CHOICE, &DisplayConfig::UpdatePlugin, this,
@ -305,12 +370,16 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
} }
void DisplayConfig::OnDialogShowEvent(wxShowEvent& event) { void DisplayConfig::OnDialogShowEvent(wxShowEvent& event) {
wxCommandEvent dummy_event;
if (event.IsShown()) { if (event.IsShown()) {
PopulatePluginOptions(); PopulatePluginOptions();
} else { } else {
StopPluginHandler(); StopPluginHandler();
} }
FillRendererList(dummy_event);
// Let the event propagate. // Let the event propagate.
event.Skip(); event.Skip();
} }
@ -415,6 +484,43 @@ void DisplayConfig::OnInterframeChanged(config::Option* option) {
interframe_selector_->GetString(static_cast<size_t>(interframe)))); interframe_selector_->GetString(static_cast<size_t>(interframe))));
} }
void DisplayConfig::FillRendererList(wxCommandEvent& event) {
#ifndef ENABLE_SDL3
SDL_RendererInfo render_info;
#endif
int num_drivers = 0;
SDL_InitSubSystem(SDL_INIT_VIDEO);
SDL_Init(SDL_INIT_VIDEO);
num_drivers = SDL_GetNumRenderDrivers();
sdlrenderer_selector_->Clear();
sdlrenderer_selector_->Append("default", new wxStringClientData("default"));
sdlrenderer_selector_->SetSelection(0);
for (int i = 0; i < num_drivers; i++) {
#ifdef ENABLE_SDL3
sdlrenderer_selector_->Append(SDL_GetRenderDriver(i), new wxStringClientData(SDL_GetRenderDriver(i)));
if (OPTION(kSDLRenderer) == wxString(SDL_GetRenderDriver(i))) {
sdlrenderer_selector_->SetSelection(i+1);
}
#else
SDL_GetRenderDriverInfo(i, &render_info);
sdlrenderer_selector_->Append(render_info.name, new wxStringClientData(render_info.name));
if (OPTION(kSDLRenderer) == wxString(render_info.name)) {
sdlrenderer_selector_->SetSelection(i+1);
}
#endif
}
// Let the event propagate.
event.Skip();
}
void DisplayConfig::HidePluginOptions() { void DisplayConfig::HidePluginOptions() {
plugin_label_->Hide(); plugin_label_->Hide();
plugin_selector_->Hide(); plugin_selector_->Hide();

View File

@ -45,6 +45,9 @@ private:
// Displays the new interframe name on the screen. // Displays the new interframe name on the screen.
void OnInterframeChanged(config::Option* option); void OnInterframeChanged(config::Option* option);
// Renderer changed
void FillRendererList(wxCommandEvent& event);
// Hides/Shows the plugin-related filter options. // Hides/Shows the plugin-related filter options.
void HidePluginOptions(); void HidePluginOptions();
void ShowPluginOptions(); void ShowPluginOptions();
@ -53,6 +56,7 @@ private:
wxChoice* plugin_selector_; wxChoice* plugin_selector_;
wxChoice* filter_selector_; wxChoice* filter_selector_;
wxChoice* interframe_selector_; wxChoice* interframe_selector_;
wxChoice* sdlrenderer_selector_;
const config::OptionsObserver filter_observer_; const config::OptionsObserver filter_observer_;
const config::OptionsObserver interframe_observer_; const config::OptionsObserver interframe_observer_;
}; };

View File

@ -158,6 +158,12 @@ SoundConfig::SoundConfig(wxWindow* parent) : BaseDialog(parent, "SoundConfig") {
std::bind(&SoundConfig::OnAudioApiChanged, this, std::placeholders::_1, std::bind(&SoundConfig::OnAudioApiChanged, this, std::placeholders::_1,
config::AudioApi::kOpenAL)); config::AudioApi::kOpenAL));
audio_api_button = GetValidatedChild("SDL");
audio_api_button->SetValidator(AudioApiValidator(config::AudioApi::kSDL));
audio_api_button->Bind(wxEVT_RADIOBUTTON,
std::bind(&SoundConfig::OnAudioApiChanged, this, std::placeholders::_1,
config::AudioApi::kSDL));
audio_api_button = GetValidatedChild("DirectSound"); audio_api_button = GetValidatedChild("DirectSound");
#if defined(__WXMSW__) #if defined(__WXMSW__)
audio_api_button->SetValidator(AudioApiValidator(config::AudioApi::kDirectSound)); audio_api_button->SetValidator(AudioApiValidator(config::AudioApi::kDirectSound));

View File

@ -49,6 +49,26 @@ protected:
}; };
#endif #endif
class SDLDrawingPanel : public DrawingPanel {
public:
SDLDrawingPanel(wxWindow* parent, int _width, int _height);
virtual ~SDLDrawingPanel();
protected:
void DrawArea();
void DrawArea(uint8_t** data);
void DrawArea(wxWindowDC&) override;
void PaintEv(wxPaintEvent& ev) override;
void EraseBackground(wxEraseEvent& ev) override;
void OnSize(wxSizeEvent& ev) override;
void DrawingPanelInit() override;
private:
SDL_Window *sdlwindow;
SDL_Texture *texture;
SDL_Renderer *renderer;
};
#if defined(__WXMSW__) && !defined(NO_D3D) #if defined(__WXMSW__) && !defined(NO_D3D)
class DXDrawingPanel : public DrawingPanel { class DXDrawingPanel : public DrawingPanel {
public: public:
@ -60,6 +80,81 @@ protected:
#endif #endif
#if defined(__WXMAC__) #if defined(__WXMAC__)
#ifndef NO_METAL
#ifdef __OBJC__
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <CoreGraphics/CoreGraphics.h>
#endif
#include <simd/simd.h>
typedef enum AAPLVertexInputIndex
{
AAPLVertexInputIndexVertices = 0,
AAPLVertexInputIndexViewportSize = 1,
} AAPLVertexInputIndex;
// Texture index values shared between shader and C code to ensure Metal shader buffer inputs match
// Metal API texture set calls
typedef enum AAPLTextureIndex
{
AAPLTextureIndexBaseColor = 0,
} AAPLTextureIndex;
// This structure defines the layout of each vertex in the array of vertices set as an input to the
// Metal vertex shader. Since this header is shared between the .metal shader and C code,
// you can be sure that the layout of the vertex array in the code matches the layout that
// the vertex shader expects
typedef struct
{
// Positions in pixel space. A value of 100 indicates 100 pixels from the origin/center.
vector_float2 position;
// 2D texture coordinate
vector_float2 textureCoordinate;
} AAPLVertex;
bool is_macosx_1012_or_newer();
class MetalDrawingPanel : public DrawingPanel {
public:
MetalDrawingPanel(wxWindow* parent, int _width, int _height);
virtual ~MetalDrawingPanel();
protected:
void DrawArea();
void DrawArea(uint8_t** data);
void DrawArea(wxWindowDC&) override;
void PaintEv(wxPaintEvent& ev) override;
void EraseBackground(wxEraseEvent& ev) override;
void OnSize(wxSizeEvent& ev) override;
void DrawingPanelInit() override;
#ifdef __OBJC__
private:
void CreateMetalView();
id<MTLTexture> loadTextureUsingData(void *data);
NSView *view;
MTKView *metalView;
NSRect metalFrame;
MTLRenderPassDescriptor *renderPassDescriptor;
id<MTLRenderCommandEncoder> renderEncoder;
id<MTLCommandBuffer> commandBuffer;
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
id<MTLRenderPipelineState> _pipelineState;
id<MTLTexture> _texture;
id<MTLBuffer> _vertices;
NSUInteger _numVertices;
vector_uint2 _viewportSize;
vector_uint2 _contentSize;
#endif
};
#endif
class Quartz2DDrawingPanel : public BasicDrawingPanel { class Quartz2DDrawingPanel : public BasicDrawingPanel {
public: public:
Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height); Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height);

View File

@ -11,12 +11,37 @@
#include "wx/viewsupt.h" #include "wx/viewsupt.h"
#include "wx/wxvbam.h" #include "wx/wxvbam.h"
#if __STDC_WANT_SECURE_LIB__
#define snprintf sprintf_s
#endif
namespace { namespace {
void utilReadScreenPixels(uint8_t* dest, int w, int h) { void utilReadScreenPixels(uint8_t* dest, int w, int h) {
uint8_t* b = dest; uint8_t* b = dest;
int sizeX = w; int sizeX = w;
int sizeY = h; int sizeY = h;
switch (systemColorDepth) { switch (systemColorDepth) {
case 8: {
uint8_t* p = (uint8_t*)(g_pix + (w + 2)); // skip first black line
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) {
uint8_t v = *p++;
// White color fix
if (v == 0xff) {
*b++ = 0xff;
*b++ = 0xff;
*b++ = 0xff;
} else {
*b++ = (((v >> 5) & 0x7) << 5);
*b++ = (((v >> 2) & 0x7) << 5);
*b++ = ((v & 0x3) << 6);
}
}
p++; // skip black pixel for filters
p++; // skip black pixel for filters
}
} break;
case 16: { case 16: {
uint16_t* p = (uint16_t*)(g_pix + (w + 2) * 2); // skip first black line uint16_t* p = (uint16_t*)(g_pix + (w + 2) * 2); // skip first black line
for (int y = 0; y < sizeY; y++) { for (int y = 0; y < sizeY; y++) {
@ -928,8 +953,9 @@ public:
for (int y = 0; y < sizeY; y++) { for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) { for (int x = 0; x < sizeX; x++) {
uint32_t color = g_vram[0x10000 + (((c + (y >> 3) * inc) * 32 + (y & 7) * 8 + (x >> 3) * 64 + (x & 7)) & 0x7FFF)]; uint32_t color = g_vram[0x10000 + (((c + (((y >> 3) * inc) << 5) + ((y & 7) << 4) + ((x >> 3) << 6) + (x & 7))) & 0x7FFF)];
color = pal[color]; color = pal[color];
*bmp++ = (color & 0x1f) << 3; *bmp++ = (color & 0x1f) << 3;
*bmp++ = ((color >> 5) & 0x1f) << 3; *bmp++ = ((color >> 5) & 0x1f) << 3;
*bmp++ = ((color >> 10) & 0x1f) << 3; *bmp++ = ((color >> 10) & 0x1f) << 3;
@ -950,7 +976,7 @@ public:
for (int y = 0; y < sizeY; y++) { for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) { for (int x = 0; x < sizeX; x++) {
uint32_t color = g_vram[0x10000 + (((c + (y >> 3) * inc) * 32 + (y & 7) * 4 + (x >> 3) * 32 + ((x & 7) >> 1)) & 0x7FFF)]; uint32_t color = g_vram[0x10000 + ((((((c + (((y >> 3) * inc) << 5)) + ((y & 7) << 2)) + ((x >> 3) << 5)) + ((x & 7) >> 1))) & 0x7FFF)];
if (x & 1) if (x & 1)
color >>= 4; color >>= 4;
@ -958,6 +984,7 @@ public:
color &= 0x0F; color &= 0x0F;
color = pal[palette + color]; color = pal[palette + color];
*bmp++ = (color & 0x1f) << 3; *bmp++ = (color & 0x1f) << 3;
*bmp++ = ((color >> 5) & 0x1f) << 3; *bmp++ = ((color >> 5) & 0x1f) << 3;
*bmp++ = ((color >> 10) & 0x1f) << 3; *bmp++ = ((color >> 10) & 0x1f) << 3;
@ -1246,7 +1273,7 @@ void savepal(wxWindow* parent, const uint8_t* data, int ncols, const wxString ty
for (int i = 0; i < ncols; i++, data += 3) { for (int i = 0; i < ncols; i++, data += 3) {
char buf[14]; char buf[14];
int l = sprintf(buf, "%d %d %d\r\n", data[0], data[1], data[2]); int l = snprintf(buf, sizeof(buf), "%d %d %d\r\n", data[0], data[1], data[2]);
f.Write(buf, l); f.Write(buf, l);
} }

View File

@ -5,8 +5,410 @@
#include <wx/rawbmp.h> #include <wx/rawbmp.h>
#include "wx/drawing.h" #include "wx/drawing.h"
#include "wx/config/option-id.h"
#include "wx/config/option-proxy.h"
#include "wx/config/option.h"
#include "wx/wxvbam.h" #include "wx/wxvbam.h"
#ifndef NO_METAL
bool is_macosx_1012_or_newer()
{
// Mac OS X 10.12 version check
if (NSAppKitVersionNumber >= 1504) {
return true;
}
return false;
}
MetalDrawingPanel::~MetalDrawingPanel()
{
if (did_init)
{
renderPassDescriptor = nil;
commandBuffer = nil;
renderEncoder = nil;
if (metalView != nil)
[metalView removeFromSuperview];
if (_device != nil)
[_device release];
if (_commandQueue != nil)
[_commandQueue release];
if (_pipelineState != nil)
[_pipelineState release];
if (_texture != nil)
[_texture release];
if (_vertices != nil)
[_vertices release];
did_init = false;
}
}
void MetalDrawingPanel::EraseBackground(wxEraseEvent& ev)
{
(void)ev; // unused params
// do nothing, do not allow propagation
}
void MetalDrawingPanel::CreateMetalView()
{
view = (NSView *)wxGetApp().frame->GetPanel()->GetHandle();
view.layerContentsPlacement = NSViewLayerContentsPlacementCenter;
view.layer.backgroundColor = [NSColor colorWithCalibratedRed:0.0f
green:0.0f
blue:0.0f
alpha:0.0f].CGColor;
metalView = [[MTKView alloc] init];
metalView.layer.backgroundColor = [NSColor colorWithCalibratedRed:0.0f
green:0.0f
blue:0.0f
alpha:0.0f].CGColor;
metalView.device = MTLCreateSystemDefaultDevice();
metalView.colorPixelFormat = MTLPixelFormatRGBA8Unorm;
metalView.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
metalView.layerContentsPlacement = NSViewLayerContentsPlacementCenter;
metalView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
metalView.layer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
metalView.layer.needsDisplayOnBoundsChange = YES;
((CAMetalLayer *)metalView.layer).device = metalView.device;
_device = metalView.device;
const AAPLVertex quadVertices[] =
{
// Pixel positions, Texture coordinates
{ { (float)(width * scale), (float)-(height * scale) }, { 1.f, 1.f } },
{ { (float)-(width * scale), (float)-(height * scale) }, { 0.f, 1.f } },
{ { (float)-(width * scale), (float)(height * scale) }, { 0.f, 0.f } },
{ { (float)(width * scale), (float)-(height * scale) }, { 1.f, 1.f } },
{ { (float)-(width * scale), (float)(height * scale) }, { 0.f, 0.f } },
{ { (float)(width * scale), (float)(height * scale) }, { 1.f, 0.f } },
};
// Create a vertex buffer, and initialize it with the quadVertices array
_vertices = [_device newBufferWithBytes:quadVertices
length:sizeof(quadVertices)
options:MTLResourceStorageModeShared];
// Calculate the number of vertices by dividing the byte length by the size of each vertex
_numVertices = sizeof(quadVertices) / sizeof(AAPLVertex);
/// Create the render pipeline.
// Load the shaders from the default library
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"samplingShader"];
// Set up a descriptor for creating a pipeline state object
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"Texturing Pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalView.colorPixelFormat;
NSError *error = NULL;
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor
error:&error];
_commandQueue = [_device newCommandQueue];
if (OPTION(kDispStretch) == false) {
metalView.frame = view.frame;
metalFrame = view.frame;
} else {
float scaleX = view.frame.size.width / (width * scale);
float scaleY = view.frame.size.height / (height * scale);
float scaleF = 0;
if (scaleX < scaleY) {
scaleF = scaleX;
} else {
scaleF = scaleY;
}
if (scaleF == 0) {
scaleF = 1;
}
metalFrame.size.width = (width * scale) * scaleF;
metalFrame.size.height = (height * scale) * scaleF;
metalFrame.origin.x = (view.frame.size.width - metalFrame.size.width) / 2;
metalFrame.origin.y = (view.frame.size.height - metalFrame.size.height) / 2;
metalView.frame = metalFrame;
}
metalView.wantsLayer = YES;
metalView.layer.contentsScale = 1.0;
metalView.autoResizeDrawable = NO;
metalView.drawableSize = metalFrame.size;
((CAMetalLayer *)metalView.layer).drawableSize = metalFrame.size;
_contentSize.x = metalFrame.size.width;
_contentSize.y = metalFrame.size.height;
_viewportSize.x = width * scale;
_viewportSize.y = height * scale;
[view addSubview:metalView];
}
void MetalDrawingPanel::DrawingPanelInit()
{
CreateMetalView();
did_init = true;
}
id<MTLTexture> MetalDrawingPanel::loadTextureUsingData(void *data)
{
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
// Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is
// an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0)
textureDescriptor.pixelFormat = metalView.colorPixelFormat;
textureDescriptor.usage = MTLTextureUsageRenderTarget;
// Set the pixel dimensions of the texture
textureDescriptor.width = width * scale;
textureDescriptor.height = height * scale;
// Create the texture from the device by using the descriptor
id<MTLTexture> texture = [_device newTextureWithDescriptor:textureDescriptor];
// Calculate the number of bytes per row in the image.
NSUInteger bytesPerRow = 0;
bytesPerRow = std::ceil((width * scale * 4) + 4);
MTLRegion region = {
{ 0, 0, 0 }, // MTLOrigin
{(NSUInteger)(width * scale), (NSUInteger)(height * scale), 1} // MTLSize
};
// Copy the bytes from the data object into the texture
[texture replaceRegion:region
mipmapLevel:0
withBytes:data
bytesPerRow:bytesPerRow];
return texture;
}
void MetalDrawingPanel::OnSize(wxSizeEvent& ev)
{
if (OPTION(kDispStretch) == false) {
metalView.frame = view.frame;
metalFrame = view.frame;
} else {
float scaleX = view.frame.size.width / (width * scale);
float scaleY = view.frame.size.height / (height * scale);
float scaleF = 0;
if (scaleX < scaleY) {
scaleF = scaleX;
} else {
scaleF = scaleY;
}
if (scaleF == 0) {
scaleF = 1;
}
metalFrame.size.width = (width * scale) * scaleF;
metalFrame.size.height = (height * scale) * scaleF;
metalFrame.origin.x = (view.frame.size.width - metalFrame.size.width) / 2;
metalFrame.origin.y = (view.frame.size.height - metalFrame.size.height) / 2;
metalView.frame = metalFrame;
}
metalView.drawableSize = metalFrame.size;
((CAMetalLayer *)metalView.layer).drawableSize = metalFrame.size;
_contentSize.x = metalFrame.size.width;
_contentSize.y = metalFrame.size.height;
_viewportSize.x = width * scale;
_viewportSize.y = height * scale;
if (todraw) {
DrawArea();
}
ev.Skip();
}
void MetalDrawingPanel::DrawArea(wxWindowDC& dc)
{
(void)dc;
DrawArea();
}
void MetalDrawingPanel::DrawArea()
{
uint32_t srcPitch = 0;
if (!did_init)
DrawingPanelInit();
if (systemColorDepth == 8) {
srcPitch = std::ceil(width * scale) + 2;
} else if (systemColorDepth == 16) {
srcPitch = std::ceil(width * scale * 2) + 4;
} else if (systemColorDepth == 24) {
srcPitch = std::ceil(width * scale * 3);
} else {
srcPitch = std::ceil(width * scale * 4) + 4;
}
if (systemColorDepth == 8) {
int pos = 0;
int src_pos = 0;
uint8_t *src = todraw + srcPitch;
uint32_t *dst = (uint32_t *)calloc(4, std::ceil((width * scale) * (height * scale) + 1));
for (int y = 0; y < (height * scale); y++) {
for (int x = 0; x < (width * scale); x++) {
#if wxBYTE_ORDER == wxLITTLE_ENDIAN
if (src[src_pos] == 0xff) {
dst[pos] = 0x00ffffff;
} else {
dst[pos] = (src[src_pos] & 0xe0) + ((src[src_pos] & 0x1c) << 11) + ((src[src_pos] & 0x3) << 22);
}
#else
if (src[src_pos] == 0xff) {
dst[pos] = 0xffffff00;
} else {
dst[pos] = ((src[src_pos] & 0xe0) << 24) + ((src[src_pos] & 0x1c) << 19) + ((src[src_pos] & 0x3) << 14);
}
#endif
pos++;
src_pos++;
}
pos++;
src_pos += 2;
}
_texture = loadTextureUsingData(dst);
if (dst != NULL) {
free(dst);
}
} else if (systemColorDepth == 16) {
int pos = 0;
int src_pos = 0;
uint8_t *src = todraw + srcPitch;
uint32_t *dst = (uint32_t *)calloc(4, std::ceil((width * scale) * (height * scale) + 1));
uint16_t *src16 = (uint16_t *)src;
for (int y = 0; y < (height * scale); y++) {
for (int x = 0; x < (width * scale); x++) {
#if wxBYTE_ORDER == wxLITTLE_ENDIAN
if (src16[src_pos] == 0x7fff) {
dst[pos] = 0x00ffffff;
} else {
dst[pos] = ((src16[src_pos] & 0x7c00) >> 7) + ((src16[src_pos] & 0x03e0) << 6) + ((src16[src_pos] & 0x1f) << 19);
}
#else
if (src16[src_pos] == 0x7fff) {
dst[pos] = 0xffffff00;
} else {
dst[pos] = ((src16[src_pos] & 0x7c00) << 17) + ((src16[src_pos] & 0x03e0) << 14) + ((src16[src_pos] & 0x1f) << 11);
}
#endif
pos++;
src_pos++;
}
pos++;
src_pos += 2;
}
_texture = loadTextureUsingData(dst);
if (dst != NULL) {
free(dst);
}
} else if (systemColorDepth == 24) {
int pos = 0;
int src_pos = 0;
uint8_t *src = todraw + srcPitch;
uint8_t *dst = (uint8_t *)calloc(4, std::ceil((width * scale) * (height * scale) + 1));
for (int y = 0; y < (height * scale); y++) {
for (int x = 0; x < (width * scale); x++) {
dst[pos] = src[src_pos];
dst[pos+1] = src[src_pos+1];
dst[pos+2] = src[src_pos+2];
dst[pos+3] = 0;
pos += 4;
src_pos += 3;
}
pos += 4;
}
_texture = loadTextureUsingData(dst);
if (dst != NULL) {
free(dst);
}
} else {
_texture = loadTextureUsingData(todraw + srcPitch);
}
// Create a new command buffer for each render pass to the current drawable
commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = @"MyCommand";
// Obtain a renderPassDescriptor
renderPassDescriptor = [metalView currentRenderPassDescriptor];
if(renderPassDescriptor != nil)
{
renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
renderEncoder.label = @"MyRenderEncoder";
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, (double)(_contentSize.x), (double)(_contentSize.y), 0.0, 1.0 }];
[renderEncoder setRenderPipelineState:_pipelineState];
[renderEncoder setVertexBuffer:_vertices
offset:0
atIndex:AAPLVertexInputIndexVertices];
[renderEncoder setVertexBytes:&_viewportSize
length:sizeof(_viewportSize)
atIndex:AAPLVertexInputIndexViewportSize];
// Set the texture object. The AAPLTextureIndexBaseColor enum value corresponds
/// to the 'colorMap' argument in the 'samplingShader' function because its
// texture attribute qualifier also uses AAPLTextureIndexBaseColor for its index.
[renderEncoder setFragmentTexture:_texture
atIndex:AAPLTextureIndexBaseColor];
// Draw the triangles.
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:_numVertices];
[renderEncoder endEncoding];
// Schedule a present once the framebuffer is complete using the next drawable
[commandBuffer presentDrawable:metalView.currentDrawable];
}
// Finalize rendering here & push the command buffer to the GPU
[commandBuffer commit];
}
#endif
Quartz2DDrawingPanel::Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height) Quartz2DDrawingPanel::Quartz2DDrawingPanel(wxWindow* parent, int _width, int _height)
: BasicDrawingPanel(parent, _width, _height) : BasicDrawingPanel(parent, _width, _height)
{ {
@ -14,8 +416,7 @@ Quartz2DDrawingPanel::Quartz2DDrawingPanel(wxWindow* parent, int _width, int _he
void Quartz2DDrawingPanel::DrawImage(wxWindowDC& dc, wxImage* im) void Quartz2DDrawingPanel::DrawImage(wxWindowDC& dc, wxImage* im)
{ {
NSView* view = (NSView*)(GetWindow()->GetHandle()); NSView *view = (NSView *)GetWindow()->GetHandle();
size_t w = std::ceil(width * scale); size_t w = std::ceil(width * scale);
size_t h = std::ceil(height * scale); size_t h = std::ceil(height * scale);
size_t size = w * h * 3; size_t size = w * h * 3;
@ -23,18 +424,19 @@ void Quartz2DDrawingPanel::DrawImage(wxWindowDC& dc, wxImage* im)
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, im->GetData(), size, NULL); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, im->GetData(), size, NULL);
CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGImageRef image = nil;
CGImageRef image = CGImageCreate( image = CGImageCreate(w, h, 8, 24, w * 3, color_space, kCGBitmapByteOrderDefault,
w, h, 8, 24, w * 3, color_space, provider, NULL, true, kCGRenderingIntentDefault);
kCGBitmapByteOrderDefault,
provider, NULL, true, kCGRenderingIntentDefault
);
// draw the image // draw the image
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
#else
[view lockFocus]; [view lockFocus];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
#endif
CGContextSaveGState(context); CGContextSaveGState(context);
@ -59,7 +461,11 @@ void Quartz2DDrawingPanel::DrawImage(wxWindowDC& dc, wxImage* im)
dc.DrawRectangle(w-2, h-2, w, h); dc.DrawRectangle(w-2, h-2, w, h);
} }
[view setNeedsDisplay:YES];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
[view unlockFocus]; [view unlockFocus];
#endif
// and release everything // and release everything

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,12 @@
#include <wx/generic/prntdlgg.h> #include <wx/generic/prntdlgg.h>
#include <wx/print.h> #include <wx/print.h>
#include <wx/printdlg.h> #include <wx/printdlg.h>
#ifdef ENABLE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "core/base/image_util.h" #include "core/base/image_util.h"
#include "core/gb/gbGlobals.h" #include "core/gb/gbGlobals.h"
@ -24,6 +29,7 @@ int systemRedShift;
int systemGreenShift; int systemGreenShift;
int systemBlueShift; int systemBlueShift;
int systemColorDepth; int systemColorDepth;
uint8_t systemColorMap8[0x10000];
uint16_t systemColorMap16[0x10000]; uint16_t systemColorMap16[0x10000];
uint32_t systemColorMap32[0x10000]; uint32_t systemColorMap32[0x10000];
#define gs555(x) (x | (x << 5) | (x << 10)) #define gs555(x) (x | (x << 5) | (x << 10))

View File

@ -331,7 +331,7 @@ public:
for (int i = 0; i < dis->nlines; i++) { for (int i = 0; i < dis->nlines; i++) {
dis->addrs.push_back(addr); dis->addrs.push_back(addr);
addr += gbDis(buf, addr); addr += gbDis(buf, sizeof(buf), addr);
dis->strings.push_back(wxString(buf, wxConvLibc)); dis->strings.push_back(wxString(buf, wxConvLibc));
} }

View File

@ -5,7 +5,11 @@
#include <wx/timer.h> #include <wx/timer.h>
#include <wx/toplevel.h> #include <wx/toplevel.h>
#ifdef ENABLE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "core/base/check.h" #include "core/base/check.h"
#include "wx/config/option-id.h" #include "wx/config/option-id.h"
@ -107,7 +111,11 @@ private:
SDL_JoystickID joystick_id_; SDL_JoystickID joystick_id_;
// The SDL GameController instance. // The SDL GameController instance.
#ifndef ENABLE_SDL3
SDL_GameController* game_controller_ = nullptr; SDL_GameController* game_controller_ = nullptr;
#else
SDL_Gamepad* game_controller_ = nullptr;
#endif
// The SDL Joystick instance. // The SDL Joystick instance.
SDL_Joystick* sdl_joystick_ = nullptr; SDL_Joystick* sdl_joystick_ = nullptr;
@ -126,6 +134,7 @@ private:
}; };
JoyState::JoyState(bool enable_game_controller, int sdl_index) : wx_joystick_(sdl_index) { JoyState::JoyState(bool enable_game_controller, int sdl_index) : wx_joystick_(sdl_index) {
#ifndef ENABLE_SDL3
if (enable_game_controller && SDL_IsGameController(sdl_index)) { if (enable_game_controller && SDL_IsGameController(sdl_index)) {
game_controller_ = SDL_GameControllerOpen(sdl_index); game_controller_ = SDL_GameControllerOpen(sdl_index);
if (game_controller_) if (game_controller_)
@ -133,11 +142,30 @@ JoyState::JoyState(bool enable_game_controller, int sdl_index) : wx_joystick_(sd
} else { } else {
sdl_joystick_ = SDL_JoystickOpen(sdl_index); sdl_joystick_ = SDL_JoystickOpen(sdl_index);
} }
#else
int nrgamepads = 0;
int nrjoysticks = 0;
SDL_JoystickID *gamepads = SDL_GetGamepads(&nrgamepads);
SDL_JoystickID *joysticks = SDL_GetJoysticks(&nrjoysticks);
if (enable_game_controller && SDL_IsGamepad(gamepads[sdl_index])) {
game_controller_ = SDL_OpenGamepad(gamepads[sdl_index]);
if (game_controller_)
{
sdl_joystick_ = SDL_GetGamepadJoystick(game_controller_);
}
} else {
sdl_joystick_ = SDL_OpenJoystick(joysticks[sdl_index]);
}
#endif
if (!sdl_joystick_) if (!sdl_joystick_)
return; return;
#ifndef ENABLE_SDL3
joystick_id_ = SDL_JoystickInstanceID(sdl_joystick_); joystick_id_ = SDL_JoystickInstanceID(sdl_joystick_);
#else
joystick_id_ = SDL_GetJoystickID(sdl_joystick_);
#endif
} }
JoyState::~JoyState() { JoyState::~JoyState() {
@ -145,11 +173,19 @@ JoyState::~JoyState() {
if (!sdl_joystick_) if (!sdl_joystick_)
return; return;
#ifndef ENABLE_SDL3
if (game_controller_) { if (game_controller_) {
SDL_GameControllerClose(game_controller_); SDL_GameControllerClose(game_controller_);
} else { } else {
SDL_JoystickClose(sdl_joystick_); SDL_JoystickClose(sdl_joystick_);
} }
#else
if (game_controller_) {
SDL_CloseGamepad(game_controller_);
} else {
SDL_CloseJoystick(sdl_joystick_);
}
#endif
} }
JoyState::JoyState(JoyState&& other) : wx_joystick_(other.wx_joystick_) { JoyState::JoyState(JoyState&& other) : wx_joystick_(other.wx_joystick_) {
@ -280,7 +316,20 @@ std::vector<UserInputEvent::Data> JoyState::ProcessHatEvent(const uint8_t index,
void JoyState::SetRumble(bool activate_rumble) { void JoyState::SetRumble(bool activate_rumble) {
rumbling_ = activate_rumble; rumbling_ = activate_rumble;
#if SDL_VERSION_ATLEAST(2, 0, 9) #ifdef ENABLE_SDL3
if (game_controller_ == NULL)
return;
if (rumbling_) {
SDL_RumbleGamepad(game_controller_, 0xFFFF, 0xFFFF, 300);
if (!IsRunning()) {
Start(150);
}
} else {
SDL_RumbleGamepad(game_controller_, 0, 0, 0);
Stop();
}
#elif SDL_VERSION_ATLEAST(2, 0, 9)
if (!game_controller_) if (!game_controller_)
return; return;
@ -309,16 +358,30 @@ SdlPoller::SdlPoller(EventHandlerProvider* const handler_provider)
VBAM_CHECK(handler_provider); VBAM_CHECK(handler_provider);
wxTimer::Start(50); wxTimer::Start(50);
#ifndef ENABLE_SDL3
SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS); SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS);
SDL_GameControllerEventState(SDL_ENABLE); SDL_GameControllerEventState(SDL_ENABLE);
SDL_JoystickEventState(SDL_ENABLE); SDL_JoystickEventState(SDL_ENABLE);
#else
SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS);
SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS);
SDL_SetGamepadEventsEnabled(true);
SDL_SetJoystickEventsEnabled(true);
#endif
} }
SdlPoller::~SdlPoller() { SdlPoller::~SdlPoller() {
wxTimer::Stop(); wxTimer::Stop();
#ifndef ENABLE_SDL3
SDL_QuitSubSystem(SDL_INIT_EVENTS); SDL_QuitSubSystem(SDL_INIT_EVENTS);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK); SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
#else
SDL_QuitSubSystem(SDL_INIT_EVENTS);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
#endif
SDL_Quit(); SDL_Quit();
} }
@ -348,6 +411,7 @@ void SdlPoller::Notify() {
std::vector<UserInputEvent::Data> event_data; std::vector<UserInputEvent::Data> event_data;
JoyState* joy_state = nullptr; JoyState* joy_state = nullptr;
switch (sdl_event.type) { switch (sdl_event.type) {
#ifndef ENABLE_SDL3
case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONUP:
joy_state = FindJoyState(sdl_event.cbutton.which); joy_state = FindJoyState(sdl_event.cbutton.which);
@ -355,41 +419,86 @@ void SdlPoller::Notify() {
event_data = joy_state->ProcessButtonEvent(sdl_event.cbutton.button, event_data = joy_state->ProcessButtonEvent(sdl_event.cbutton.button,
sdl_event.cbutton.state); sdl_event.cbutton.state);
} }
#else
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
joy_state = FindJoyState(sdl_event.gbutton.which);
if (joy_state) {
event_data = joy_state->ProcessButtonEvent(sdl_event.gbutton.button,
sdl_event.gbutton.down);
}
#endif
break; break;
#ifndef ENABLE_SDL3
case SDL_CONTROLLERAXISMOTION: case SDL_CONTROLLERAXISMOTION:
joy_state = FindJoyState(sdl_event.caxis.which); joy_state = FindJoyState(sdl_event.caxis.which);
if (joy_state) { if (joy_state) {
event_data = joy_state->ProcessAxisEvent( event_data = joy_state->ProcessAxisEvent(
sdl_event.caxis.axis, AxisValueToStatus(sdl_event.caxis.value)); sdl_event.caxis.axis, AxisValueToStatus(sdl_event.caxis.value));
} }
#else
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
joy_state = FindJoyState(sdl_event.gaxis.which);
if (joy_state) {
event_data = joy_state->ProcessAxisEvent(
sdl_event.gaxis.axis, AxisValueToStatus(sdl_event.gaxis.value));
}
#endif
break; break;
#ifndef ENABLE_SDL3
case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED: case SDL_CONTROLLERDEVICEREMOVED:
#else
case SDL_EVENT_GAMEPAD_ADDED:
case SDL_EVENT_GAMEPAD_REMOVED:
#endif
// Do nothing. This will be handled with JOYDEVICEADDED and // Do nothing. This will be handled with JOYDEVICEADDED and
// JOYDEVICEREMOVED events. // JOYDEVICEREMOVED events.
break; break;
// Joystick events for non-GameControllers. // Joystick events for non-GameControllers.
#ifndef ENABLE_SDL3
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
#else
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
#endif
joy_state = FindJoyState(sdl_event.jbutton.which); joy_state = FindJoyState(sdl_event.jbutton.which);
if (joy_state && !joy_state->is_game_controller()) { if (joy_state && !joy_state->is_game_controller()) {
#ifndef ENABLE_SDL3
event_data = joy_state->ProcessButtonEvent(sdl_event.cbutton.button,
sdl_event.cbutton.state);
#else
event_data = joy_state->ProcessButtonEvent(sdl_event.jbutton.button, event_data = joy_state->ProcessButtonEvent(sdl_event.jbutton.button,
sdl_event.jbutton.state); sdl_event.jbutton.down);
#endif
} }
break; break;
#ifndef ENABLE_SDL3
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
#else
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
#endif
joy_state = FindJoyState(sdl_event.jaxis.which); joy_state = FindJoyState(sdl_event.jaxis.which);
if (joy_state && !joy_state->is_game_controller()) { if (joy_state && !joy_state->is_game_controller()) {
event_data = joy_state->ProcessAxisEvent( event_data = joy_state->ProcessAxisEvent(
#ifndef ENABLE_SDL3
sdl_event.caxis.axis, AxisValueToStatus(sdl_event.caxis.value));
#else
sdl_event.jaxis.axis, AxisValueToStatus(sdl_event.jaxis.value)); sdl_event.jaxis.axis, AxisValueToStatus(sdl_event.jaxis.value));
#endif
} }
break; break;
#ifndef ENABLE_SDL3
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
#else
case SDL_EVENT_JOYSTICK_HAT_MOTION:
#endif
joy_state = FindJoyState(sdl_event.jhat.which); joy_state = FindJoyState(sdl_event.jhat.which);
if (joy_state && !joy_state->is_game_controller()) { if (joy_state && !joy_state->is_game_controller()) {
event_data = event_data =
@ -397,12 +506,20 @@ void SdlPoller::Notify() {
} }
break; break;
#ifndef ENABLE_SDL3
case SDL_JOYDEVICEADDED: case SDL_JOYDEVICEADDED:
#else
case SDL_EVENT_JOYSTICK_ADDED:
#endif
// Always remap all controllers. // Always remap all controllers.
RemapControllers(); RemapControllers();
break; break;
#ifndef ENABLE_SDL3
case SDL_JOYDEVICEREMOVED: case SDL_JOYDEVICEREMOVED:
#else
case SDL_EVENT_JOYSTICK_REMOVED:
#endif
joystick_states_.erase(sdl_event.jdevice.which); joystick_states_.erase(sdl_event.jdevice.which);
break; break;
} }
@ -426,11 +543,21 @@ JoyState* SdlPoller::FindJoyState(const SDL_JoystickID& joy_id) {
} }
void SdlPoller::RemapControllers() { void SdlPoller::RemapControllers() {
#ifdef ENABLE_SDL3
int total_joysticks = 0;
SDL_GetJoysticks(&total_joysticks);
#endif
// Clear the current joystick states. // Clear the current joystick states.
joystick_states_.clear(); joystick_states_.clear();
// Reconnect all controllers. // Reconnect all controllers.
#ifndef ENABLE_SDL3
for (int i = 0; i < SDL_NumJoysticks(); ++i) { for (int i = 0; i < SDL_NumJoysticks(); ++i) {
#else
for (int i = 0; i < total_joysticks; ++i) {
#endif
JoyState joy_state(enable_game_controller_, i); JoyState joy_state(enable_game_controller_, i);
if (joy_state.IsValid()) { if (joy_state.IsValid()) {
joystick_states_.insert({joy_state.joystick_id(), std::move(joy_state)}); joystick_states_.insert({joy_state.joystick_id(), std::move(joy_state)});

Some files were not shown because too many files have changed in this diff Show More