Compare commits

...

81 Commits

Author SHA1 Message Date
Brad Smith
ede668b712 Fixes for BSD build
- patch fixes for BSD handling
- OpenBSD/aarch64 has elf_aux_info()
- unrar build fix for FreeBSD/NetBSD/OpenBSD
- OpenBSD does not have librt

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-25 15:05:32 +00:00
Rafael Kitover
5bd8904746 build: fix check for SDL3 pixel art filter
Fix the CMake compile check for SDL_SCALEMODE_PIXELART to use
CheckSourceCompiles instead of CheckSymbolExists which does not work for
this purpose.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-21 19:33:29 +00:00
Rafael Kitover
46326939eb translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-19 05:00:21 +00:00
Brad Smith
3f005837dd Rename swap16/swap32 functions which conflict with OpenBSD macros 2025-09-19 01:28:30 +00:00
Rafael Kitover
2b3edb266a translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 14:00:23 +00:00
Rafael Kitover
8e5fc43dd6 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 13:00:23 +00:00
Rafael Kitover
362ca53cbe translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 02:00:23 +00:00
Rafael Kitover
9dc10ff6c4 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 02:00:07 +00:00
Rafael Kitover
ab01be3373 Add option to enable SDL pixel art texture filter
Add a checkbox in display config to enable SDL_SCALEMODE_PIXELART when
it is available.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 01:22:47 +00:00
Rafael Kitover
6ec0ba0610 Apply bilinear option for SDL texture
Set the texture option for bilinear or nearest on the SDL texture
depending on the value of the bilinear checkbox.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-18 01:22:47 +00:00
Rafael Kitover
9fcc0ad7a8 build: fix finding static vcpkg x265 for FFmpeg
Fix finding static vcpkg x265 when it is named `x265-static.lib` as it
is right now.

Fix finding vcpkg host pkgconf on ARM64 Windows, which uses x64 host
binaries.

Remove build environment architecture check, which fails building x64 on
ARM64. That whole file needs to be rewritten to use the compiler target
architecture.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-13 20:59:08 -07:00
Rafael Kitover
32622efc1e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-11 11:00:20 +00:00
Rafael Kitover
1dd5ba4567 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-04 08:00:21 +00:00
Rafael Kitover
2070f75934 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-03 18:00:30 +00:00
Rafael Kitover
89146a8597 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-09-03 17:00:21 +00:00
Rafael Kitover
043956753b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-30 15:00:20 +00:00
Rafael Kitover
e0eb3b3dab translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-30 08:00:21 +00:00
Rafael Kitover
e3e14232f7 Set gba_darken opt default to 37
Set the GBA darken value default to 37 instead of 50, seems to look
pretty good.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-28 04:23:51 +00:00
Squall Leonhart
7565cac230 Update 2xSaI.cpp
The previous interpolation operator could cause the channels to bleed into the next when the LCD Color filter was enabled, on some starts, some settings.
2025-08-25 17:41:04 +10:00
Rafael Kitover
33c5aeb80e Default LCD Filter to enabled for GBA/GB
Set the defaults for GB and GBA LCD Filter to enabled and rewrite the
values in previous versions of the config to enabled as well.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-24 02:49:59 +00:00
Rafael Kitover
c5510ba28f ci: update install-nix-action to v31
Update the GitHub CI action install-nix-action to v31 and remove
references to apple_sdk from default.nix, they have been deprecated.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 22:04:19 +00:00
Rafael Kitover
96c23628ba Set default for gba_darken to 50
Set the default for the color correction option gba_darken to 50, which
is the nicest looking value.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 16:39:22 +00:00
Rafael Kitover
37fb449fc9 Remove gbafilter_pad/gbcfilter_pad, dead code
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 16:35:06 +00:00
Rafael Kitover
7519c9b818 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 01:00:20 +00:00
Rafael Kitover
24b779c09e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-23 00:00:20 +00:00
Rafael Kitover
a17df26e52 build: fix Debian installdeps for current Ubuntu
Fix installdeps for Debian variants by checking for `libsdl3-dev` and
falling back to `libsdl2-dev` if not available.

Also add `libx264-dev` and `libx265-dev` to the list of FFmpeg packages
as we now require them.

Fix #1486

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-21 22:53:33 +00:00
Rafael Kitover
b2dd03c6cb build: guard cmake_policy() w if(POLICY)
Check if CMake policies being set exist to prevent errors on older CMake
versions.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-21 20:49:32 +00:00
Andy Vandijck
967426e2f0 Fix color change with previous check 2025-08-21 09:17:54 +02:00
Rafael Kitover
ee2678c13c translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-20 20:00:20 +00:00
Rafael Kitover
337e465741 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-20 19:00:19 +00:00
Andy Vandijck
5007977189 Add capital begin letter 2025-08-20 16:36:27 +02:00
Andy Vandijck
99f97138a2 Add LCD filter parameters and add GBC filter 2025-08-20 16:31:05 +02:00
Andy Vandijck
5b867c1483 Fix color name 2025-08-19 15:27:37 +02:00
Andy Vandijck
fe08f4d326 Remove quoted code 2025-08-19 15:26:12 +02:00
Andy Vandijck
c334e3ffca Fix PS2 colors for libretro 2025-08-19 15:20:49 +02:00
Andy Vandijck
35f8ba0b8f Add libretro PlayStation2 support 2025-08-18 16:12:29 +02:00
Andy Vandijck
fca5fae329 Check file size for GBA ROM and reduce memory footprint 2025-08-17 16:02:26 +02:00
Andy Vandijck
56ea6456f5 Check file size for GBA ROM and reduce memory footprint 2025-08-17 16:01:20 +02:00
Rafael Kitover
0510656ca3 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-13 00:00:20 +00:00
Squall-Leonhart
b92fcf7e31 prevent the zip program from being incompletely downloaded
\
2025-08-11 14:41:19 +00:00
Andy Vandijck
22f381a19e Update macOS SDL3 to 3.2.20 2025-08-08 10:01:06 +02:00
Andy Vandijck
e9fc6c8e13 Update macOS SDL3 to 3.2.20 2025-08-08 10:00:04 +02:00
Rafael Kitover
bd20c79013 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-07 10:00:21 +00:00
Andy Vandijck
203be42665 Fix typo 2025-08-07 11:45:40 +02:00
Andy Vandijck
d75072009b Set params when no image is loaded 2025-08-07 11:39:59 +02:00
Andy Vandijck
0e32b90002 Fix LCD color filter 2025-08-07 10:45:11 +02:00
Rafael Kitover
2640716496 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-07 07:00:20 +00:00
Rafael Kitover
b065db66d9 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-06 10:00:20 +00:00
Rafael Kitover
4d837fd739 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 21:00:19 +00:00
Rafael Kitover
1ef356c6f0 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 08:00:23 +00:00
Rafael Kitover
a8c82bb4a1 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 08:00:07 +00:00
Rafael Kitover
1778d605f4 Add config for color correction
Add display config dialog and config file options for GBA and GBC color
correction.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-05 07:29:50 +00:00
Rafael Kitover
d6d2a83e7e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 15:00:19 +00:00
Rafael Kitover
881667a5f8 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 13:00:24 +00:00
Rafael Kitover
b332aa693d translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 13:00:07 +00:00
Rafael Kitover
7f7035a07b translations: finish removing German
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 12:01:47 +00:00
Rafael Kitover
3e355509e9 build: restore FindFFmpeg.cmake
Restore `FindFFmpeg.cmake`, because FFmpeg does not come with CMake
import modules.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-04 11:56:18 +00:00
Rafael Kitover
e68681ffda translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-03 15:00:19 +00:00
Andy Vandijck
f83aa940d7 Fix GB reset
Fix GB reset
2025-08-03 13:27:26 +02:00
Andy Vandijck
a18559678c Fix MS compile
Fix MS compile
2025-08-03 13:09:59 +02:00
Andy Vandijck
d927594af2 Fix MS compile
Fix MS compile
2025-08-03 13:06:32 +02:00
Andy Vandijck
06507775e8 Replace nullptr with NULL
Replace nullptr with NULL
2025-08-03 11:52:14 +02:00
Andy Vandijck
b08ecd123d Fix libretro 24 bit color
Fix libretro 24 bit color
2025-08-03 10:44:43 +02:00
Andy Vandijck
d154a6abc8 Add games app category for macOS (optimisations)
Add games app category for macOS (optimisations)
2025-08-03 10:33:47 +02:00
Andy Vandijck
b134bacc45 Fix SDL audio on Windows
Fix SDL audio on Windows
2025-08-03 10:08:27 +02:00
Andy Vandijck
9ae1473f36 Fix 8 bit PNG recording
Fix 8 bit PNG recording
2025-08-02 11:27:21 +02:00
Andy Vandijck
9cd0c5c04c Fix 8 bit video recording
Fix 8 bit video recording
2025-08-02 11:10:00 +02:00
Andy Vandijck
9e41c5476a Fix 8 bit color
Fix 8 bit color
2025-08-02 10:20:05 +02:00
Andy Vandijck
e91171459d Fix policy in newer CMake 2025-08-02 09:49:22 +02:00
Andy Vandijck
16f008b448 Fix macOS build
Fix macOS build
2025-08-02 09:38:42 +02:00
Rafael Kitover
bad10342bd build: use pkg-config on UNIX for SDL3
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-02 06:20:37 +00:00
Squall Leonhart
06b3cb094e Merge pull request #1484 from Squall-Leonhart/Correct24bit
24bit was prone to corrupting g_pix on all renderers
2025-08-02 07:50:07 +10:00
Squall-Leonhart
82617ea75d correct memory alignment 2025-08-02 07:48:03 +10:00
Andy Vandijck
0561ef91a4 Fix CoreAudio stall
Fix CoreAudio stall
2025-08-01 09:48:58 +02:00
Rafael Kitover
afc6a1cc3a build: fix build, de translation removed
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 04:40:38 +00:00
Rafael Kitover
35df9d7647 translations: remove German, not German
Remove the `de` translation as it does not contain a German translation.
Also deleted from Transifex.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 03:10:01 +00:00
Rafael Kitover
031ae2ebf6 build: fix CMake slowness
Optimize the `find_wx_util` function to try the major and minor version
parsed from the lib file first, avoiding a very slow exhaustive search
of possible version numbers.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-08-01 03:05:55 +00:00
Squall Leonhart
6242679e23 initialise stereo_buffer to 0 to prevent a race condition 2025-08-01 12:12:44 +10:00
Rafael Kitover
537393a0ab translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-31 16:00:20 +00:00
Rafael Kitover
616f7abc4e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-31 13:00:21 +00:00
Rafael Kitover
f1414000e6 doc: fix release commit instructions
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2025-07-30 11:49:27 +00:00
114 changed files with 11481 additions and 13111 deletions

View File

@@ -36,7 +36,7 @@ jobs:
with:
submodules: recursive
- name: Install nix
uses: cachix/install-nix-action@v22
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable

View File

@@ -1,6 +1,17 @@
cmake_minimum_required(VERSION 3.19)
cmake_policy(VERSION 3.19...3.28.3)
# Use new link library de-duplication behavior.
if(POLICY CMP0156)
cmake_policy(SET CMP0156 NEW)
endif()
if(POLICY CMP0179)
cmake_policy(SET CMP0179 NEW)
endif()
#if(POLICY CMP0181)
# cmake_policy(SET CMP0181 NEW)
#endif()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(WIN32)

View File

@@ -2,6 +2,8 @@ if(TRANSLATIONS_ONLY)
return()
endif()
# TODO: Use compiler CPU not CMake.
if(NOT CMAKE_SYSTEM_PROCESSOR)
if(NOT CMAKE_TOOLCHAIN_FILE AND CMAKE_HOST_SYSTEM_PROCESSOR)
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
@@ -71,14 +73,6 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "[aA][aA][rR][cC][hH]|[aA][rR][mM]")
endif()
endif()
if(DEFINED VCPKG_TARGET_TRIPLET)
string(REGEX MATCH "^[^-]+" target_arch ${VCPKG_TARGET_TRIPLET})
if(NOT WINARCH STREQUAL target_arch)
message(FATAL_ERROR "Wrong build environment architecture for VCPKG_TARGET_TRIPLET, you specified ${target_arch} but your compiler is for ${WINARCH}")
endif()
endif()
# We do not support amd64 asm yet
if(X86_64 AND (ENABLE_ASM_CORE OR ENABLE_ASM_SCALERS OR ENABLE_MMX))
message(FATAL_ERROR "The options ASM_CORE, ASM_SCALERS and MMX are not supported on X86_64 yet.")

View File

@@ -48,16 +48,20 @@ if((NOT ENABLE_SDL3) AND CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
endif()
if(ENABLE_SDL3)
if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL3::SDL3-static ${SDL_LIBRARY_TEMP})
if(UNIX AND NOT APPLE)
set(VBAM_SDL_LIBS "${SDL3_LIBRARIES}")
else()
set(VBAM_SDL_LIBS SDL3::SDL3 ${SDL_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()
endif()
else()
if(VBAM_STATIC)
set(VBAM_SDL_LIBS SDL2::SDL2-static ${SDL_LIBRARY_TEMP})
set(VBAM_SDL_LIBS SDL2::SDL2-static ${SDL_LIBRARY_TEMP})
else()
set(VBAM_SDL_LIBS SDL2::SDL2 ${SDL_LIBRARY_TEMP})
set(VBAM_SDL_LIBS SDL2::SDL2 ${SDL_LIBRARY_TEMP})
endif()
endif()

View File

@@ -97,6 +97,11 @@ endmacro()
# Check for cached results. If there are skip the costly part.
if (NOT FFMPEG_LIBRARIES)
set(x265_lib "x265")
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg" AND FFMPEG_STATIC)
set(x265_lib "x265-static")
endif()
# Check for all possible component.
find_component(AVFORMAT libavformat avformat libavformat/avformat.h)
@@ -108,7 +113,7 @@ if (NOT FFMPEG_LIBRARIES)
find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h)
find_component(X264 x264 x264 x264.h)
find_component(X265 x265 x265 x265.h)
find_component(X265 x265 "${x265_lib}" x265.h)
# Check if the required components were found and add their stuff to the FFMPEG_* vars.
foreach (_component ${FFmpeg_FIND_COMPONENTS})

View File

@@ -221,7 +221,7 @@ release notes.
Run the following commands to commit the change:
git commit -m'release ${new_tag}' --signoff -S
git commit -a -m'release ${new_tag}' --signoff -S
git tag -s -m'${new_tag}' ${new_tag}
To rollback these changes, run this command:

View File

@@ -40,15 +40,27 @@ if(VBAM_STATIC)
endif()
endif()
find_package(SDL3 QUIET)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
set(PKG_CONFIG_EXECUTABLE "$ENV{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe")
endif()
find_package(PkgConfig)
if(UNIX AND NOT APPLE)
pkg_check_modules(SDL3 sdl3 QUIET)
else()
find_package(SDL3 QUIET)
endif()
option(ENABLE_SDL3 "Use SDL3" "${SDL3_FOUND}")
if(NOT TRANSLATIONS_ONLY)
if(ENABLE_SDL3)
find_package(SDL3 CONFIG REQUIRED)
if(NOT UNIX)
find_package(SDL3 REQUIRED)
endif()
else()
find_package(SDL2 CONFIG REQUIRED)
find_package(SDL2 REQUIRED)
endif()
endif()
@@ -64,6 +76,18 @@ option(ENABLE_LZMA "Enable LZMA archive support" ON)
if(ENABLE_SDL3)
set(CMAKE_C_FLAGS "-DENABLE_SDL3 ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-DENABLE_SDL3 ${CMAKE_CXX_FLAGS}")
include(CheckSourceCompiles)
check_source_compiles(CXX
"#include <SDL3/SDL.h>
int main() { return SDL_SCALEMODE_PIXELART; }
" HAVE_SDL_SCALEMODE_PIXELART)
if(HAVE_SDL_SCALEMODE_PIXELART)
set(CMAKE_C_FLAGS "-DHAVE_SDL3_PIXELART ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-DHAVE_SDL3_PIXELART ${CMAKE_CXX_FLAGS}")
endif()
endif()
if(DISABLE_OPENGL)
@@ -93,12 +117,6 @@ if(APPLE AND NOT DISABLE_MACOS_PACKAGE_MANAGERS)
include(MacPackageManagers)
endif()
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^([xX]86_64|[aA][mM][dD]64)$")
set(PKG_CONFIG_EXECUTABLE "$ENV{VCPKG_ROOT}/installed/x64-windows/tools/pkgconf/pkgconf.exe")
endif()
find_package(PkgConfig)
# Link / SFML
if(NOT TRANSLATIONS_ONLY)
set(ENABLE_LINK_DEFAULT ON)
@@ -110,31 +128,25 @@ set(FFMPEG_DEFAULT OFF)
set(FFMPEG_COMPONENTS AVFORMAT AVCODEC SWSCALE AVUTIL SWRESAMPLE X264 X265)
set(FFMPEG_COMPONENT_VERSIONS AVFORMAT>=58.12.100 AVCODEC>=58.18.100 SWSCALE>=5.1.100 AVUTIL>=56.14.100 SWRESAMPLE>=3.1.100 X264>=0 X265>=0)
option(FIND_FFMPEG_APPLE "Find using Apple FFMPEG function" OFF)
if(NOT TRANSLATIONS_ONLY AND (NOT DEFINED ENABLE_FFMPEG OR ENABLE_FFMPEG))
set(FFMPEG_DEFAULT ON)
if (APPLE OR FIND_FFMPEG_APPLE)
find_package(AppleFFMPEG COMPONENTS ${FFMPEG_COMPONENTS})
else()
find_package(FFMPEG COMPONENTS ${FFMPEG_COMPONENTS})
endif()
find_package(FFmpeg COMPONENTS ${FFMPEG_COMPONENTS})
# check versions, but only if pkgconfig is available
if(FFMPEG_FOUND AND PKG_CONFIG_FOUND AND NOT CMAKE_TOOLCHAIN_FILE MATCHES vcpkg)
if(FFmpeg_FOUND AND PKG_CONFIG_FOUND AND NOT CMAKE_TOOLCHAIN_FILE MATCHES vcpkg)
foreach(component ${FFMPEG_COMPONENT_VERSIONS})
string(REPLACE ">=" ";" parts ${component})
list(GET parts 0 name)
list(GET parts 1 version)
if((NOT DEFINED ${name}_VERSION) OR ${name}_VERSION VERSION_LESS ${version})
set(FFMPEG_FOUND OFF)
set(FFmpeg_FOUND OFF)
endif()
endforeach()
endif()
if(NOT FFMPEG_FOUND)
if(NOT FFmpeg_FOUND)
set(FFMPEG_DEFAULT OFF)
endif()
endif()

View File

@@ -37,8 +37,48 @@ function(check_clean_exit var)
set(${var} ${exit_status} PARENT_SCOPE)
endfunction()
function(try_wx_util var util conf_suffix major_version minor_version)
unset(suffix)
if(conf_suffix)
set(suffix "-${conf_suffix}")
endif()
if(major_version)
set(suffix "${suffix}-${major_version}")
if(NOT minor_version EQUAL -1)
set(suffix "${suffix}.${minor_version}")
endif()
endif()
# find_program caches the result
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${util}${suffix}")
# try infix variant, as on FreeBSD
if(NOT EXISTS "${exe}")
string(REGEX REPLACE "^-" "" suffix "${suffix}")
string(REGEX REPLACE "-" "${suffix}-" try "${util}")
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${try}")
endif()
if(EXISTS "${exe}")
# check that the utility can be executed cleanly
# in case we find e.g. the wrong architecture binary
# when cross-compiling
check_clean_exit(exit_status "${exe}" --help)
if(exit_status EQUAL 0)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
endif()
endfunction()
function(find_wx_util var util)
if(WIN32 OR EXISTS /etc/gentoo-release)
if((WIN32 AND (NOT CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")) OR EXISTS /etc/gentoo-release)
# On win32, including cross builds we prefer the plain utility
# name first from PATH, with the exception of -static for static
# builds.
@@ -57,48 +97,34 @@ function(find_wx_util var util)
set(major_versions ";")
endif()
list(APPEND conf_suffixes gtk4u gtk4 gtk3u gtk3 gtk2u gtk2 "")
list(APPEND major_versions 4 3 2 "")
list(APPEND conf_suffixes "" gtk3u gtk3 gtk2u gtk2)
list(APPEND major_versions "" 3)
get_target_property(wx_base_lib_prop wx::base LOCATION)
string(STRIP "${wx_base_lib_prop}" wx_base_lib)
if(wx_base_lib MATCHES "wx_baseu?-([0-9]+)\\.([0-9]+)\\.")
set(lib_major "${CMAKE_MATCH_1}")
set(lib_minor "${CMAKE_MATCH_2}")
endif()
foreach(conf_suffix IN LISTS conf_suffixes)
if(lib_major AND lib_minor)
try_wx_util(exe "${util}" "${conf_suffix}" "${lib_major}" "${lib_minor}")
if(exe)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
endif()
foreach(major_version IN LISTS major_versions)
foreach(minor_version RANGE 100 -1 -1)
unset(suffix)
if(conf_suffix)
set(suffix "-${conf_suffix}")
endif()
if(major_version)
set(suffix "${suffix}-${major_version}")
foreach(minor_version RANGE 30 -1 -1)
try_wx_util(exe "${util}" "${conf_suffix}" "${major_version}" "${minor_version}")
if(NOT minor_version EQUAL -1)
set(suffix "${suffix}.${minor_version}")
endif()
endif()
# find_program caches the result
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES "${util}${suffix}")
# try infix variant, as on FreeBSD
if(NOT EXISTS ${exe})
string(REGEX REPLACE "^-" "" suffix "${suffix}")
string(REGEX REPLACE "-" "${suffix}-" try ${util})
set(exe NOTFOUND CACHE INTERNAL "" FORCE)
find_program(exe NAMES ${try})
endif()
if(EXISTS ${exe})
# check that the utility can be executed cleanly
# in case we find e.g. the wrong architecture binary
# when cross-compiling
check_clean_exit(exit_status ${exe} --help)
if(exit_status EQUAL 0)
set(${var} ${exe} PARENT_SCOPE)
return()
endif()
if(exe)
set("${var}" "${exe}" PARENT_SCOPE)
return()
endif()
# don't iterate over minor versions for empty major version

View File

@@ -2,7 +2,7 @@ with import <nixpkgs> {};
stdenv.mkDerivation {
name = "visualboyadvance-m";
buildInputs = if stdenv.isDarwin then
[ ninja cmake nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 sdl3 pcre pcre2 darwin.apple_sdk.frameworks.System darwin.apple_sdk.frameworks.IOKit darwin.apple_sdk.frameworks.Carbon darwin.apple_sdk.frameworks.Cocoa darwin.apple_sdk.frameworks.QuartzCore darwin.apple_sdk.frameworks.AudioToolbox darwin.apple_sdk.frameworks.OpenGL darwin.apple_sdk.frameworks.OpenAL llvmPackages_latest.clang llvmPackages_latest.bintools ]
[ ninja cmake nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 sdl3 pcre pcre2 llvmPackages_latest.clang llvmPackages_latest.bintools ]
else
[ ninja cmake gcc clang llvm llvmPackages.libcxx nasm faudio gettext libintl libtiff pkg-config zip zlib openal ffmpeg wxGTK32 libGL libGLU glfw sdl3 gtk3-x11 pcre pcre2 util-linuxMinimal libselinux libsepol libthai libdatrie xorg.libXdmcp xorg.libXtst libxkbcommon libepoxy dbus at-spi2-core ];
}

View File

@@ -342,9 +342,12 @@ debian_installdeps() {
;;
esac
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl3-dev libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
sdl_lib=$(apt-cache search libsdl3-dev | grep libsdl3-dev | awk '{ print $1 }')
[ -z "$sdl_lib" ] && sdl_lib=libsdl2-dev
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev libx264-dev libx265-dev"
check sudo apt-get -qy install $pkgs
else

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,5 +2,6 @@ add_subdirectory(av_recording)
add_subdirectory(draw_text)
add_subdirectory(filters)
add_subdirectory(filters_agb)
add_subdirectory(filters_cgb)
add_subdirectory(filters_interframe)
add_subdirectory(user_config)

View File

@@ -278,7 +278,7 @@ recording::MediaRet recording::MediaRecorder::setup_video_stream_info(int width,
switch (pixsize)
{
case 1:
tbord = 1; rbord = 2;
tbord = 1; rbord = 4;
break;
case 2:
// 16-bit: 2 @ right, 1 @ top

View File

@@ -26,10 +26,6 @@ extern "C"
bool cpu_mmx = 1;
#endif
}
static uint32_t colorMask = 0xF7DEF7DE;
static uint32_t lowPixelMask = 0x08210821;
static uint32_t qcolorMask = 0xE79CE79C;
static uint32_t qlowpixelMask = 0x18631863;
static uint32_t redblueMask = 0xF81F;
static uint32_t greenMask = 0x7E0;
@@ -41,20 +37,12 @@ int Init_2xSaI(uint32_t BitFormat)
{
if(systemColorDepth == 16) {
if (BitFormat == 565) {
colorMask = 0xF7DEF7DE;
lowPixelMask = 0x08210821;
qcolorMask = 0xE79CE79C;
qlowpixelMask = 0x18631863;
redblueMask = 0xF81F;
greenMask = 0x7E0;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0xF7DEF7DE;
hq2x_init(16);
RGB_LOW_BITS_MASK = 0x0821;
} else if (BitFormat == 555) {
colorMask = 0x7BDE7BDE;
lowPixelMask = 0x04210421;
qcolorMask = 0x739C739C;
qlowpixelMask = 0x0C630C63;
redblueMask = 0x7C1F;
greenMask = 0x3E0;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0x7BDE7BDE;
@@ -64,10 +52,6 @@ int Init_2xSaI(uint32_t BitFormat)
return 0;
}
} else if(systemColorDepth == 32) {
colorMask = 0xfefefe;
lowPixelMask = 0x010101;
qcolorMask = 0xfcfcfc;
qlowpixelMask = 0x030303;
qRGB_COLOR_MASK[0] = qRGB_COLOR_MASK[1] = 0xfefefe;
hq2x_init(32);
RGB_LOW_BITS_MASK = 0x010101;
@@ -146,25 +130,24 @@ static inline int GetResult (uint32_t A, uint32_t B, uint32_t C, uint32_t D)
return r;
}
static inline uint32_t INTERPOLATE (uint32_t A, uint32_t B)
{
if (A != B) {
return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) +
(A & B & lowPixelMask));
} else
return A;
static inline uint32_t INTERPOLATE(uint32_t A, uint32_t B) {
if (A == B) {
return A;
}
return (
(((((A >> 16) & 0xFF) & 0xFE) >> 1) + ((((B >> 16) & 0xFF) & 0xFE) >> 1) + (((A >> 16) & 0xFF) & ((B >> 16) & 0xFF) & 0x01)) << 16) |
((((((A >> 8) & 0xFF) & 0xFE) >> 1) + ((((B >> 8) & 0xFF) & 0xFE) >> 1) + (((A >> 8) & 0xFF) & ((B >> 8) & 0xFF) & 0x01)) << 8) |
(((((A & 0xFF) & 0xFE) >> 1) + (((B & 0xFF) & 0xFE) >> 1) + ((A & 0xFF) & (B & 0xFF) & 0x01)));
}
static inline uint32_t Q_INTERPOLATE (uint32_t A, uint32_t B, uint32_t C, uint32_t D)
{
uint32_t x = ((A & qcolorMask) >> 2) +
((B & qcolorMask) >> 2) +
((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
uint32_t y = (A & qlowpixelMask) +
(B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask);
y = (y >> 2) & qlowpixelMask;
return x + y;
static inline uint32_t Q_INTERPOLATE(uint32_t A, uint32_t B, uint32_t C, uint32_t D) {
return (
(((((A >> 16) & 0xFC) >> 2) + (((B >> 16) & 0xFC) >> 2) + (((C >> 16) & 0xFC) >> 2) + (((D >> 16) & 0xFC) >> 2) +
(((A >> 16) & 0x03) + ((B >> 16) & 0x03) + ((C >> 16) & 0x03) + ((D >> 16) & 0x03))) << 16) |
(((((A >> 8) & 0xFC) >> 2) + (((B >> 8) & 0xFC) >> 2) + (((C >> 8) & 0xFC) >> 2) + (((D >> 8) & 0xFC) >> 2) +
(((A >> 8) & 0x03) + ((B >> 8) & 0x03) + ((C >> 8) & 0x03) + ((D >> 8) & 0x03))) << 8) |
((((A & 0xFC) >> 2) + ((B & 0xFC) >> 2) + ((C & 0xFC) >> 2) + ((D & 0xFC) >> 2) +
((A & 0x03) + (B & 0x03) + (C & 0x03) + (D & 0x03)))));
}
static inline int GetResult1_32 (uint32_t A, uint32_t B, uint32_t C, uint32_t D,
@@ -1275,4 +1258,3 @@ void Scale_2xSaI (uint8_t *srcPtr, uint32_t srcPitch, uint8_t * /* deltaPtr */,
dstPtr += dstPitch;
}
}

View File

@@ -1,4 +1,17 @@
/*
* GBA Color Correction Shader Implementation
*
* Shader modified by Pokefan531.
* Color Mangler
* Original Author: hunterk
* Original License: Public domain
*
* This code is adapted from the original shader logic.
*/
#include "components/filters_agb/filters_agb.h"
#include <cmath>
#include <algorithm>
extern int systemColorDepth;
extern int systemRedShift;
@@ -9,272 +22,332 @@ extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000];
static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12,
0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80,
0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0 };
// --- Global Constants and Variables for GBA Color Correction ---
// Define the color profile matrix as a static const float 2D array
// This replicates the column-major order of GLSL mat4 for easier translation.
// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... }
static const float GBA_sRGB[4][4] = {
{0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A)
{0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A)
{-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A)
{0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution)
};
// output R G B
static const unsigned char influence[3 * 3] = { 16, 4, 4, // red
8, 16, 8, // green
0, 8, 16 }; // blue
static const float GBA_DCI[4][4] = {
{0.76f, 0.125f, 0.16f, 0.0f},
{0.27f, 0.6375f, 0.18f, 0.0f},
{-0.03f, 0.2375f, 0.66f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.97f}
};
inline void swap(short& a, short& b)
{
short temp = a;
a = b;
b = temp;
static const float GBA_Rec2020[4][4] = {
{0.61f, 0.155f, 0.16f, 0.0f},
{0.345f, 0.615f, 0.1875f, 0.0f},
{0.045f, 0.23f, 0.6525f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
};
// Screen darkening factor. Default to 0.0f
static float darken_screen = 0.0f;
// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0).
static int color_mode = 0;
// Pointer to the currently selected color profile matrix.
static const float (*profile)[4];
// Global constants from the shader for gamma correction values
static const float target_gamma = 2.2f;
static const float display_gamma = 2.2f;
// --- Function Implementations ---
// Forward declaration of a helper function to set the profile based on color_mode
static void set_profile_from_mode();
// This constructor-like function runs once when the program starts.
struct GbafilterInitializer {
GbafilterInitializer() {
set_profile_from_mode();
}
};
static GbafilterInitializer __gbafilter_initializer;
// Helper function to set the 'profile' pointer based on the 'color_mode' variable.
static void set_profile_from_mode() {
if (color_mode == 0) {
profile = GBA_sRGB;
}
else if (color_mode == 1) {
profile = GBA_DCI;
}
else if (color_mode == 2) {
profile = GBA_Rec2020;
}
else {
profile = GBA_sRGB; // Default to sRGB if an invalid mode is set
}
}
// Public function to set color mode and darken screen from external calls
void gbafilter_set_params(int new_color_mode, float new_darken_screen) {
color_mode = new_color_mode;
darken_screen = fmaxf(0.0f, fminf(1.0f, new_darken_screen)); // Clamp to 0.0-1.0
// Call the helper to update 'profile' based on the new 'color_mode'
set_profile_from_mode();
}
void gbafilter_update_colors(bool lcd) {
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: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal32(systemColorMap32, 0x10000);
} break;
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));
}
if (lcd)
gbafilter_pal8(systemColorMap8, 0x10000);
} break;
case 16: {
for (int i = 0x0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbafilter_pal32(systemColorMap32, 0x10000);
} break;
}
}
void gbafilter_pal8(uint8_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint8_t pix = *buf;
uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5);
uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2);
uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_3bit / 7.0f;
float g = (float)original_g_val_3bit / 7.0f;
float b = (float)original_b_val_2bit / 3.0f;
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f);
// Ensure values are strictly within 0-7 or 0-3 range after rounding
if (final_red > 7) final_red = 7;
if (final_green > 7) final_green = 7;
if (final_blue > 3) final_blue = 3;
*buf++ = ((final_red & 0x7) << 5) |
((final_green & 0x7) << 2) |
(final_blue & 0x3);
}
}
void gbafilter_pal(uint16_t* buf, int count)
{
short temp[3 * 3], s;
uint16_t pix;
uint8_t red, green, blue;
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
pix = *buf;
uint16_t pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
if (temp[0] < temp[3])
swap(temp[0], temp[3]);
if (temp[0] < temp[6])
swap(temp[0], temp[6]);
if (temp[3] < temp[6])
swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
red = ((int(temp[0]) * 160) >> 17) + 4;
if (red > 31)
red = 31;
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
if (temp[2] < temp[5])
swap(temp[2], temp[5]);
if (temp[2] < temp[8])
swap(temp[2], temp[8]);
if (temp[5] < temp[8])
swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
blue = ((int(temp[2]) * 160) >> 17) + 4;
if (blue > 31)
blue = 31;
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
if (temp[1] < temp[4])
swap(temp[1], temp[4]);
if (temp[1] < temp[7])
swap(temp[1], temp[7]);
if (temp[4] < temp[7])
swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
// Convert back to 5-bit (0-31) integer and combine into uint16_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f);
green = ((int(temp[1]) * 160) >> 17) + 4;
if (green > 31)
green = 31;
// Ensure values are strictly within 0-31 range after rounding
if (final_red > 31) final_red = 31;
if (final_green > 31) final_green = 31;
if (final_blue > 31) final_blue = 31;
pix = red << systemRedShift;
pix += green << systemGreenShift;
pix += blue << systemBlueShift;
*buf++ = pix;
*buf++ = (final_red << systemRedShift) |
(final_green << systemGreenShift) |
(final_blue << systemBlueShift);
}
}
void gbafilter_pal32(uint32_t* buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
uint8_t red, green, blue;
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + darken_screen;
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
pix = *buf;
uint32_t pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
// Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel.
// These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red).
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
if (temp[0] < temp[3])
swap(temp[0], temp[3]);
if (temp[0] < temp[6])
swap(temp[0], temp[6]);
if (temp[3] < temp[6])
swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
// 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
//red = ((int(temp[0]) * 160) >> 17) + 4;
red = ((int(temp[0]) * 160) >> 14) + 32;
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
if (temp[2] < temp[5])
swap(temp[2], temp[5]);
if (temp[2] < temp[8])
swap(temp[2], temp[8]);
if (temp[5] < temp[8])
swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
// 3. Apply color profile matrix
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
//blue = ((int(temp[2]) * 160) >> 17) + 4;
blue = ((int(temp[2]) * 160) >> 14) + 32;
// 4. Apply display gamma.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
if (temp[1] < temp[4])
swap(temp[1], temp[4]);
if (temp[1] < temp[7])
swap(temp[1], temp[7]);
if (temp[4] < temp[7])
swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
//green = ((int(temp[1]) * 160) >> 17) + 4;
green = ((int(temp[1]) * 160) >> 14) + 32;
//pix = red << redshift;
//pix += green << greenshift;
//pix += blue << blueshift;
// Convert the floating-point values to 8-bit integer components (0-255).
uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f);
uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f);
uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f);
pix = red << (systemRedShift - 3);
pix += green << (systemGreenShift - 3);
pix += blue << (systemBlueShift - 3);
// Ensure values are strictly within 0-255 range after rounding
if (final_red_8bit > 255) final_red_8bit = 255;
if (final_green_8bit > 255) final_green_8bit = 255;
if (final_blue_8bit > 255) final_blue_8bit = 255;
*buf++ = pix;
}
}
// --- NEW PACKING LOGIC ---
// This is the critical change to correctly map 8-bit color to the 5-bit shifted format,
// while allowing FFFFFF.
// It uses the top 5 bits of the 8-bit value for the GBA's 5-bit component position,
// and the bottom 3 bits to fill the lower, normally zeroed, positions.
// for palette mode to work with the three spoony filters in 32bpp depth
uint32_t final_pix = 0;
void gbafilter_pad(uint8_t* buf, int count)
{
union {
struct
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
} part;
unsigned whole;
} mask;
// Red component
// 5 most significant bits (MSBs) for the 'systemRedShift' position
final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift;
// 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3)
final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3);
mask.whole = 0x1f << systemRedShift;
mask.whole += 0x1f << systemGreenShift;
mask.whole += 0x1f << systemBlueShift;
switch (systemColorDepth) {
case 24:
while (count--) {
*buf++ &= mask.part.r;
*buf++ &= mask.part.g;
*buf++ &= mask.part.b;
// Green component
// 5 MSBs for the 'systemGreenShift' position
final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift;
// 3 LSBs for the 'base' position (systemGreenShift - 3)
final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3);
// Blue component
// 5 MSBs for the 'systemBlueShift' position
final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift;
// 3 LSBs for the 'base' position (systemBlueShift - 3)
final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3);
// Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth)
if (systemColorDepth == 32) {
final_pix |= (pix & (0xFF << 24));
}
break;
case 32:
while (count--) {
*((uint32_t*)buf) &= mask.whole;
buf += 4;
}
}
}
/*
void UpdateSystemColorMaps(int lcd)
{
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);
}
*buf++ = final_pix;
}
break;
case 16:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000);
}
break;
case 24:
case 32:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000);
}
break;
}
}
*/

View File

@@ -4,8 +4,9 @@
#include <cstdint>
void gbafilter_update_colors(bool lcd = false);
void gbafilter_pal8(uint8_t* buf, int count);
void gbafilter_pal(uint16_t* buf, int count);
void gbafilter_pal32(uint32_t* buf, int count);
void gbafilter_pad(uint8_t* buf, int count);
void gbafilter_set_params(int color_mode, float darken_screen);
#endif // VBAM_COMPONENTS_FILTERS_AGB_FILTERS_AGB_H_

View File

@@ -0,0 +1,6 @@
add_library(vbam-components-filters-cgb OBJECT)
target_sources(vbam-components-filters-cgb
PRIVATE filters_cgb.cpp
PUBLIC filters_cgb.h
)

View File

@@ -0,0 +1,352 @@
/*
* GBC Color Correction Shader Implementation
*
* Shader modified by Pokefan531.
* Color Mangler
* Original Author: hunterk
* Original License: Public domain
*
* This code is adapted from the original shader logic.
*/
#include "components/filters_cgb/filters_cgb.h"
#include <cmath>
#include <algorithm>
extern int systemColorDepth;
extern int systemRedShift;
extern int systemGreenShift;
extern int systemBlueShift;
extern uint8_t systemColorMap8[0x10000];
extern uint16_t systemColorMap16[0x10000];
extern uint32_t systemColorMap32[0x10000];
// --- Global Constants and Variables for GBC Color Correction ---
// Define the color profile matrix as a static const float 2D array
// This replicates the column-major order of GLSL mat4 for easier translation.
// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... }
static const float GBC_sRGB[4][4] = {
{0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A)
{0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A)
{-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A)
{0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution)
};
static const float GBC_DCI[4][4] = {
{0.76f, 0.125f, 0.16f, 0.0f},
{0.27f, 0.6375f, 0.18f, 0.0f},
{-0.03f, 0.2375f, 0.66f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.97f}
};
static const float GBC_Rec2020[4][4] = {
{0.61f, 0.155f, 0.16f, 0.0f},
{0.345f, 0.615f, 0.1875f, 0.0f},
{0.045f, 0.23f, 0.6525f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
};
// Screen lightening factor. Default to 0.0f.
static float lighten_screen = 0.0f;
// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0).
static int color_mode = 0;
// Pointer to the currently selected color profile matrix.
static const float (*profile)[4];
// Global constants from the shader for gamma correction values
static const float target_gamma = 2.2f;
static const float display_gamma = 2.2f;
// --- Function Implementations ---
// Forward declaration of a helper function to set the profile based on color_mode
static void set_profile_from_mode();
// This constructor-like function runs once when the program starts.
struct GbcfilterInitializer {
GbcfilterInitializer() {
set_profile_from_mode();
}
};
static GbcfilterInitializer __gbcfilter_initializer;
// Helper function to set the 'profile' pointer based on the 'color_mode' variable.
static void set_profile_from_mode() {
if (color_mode == 0) {
profile = GBC_sRGB;
}
else if (color_mode == 1) {
profile = GBC_DCI;
}
else if (color_mode == 2) {
profile = GBC_Rec2020;
}
else {
profile = GBC_sRGB; // Default to sRGB if an invalid mode is set
}
}
// Public function to set color mode and darken screen from external calls
void gbcfilter_set_params(int new_color_mode, float new_lighten_screen) {
color_mode = new_color_mode;
lighten_screen = fmaxf(0.0f, fminf(1.0f, new_lighten_screen)); // Clamp to 0.0-1.0
// Call the helper to update 'profile' based on the new 'color_mode'
set_profile_from_mode();
}
void gbcfilter_update_colors(bool lcd) {
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));
}
if (lcd)
gbcfilter_pal8(systemColorMap8, 0x10000);
} break;
case 16: {
for (int i = 0x0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbcfilter_pal(systemColorMap16, 0x10000);
} break;
case 24:
case 32: {
for (int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd)
gbcfilter_pal32(systemColorMap32, 0x10000);
} break;
}
}
void gbcfilter_pal8(uint8_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint8_t pix = *buf;
uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5);
uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2);
uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_3bit / 7.0f;
float g = (float)original_g_val_3bit / 7.0f;
float b = (float)original_b_val_2bit / 3.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t
// Apply 3-bit or 2-bit to 8-bit conversion, as this palette is for 8-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f);
// Ensure values are strictly within 0-7 or 0-3 range after rounding
if (final_red > 7) final_red = 7;
if (final_green > 7) final_green = 7;
if (final_blue > 3) final_blue = 3;
*buf++ = ((final_red & 0x7) << 5) |
((final_green & 0x7) << 2) |
(final_blue & 0x3);
}
}
void gbcfilter_pal(uint16_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint16_t pix = *buf;
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
// This step will affect non-"white" values.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix (using profile[column][row] access)
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma to convert back for display.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert back to 5-bit (0-31) integer and combine into uint16_t
// Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output.
uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f);
uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f);
uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f);
// Ensure values are strictly within 0-31 range after rounding
if (final_red > 31) final_red = 31;
if (final_green > 31) final_green = 31;
if (final_blue > 31) final_blue = 31;
*buf++ = (final_red << systemRedShift) |
(final_green << systemGreenShift) |
(final_blue << systemBlueShift);
}
}
void gbcfilter_pal32(uint32_t* buf, int count)
{
// Pre-calculate constants for efficiency within function scope
const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f);
const float display_gamma_reciprocal = 1.0f / display_gamma;
const float luminance_factor = profile[3][3]; // profile[3].w from GLSL
while (count--) {
uint32_t pix = *buf;
// Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel.
// These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red).
uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f);
uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f);
uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f);
// Normalize to 0.0-1.0 for calculations
float r = (float)original_r_val_5bit / 31.0f;
float g = (float)original_g_val_5bit / 31.0f;
float b = (float)original_b_val_5bit / 31.0f;
// 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space.
r = powf(r, target_gamma_exponent);
g = powf(g, target_gamma_exponent);
b = powf(b, target_gamma_exponent);
// 2. Apply luminance factor and clamp.
r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor));
g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor));
b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor));
// 3. Apply color profile matrix
float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b;
float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b;
float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b;
// 4. Apply display gamma.
transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r);
transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g);
transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b);
// Final clamp: ensure values are within 0.0-1.0 range
transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r));
transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g));
transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b));
// Convert the floating-point values to 8-bit integer components (0-255).
uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f);
uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f);
uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f);
// Ensure values are strictly within 0-255 range after rounding
if (final_red_8bit > 255) final_red_8bit = 255;
if (final_green_8bit > 255) final_green_8bit = 255;
if (final_blue_8bit > 255) final_blue_8bit = 255;
// --- NEW PACKING LOGIC ---
// This is the critical change to correctly map 8-bit color to the 5-bit shifted format,
// while allowing FFFFFF.
// It uses the top 5 bits of the 8-bit value for the GBC's 5-bit component position,
// and the bottom 3 bits to fill the lower, normally zeroed, positions.
uint32_t final_pix = 0;
// Red component
// 5 most significant bits (MSBs) for the 'systemRedShift' position
final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift;
// 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3)
final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3);
// Green component
// 5 MSBs for the 'systemGreenShift' position
final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift;
// 3 LSBs for the 'base' position (systemGreenShift - 3)
final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3);
// Blue component
// 5 MSBs for the 'systemBlueShift' position
final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift;
// 3 LSBs for the 'base' position (systemBlueShift - 3)
final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3);
// Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth)
if (systemColorDepth == 32) {
final_pix |= (pix & (0xFF << 24));
}
*buf++ = final_pix;
}
}

View File

@@ -0,0 +1,12 @@
#ifndef VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
#define VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
#include <cstdint>
void gbcfilter_update_colors(bool lcd = false);
void gbcfilter_pal8(uint8_t* buf, int count);
void gbcfilter_pal(uint16_t* buf, int count);
void gbcfilter_pal32(uint32_t* buf, int count);
void gbcfilter_set_params(int color_mode, float lighten_screen);
#endif // VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_

View File

@@ -19,12 +19,12 @@ FILE* utilOpenFile(const char* filename, const char* mode) {
#ifdef _WIN32
std::wstring wfilename = core::internal::ToUTF16(filename);
if (wfilename.empty()) {
return nullptr;
return NULL;
}
std::wstring wmode = core::internal::ToUTF16(mode);
if (wmode.empty()) {
return nullptr;
return NULL;
}
#if __STDC_WANT_SECURE_LIB__
@@ -53,7 +53,7 @@ bool utilIsGBAImage(const char* file) {
if (strlen(file) > 4) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if ((strcasecmp(p, ".agb") == 0) || (strcasecmp(p, ".gba") == 0) ||
(strcasecmp(p, ".bin") == 0) || (strcasecmp(p, ".elf") == 0))
return true;
@@ -71,7 +71,7 @@ bool utilIsGBImage(const char* file) {
if (strlen(file) > 4) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if ((strcasecmp(p, ".dmg") == 0) || (strcasecmp(p, ".gb") == 0) ||
(strcasecmp(p, ".gbc") == 0) || (strcasecmp(p, ".cgb") == 0) ||
(strcasecmp(p, ".sgb") == 0))

View File

@@ -24,7 +24,7 @@ bool utilIsGzipFile(const char* file) {
if (strlen(file) > 3) {
const char* p = strrchr(file, '.');
if (p != nullptr) {
if (p != NULL) {
if (strcasecmp(p, ".gz") == 0)
return true;
if (strcasecmp(p, ".z") == 0)
@@ -36,13 +36,13 @@ bool utilIsGzipFile(const char* file) {
}
// Opens and scans archive using accept(). Returns fex_t if found.
// If error or not found, displays message and returns nullptr.
// If error or not found, displays message and returns NULL.
fex_t* scanArchive(const char* file, bool (*accept)(const char*), char (&buffer)[2048]) {
fex_t* fe;
fex_err_t err = fex_open(&fe, file);
if (!fe) {
systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err);
return nullptr;
return NULL;
}
// Scan filenames
@@ -67,14 +67,14 @@ fex_t* scanArchive(const char* file, bool (*accept)(const char*), char (&buffer)
if (err) {
systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err);
fex_close(fe);
return nullptr;
return NULL;
}
}
if (!found) {
systemMessage(MSG_NO_IMAGE_ON_ZIP, N_("No image found in file %s"), file);
fex_close(fe);
return nullptr;
return NULL;
}
return fe;
}
@@ -101,10 +101,10 @@ IMAGE_TYPE utilFindType(const char* file, char (&buffer)[2048]) {
return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB;
}
int(ZEXPORT* utilGzWriteFunc)(gzFile, const voidp, unsigned int) = nullptr;
int(ZEXPORT* utilGzReadFunc)(gzFile, voidp, unsigned int) = nullptr;
int(ZEXPORT* utilGzCloseFunc)(gzFile) = nullptr;
z_off_t(ZEXPORT* utilGzSeekFunc)(gzFile, z_off_t, int) = nullptr;
int(ZEXPORT* utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
int(ZEXPORT* utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
int(ZEXPORT* utilGzCloseFunc)(gzFile) = NULL;
z_off_t(ZEXPORT* utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
} // namespace
@@ -113,7 +113,7 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
char buffer[2048];
fex_t* fe = scanArchive(file, accept, buffer);
if (!fe)
return nullptr;
return NULL;
// Allocate space for image
fex_err_t err = fex_stat(fe);
@@ -122,17 +122,17 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
size = fileSize;
if (size > MAX_CART_SIZE)
return nullptr;
return NULL;
uint8_t* image = data;
if (image == nullptr) {
if (image == NULL) {
// allocate buffer memory if none was passed to the function
image = (uint8_t*)malloc(utilGetSize(size));
if (image == nullptr) {
if (image == NULL) {
fex_close(fe);
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), "data");
return nullptr;
return NULL;
}
size = fileSize;
}
@@ -144,9 +144,9 @@ uint8_t* utilLoad(const char* file, bool (*accept)(const char*), uint8_t* data,
if (err) {
systemMessage(MSG_ERROR_READING_IMAGE, N_("Error reading image from %s: %s"), buffer, err);
if (data == nullptr)
if (data == NULL)
free(image);
return nullptr;
return NULL;
}
size = fileSize;
@@ -183,7 +183,7 @@ gzFile utilAutoGzOpen(const char* file, const char* mode) {
std::wstring wfile = core::internal::ToUTF16(file);
if (wfile.empty()) {
return nullptr;
return NULL;
}
return gzopen_w(wfile.data(), mode);

View File

@@ -25,12 +25,12 @@ static int utilGetSize(int size) {
}
uint8_t* utilLoad(const char* file, bool (*)(const char*), uint8_t* data, int& size) {
FILE* fp = nullptr;
FILE* fp = NULL;
fp = fopen(file, "rb");
if (!fp) {
log("Failed to open file %s", file);
return nullptr;
return NULL;
}
fseek(fp, 0, SEEK_END); // go to end
@@ -38,18 +38,18 @@ uint8_t* utilLoad(const char* file, bool (*)(const char*), uint8_t* data, int& s
rewind(fp);
uint8_t* image = data;
if (image == nullptr) {
if (image == NULL) {
image = (uint8_t*)malloc(utilGetSize(size));
if (image == nullptr) {
if (image == NULL) {
log("Failed to allocate memory for %s", file);
return nullptr;
return NULL;
}
}
if (fread(image, 1, size, fp) != (size_t)size) {
log("Failed to read from %s", file);
fclose(fp);
return nullptr;
return NULL;
}
fclose(fp);

View File

@@ -10,8 +10,6 @@ extern "C" {
#include "core/base/system.h"
#include "core/base/message.h"
bool no_border = false;
bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
static constexpr size_t kNumChannels = 3;
uint8_t* writeBuffer = new uint8_t[w * h * kNumChannels];
@@ -23,7 +21,7 @@ bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
switch (systemColorDepth) {
case 8: {
uint8_t* pixU8 = (uint8_t*)pix + (w);
uint8_t* pixU8 = (uint8_t*)pix + (w + 4);
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
// White color fix
@@ -38,9 +36,7 @@ bool utilWritePNGFile(const char* fileName, int w, int h, uint8_t* pix) {
}
}
if (no_border == false) {
pixU8 += 2;
}
pixU8 += 4;
}
} break;
case 16: {
@@ -155,11 +151,7 @@ bool utilWriteBMPFile(const char* fileName, int w, int h, uint8_t* pix) {
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));
}
pixU8 = (uint8_t*)pix + ((w + 4) * (h));
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++, pixU8++) {
@@ -175,13 +167,11 @@ bool utilWriteBMPFile(const char* fileName, int w, int h, uint8_t* pix) {
}
}
if (no_border == false) {
pixU8++;
pixU8++;
pixU8 -= 2 * (w + 2);
} else {
pixU8 -= 2 * (w);
}
pixU8++;
pixU8++;
pixU8++;
pixU8++;
pixU8 -= 2 * (w + 4);
fwrite(writeBuffer, 1, 3 * w, fp);
b = writeBuffer;

View File

@@ -10,7 +10,7 @@ namespace internal {
#if defined(_WIN32)
std::wstring ToUTF16(const char* utf8) {
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0);
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
if (len == 0) {
return std::wstring();
}

View File

@@ -10,7 +10,7 @@
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#define fopen64 fopen
#define fseeko64 fseeko
@@ -34,7 +34,7 @@
#include "core/base/file_util.h"
#ifdef __GNUC__
#if defined(__MUSL__) || defined(__APPLE__) || defined(BSD) || defined(__NetBSD__)
#if defined(__MUSL__) || defined(__APPLE__) || defined(BSD)
typedef off_t __off64_t; /* off_t is 64 bits on BSD. */
#define fseeko64 fseeko
#define ftello64 ftello

View File

@@ -37,21 +37,21 @@
#else
// swaps a 16-bit value
static inline uint16_t swap16(uint16_t v)
static inline uint16_t vbswap16(uint16_t v)
{
return (v << 8) | (v >> 8);
}
// swaps a 32-bit value
static inline uint32_t swap32(uint32_t v)
static inline uint32_t vbswap32(uint32_t v)
{
return (v << 24) | ((v << 8) & 0xff0000) | ((v >> 8) & 0xff00) | (v >> 24);
}
#define READ16LE(x) swap16(*((uint16_t *)(x)))
#define READ32LE(x) swap32(*((uint32_t *)(x)))
#define WRITE16LE(x, v) *((uint16_t *)x) = swap16((v))
#define WRITE32LE(x, v) *((uint32_t *)x) = swap32((v))
#define READ16LE(x) vbswap16(*((uint16_t *)(x)))
#define READ32LE(x) vbswap32(*((uint32_t *)(x)))
#define WRITE16LE(x, v) *((uint16_t *)x) = vbswap16((v))
#define WRITE32LE(x, v) *((uint32_t *)x) = vbswap32((v))
#endif
#else
#define READ16LE(x) *((uint16_t *)x)

View File

@@ -74,8 +74,8 @@ extern struct CoreOptions {
uint32_t speedup_throttle = 100;
uint32_t speedup_frame_skip = 9;
uint32_t throttle = 100;
const char* loadDotCodeFile = nullptr;
const char* saveDotCodeFile = nullptr;
const char* loadDotCodeFile = NULL;
const char* saveDotCodeFile = NULL;
} coreOptions;
// The following functions must be implemented by the emulator.

View File

@@ -877,7 +877,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
#ifdef USE_HWCAP
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
static unsigned long MY_getauxval(int aux)
{
unsigned long val;

View File

@@ -129,7 +129,9 @@ wchar etoupperw(wchar ch)
{
if (ch=='i')
return('I');
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__linux__)
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__MINGW32__) || \
defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__OpenBSD__)
return(toupper(ch));
#else
return(toupperw(ch));
@@ -234,7 +236,9 @@ bool LowAscii(const wchar *Str)
int wcsicompc(const wchar *Str1,const wchar *Str2)
{
#if defined(_UNIX) || defined(_MSC_VER) || defined(__APPLE__) || defined(__linux__)
#if defined(_UNIX) || defined(_MSC_VER) || defined(__APPLE__) || \
defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
defined(__OpenBSD__)
return my_wcscmp(Str1,Str2);
#elif defined(__MINGW32__)
return _wcsicmp(Str1,Str2);

View File

@@ -38,10 +38,10 @@ extern uint8_t* g_pix;
namespace {
// Mapper functions.
void (*g_mapper)(uint16_t, uint8_t) = nullptr;
void (*g_mapperRAM)(uint16_t, uint8_t) = nullptr;
uint8_t (*g_mapperReadRAM)(uint16_t) = nullptr;
void (*g_mapperUpdateClock)() = nullptr;
void (*g_mapper)(uint16_t, uint8_t) = NULL;
void (*g_mapperRAM)(uint16_t, uint8_t) = NULL;
uint8_t (*g_mapperReadRAM)(uint16_t) = NULL;
void (*g_mapperUpdateClock)() = NULL;
// Set to true on battery load error.
bool g_gbBatteryError = false;
@@ -59,7 +59,7 @@ struct VBamIoVec {
int leeway = 0;
// Optional action to take on read failure.
// If this is set, `g_gbBatteryError` will not be set.
void (*action_on_failure)() = nullptr;
void (*action_on_failure)() = NULL;
};
std::vector<VBamIoVec> g_vbamIoVecs;
@@ -136,7 +136,7 @@ bool WriteBatteryFile(const char* file_name) {
}
FILE* file = utilOpenFile(file_name, "wb");
if (file == nullptr) {
if (file == NULL) {
systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
file_name);
return false;
@@ -157,7 +157,7 @@ bool ReadBatteryFile(const char* file_name) {
}
gzFile gzFile = utilAutoGzOpen(file_name, "rb");
if (gzFile == nullptr) {
if (gzFile == NULL) {
return false;
}
@@ -404,9 +404,9 @@ bool gbInitializeRom(size_t romSize) {
break;
case gbCartData::MapperType::kTama5:
gbRamFill = 0x00;
if (gbTAMA5ram == nullptr) {
if (gbTAMA5ram == NULL) {
gbTAMA5ram = (uint8_t*)calloc(1, kTama5RamSize);
if (gbTAMA5ram == nullptr) {
if (gbTAMA5ram == NULL) {
return false;
}
}
@@ -432,16 +432,16 @@ bool gbInitializeRom(size_t romSize) {
// We need to explicitly reset gbRam here as the patch application process
// may have changed the RAM size.
if (gbRam != nullptr) {
if (gbRam != NULL) {
free(gbRam);
gbRam = nullptr;
gbRam = NULL;
}
const size_t ramSize = g_gbCartData.ram_size();
if (g_gbCartData.HasRam()) {
// Always allocate 4 KiB to prevent access issues down the line.
gbRam = (uint8_t*)malloc(std::max(k4KiB, ramSize));
if (gbRam == nullptr) {
if (gbRam == NULL) {
return false;
}
memset(gbRam, gbRamFill, ramSize);
@@ -2711,27 +2711,27 @@ void gbReset()
gbInterruptLaunched = 0;
if (gbCgbMode) {
if (gbVram == nullptr) {
if (gbVram == NULL) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
if (gbVram == NULL) {
return;
}
}
if (gbWram == nullptr) {
if (gbWram == NULL) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
if (gbWram == NULL) {
return;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram != nullptr) {
if (gbVram != NULL) {
free(gbVram);
gbVram = nullptr;
gbVram = NULL;
}
if (gbWram != nullptr) {
if (gbWram != NULL) {
free(gbWram);
gbWram = nullptr;
gbWram = NULL;
}
}
@@ -2749,7 +2749,7 @@ void gbReset()
// In all cases, most of the 2nd bank is filled with 00s.
// The starting data are important for some 'buggy' games, like Buster Brothers or
// Karamuchou ha Oosawagi!.
if (gbMemory != nullptr) {
if (gbMemory != NULL) {
memset(gbMemory, 0xff, 65536);
for (int temp = 0xC000; temp < 0xE000; temp++)
if ((temp & 0x8) ^ ((temp & 0x800) >> 8)) {
@@ -2775,15 +2775,16 @@ void gbReset()
}
// clean LineBuffer
if (gbLineBuffer != nullptr) {
if (gbLineBuffer != NULL) {
memset(gbLineBuffer, 0, kGBLineBufferSize);
}
// clean Pix
if (g_pix != nullptr) {
memset(g_pix, 0, kGBPixSize);
if (g_pix != NULL) {
free(g_pix);
g_pix = (uint8_t *)malloc(kGBPixSize);
}
// clean Vram
if (gbVram != nullptr) {
if (gbVram != NULL) {
memset(gbVram, 0, kGBVRamSize);
}
// clean Wram 2
@@ -2793,7 +2794,7 @@ void gbReset()
// In all cases, most of the 2nd bank is filled with 00s.
// The starting data are important for some 'buggy' games, like Buster Brothers or
// Karamuchou ha Oosawagi!
if (gbWram != nullptr) {
if (gbWram != NULL) {
for (int i = 0; i < 8; i++)
if (i != 2)
memcpy((uint16_t*)(gbWram + i * 0x1000), (uint16_t*)(gbMemory + 0xC000), 0x1000);
@@ -3433,27 +3434,27 @@ static bool gbReadSaveState(gzFile gzFile)
// Correct crash when loading color gameboy save in regular gameboy type.
if (gbCgbMode) {
if (gbVram == nullptr) {
if (gbVram == NULL) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
if (gbVram == NULL) {
return false;
}
}
if (gbWram == nullptr) {
if (gbWram == NULL) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
if (gbWram == NULL) {
return false;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram != nullptr) {
if (gbVram != NULL) {
free(gbVram);
gbVram = nullptr;
gbVram = NULL;
}
if (gbWram != nullptr) {
if (gbWram != NULL) {
free(gbWram);
gbWram = nullptr;
gbWram = NULL;
}
}
@@ -3765,58 +3766,58 @@ bool gbWriteBMPFile(const char* fileName)
void gbCleanUp()
{
if (gbRam != nullptr) {
if (gbRam != NULL) {
free(gbRam);
gbRam = nullptr;
gbRam = NULL;
}
if (gbRom != nullptr) {
if (gbRom != NULL) {
free(gbRom);
gbRom = nullptr;
gbRom = NULL;
}
if (g_bios != nullptr) {
if (g_bios != NULL) {
free(g_bios);
g_bios = nullptr;
g_bios = NULL;
}
if (gbMemory != nullptr) {
if (gbMemory != NULL) {
free(gbMemory);
gbMemory = nullptr;
gbMemory = NULL;
}
if (gbLineBuffer != nullptr) {
if (gbLineBuffer != NULL) {
free(gbLineBuffer);
gbLineBuffer = nullptr;
gbLineBuffer = NULL;
}
if (g_pix != nullptr) {
if (g_pix != NULL) {
free(g_pix);
g_pix = nullptr;
g_pix = NULL;
}
gbSgbShutdown();
if (gbVram != nullptr) {
if (gbVram != NULL) {
free(gbVram);
gbVram = nullptr;
gbVram = NULL;
}
if (gbWram != nullptr) {
if (gbWram != NULL) {
free(gbWram);
gbWram = nullptr;
gbWram = NULL;
}
if (gbTAMA5ram != nullptr) {
if (gbTAMA5ram != NULL) {
free(gbTAMA5ram);
gbTAMA5ram = nullptr;
gbTAMA5ram = NULL;
}
g_gbCartData = gbCartData();
g_mapper = nullptr;
g_mapperRAM = nullptr;
g_mapperReadRAM = nullptr;
g_mapperUpdateClock = nullptr;
g_mapper = NULL;
g_mapperRAM = NULL;
g_mapperReadRAM = NULL;
g_mapperUpdateClock = NULL;
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
#if !defined(__LIBRETRO__)
@@ -3827,39 +3828,39 @@ void gbCleanUp()
bool gbLoadRom(const char* filename) {
int romSize = 0;
if (gbRom != nullptr) {
if (gbRom != NULL) {
gbCleanUp();
}
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
gbRom = utilLoad(filename, utilIsGBImage, nullptr, romSize);
gbRom = utilLoad(filename, utilIsGBImage, NULL, romSize);
if (!gbRom)
return false;
g_gbBatteryError = false;
if (g_bios != nullptr) {
if (g_bios != NULL) {
free(g_bios);
g_bios = nullptr;
g_bios = NULL;
}
g_bios = (uint8_t*)calloc(1, kGBBiosBufferSize);
if (g_bios == nullptr) {
if (g_bios == NULL) {
return false;
}
gbMemory = (uint8_t*)malloc(65536);
if (gbMemory == nullptr) {
if (gbMemory == NULL) {
return false;
}
g_pix = (uint8_t*)calloc(1, kGBPixSize);
if (g_pix == nullptr) {
if (g_pix == NULL) {
return false;
}
gbLineBuffer = (uint16_t*)malloc(kGBLineBufferSize);
if (gbLineBuffer == nullptr) {
if (gbLineBuffer == NULL) {
return false;
}
@@ -3905,7 +3906,7 @@ void gbDrawLine()
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)
uint8_t* dest = (uint8_t*)g_pix + (gbBorderLineSkip + 4) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (size_t x = 0; x < kGBWidth;) {
@@ -3932,7 +3933,7 @@ void gbDrawLine()
if (gbBorderOn)
dest += gbBorderColumnSkip;
#ifndef __LIBRETRO__
*dest++ = 0; // for filters that read one pixel more
* dest++ = 0; // for filters that read one pixel more
#endif
} break;
case 16: {
@@ -3970,48 +3971,67 @@ void gbDrawLine()
*dest++ = 0; // for filters that read one pixel more
#endif
} break;
case 24: {
uint8_t* dest = (uint8_t*)g_pix + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + gbBorderColumnSkip);
#ifdef __LIBRETRO__
uint8_t* dest = (uint8_t*)g_pix + (gbBorderLineSkip * 3) * (register_LY + gbBorderRowSkip)
+ (gbBorderColumnSkip * 3);
#else
uint8_t* dest = (uint8_t*)g_pix + (gbBorderLineSkip * 3) * (register_LY + gbBorderRowSkip + 1)
+ (gbBorderColumnSkip * 3);
#endif
for (size_t x = 0; x < kGBWidth;) {
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
uint32_t color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[gbLineMix[x++]];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
}
} break;
case 32: {
#ifdef __LIBRETRO__
uint32_t* dest = (uint32_t*)g_pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
@@ -4946,14 +4966,14 @@ void gbEmulate(int ticksToStop)
}
bool gbLoadRomData(const char* data, size_t size) {
if (gbRom != nullptr) {
if (gbRom != NULL) {
gbCleanUp();
}
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
gbRom = (uint8_t*)calloc(1, size);
if (gbRom == nullptr) {
if (gbRom == NULL) {
return false;
}
@@ -4961,28 +4981,28 @@ bool gbLoadRomData(const char* data, size_t size) {
g_gbBatteryError = false;
if (g_bios != nullptr) {
if (g_bios != NULL) {
free(g_bios);
g_bios = nullptr;
g_bios = NULL;
}
g_bios = (uint8_t*)calloc(1, kGBBiosBufferSize);
if (g_bios == nullptr) {
if (g_bios == NULL) {
return false;
}
gbMemory = (uint8_t*)malloc(65536);
if (gbMemory == nullptr) {
if (gbMemory == NULL) {
return false;
}
g_pix = (uint8_t*)calloc(1, kGBPixSize);
if (g_pix == nullptr) {
if (g_pix == NULL) {
return false;
}
gbLineBuffer = (uint16_t*)malloc(kGBLineBufferSize);
if (gbLineBuffer == nullptr) {
if (gbLineBuffer == NULL) {
return false;
}
@@ -5033,7 +5053,7 @@ unsigned int gbWriteSaveState(uint8_t* data)
if (g_gbCartData.mapper_type() == gbCartData::MapperType::kHuC3)
utilWriteMem(data, &gbRTCHuC3, sizeof(gbRTCHuC3));
utilWriteMem(data, &gbDataTAMA5, sizeof(gbDataTAMA5));
if (gbTAMA5ram != nullptr)
if (gbTAMA5ram != NULL)
utilWriteMem(data, gbTAMA5ram, kTama5RamSize);
utilWriteMem(data, &gbDataMMM01, sizeof(gbDataMMM01));
@@ -5118,27 +5138,27 @@ bool gbReadSaveState(const uint8_t* data)
// Correct crash when loading color gameboy save in regular gameboy type.
if (gbCgbMode) {
if (gbVram == nullptr) {
if (gbVram == NULL) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
if (gbVram == NULL) {
return false;
}
}
if (gbWram == nullptr) {
if (gbWram == NULL) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
if (gbWram == NULL) {
return false;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram != nullptr) {
if (gbVram != NULL) {
free(gbVram);
gbVram = nullptr;
gbVram = NULL;
}
if (gbWram != nullptr) {
if (gbWram != NULL) {
free(gbWram);
gbWram = nullptr;
gbWram = NULL;
}
}

View File

@@ -55,7 +55,7 @@ void gbRenderLine()
bank1 = &gbVram[0x2000];
} else {
bank0 = &gbMemory[0x8000];
bank1 = nullptr;
bank1 = NULL;
}
int tile_map = 0x1800;
@@ -92,7 +92,7 @@ void gbRenderLine()
int tile_map_address = tile_map_line_y + tx;
uint8_t _attrs = 0;
if (bank1 != nullptr)
if (bank1 != NULL)
_attrs = bank1[tile_map_address];
uint8_t tile = bank0[tile_map_address];
@@ -406,7 +406,7 @@ void gbDrawSpriteTile(int tile, int x, int y, int t, int flags,
bank1 = &gbVram[0x2000];
} else {
bank0 = &gbMemory[0x8000];
bank1 = nullptr;
bank1 = NULL;
}
int SpritesTicks = gbSpritesTicks[x + 8] * (gbSpeed ? 2 : 4);

View File

@@ -1,14 +1,15 @@
#include "core/gb/gbGlobals.h"
#include <stdlib.h>
uint8_t* gbMemoryMap[16];
uint8_t* gbMemory = nullptr;
uint8_t* gbVram = nullptr;
uint8_t* gbRom = nullptr;
uint8_t* gbRam = nullptr;
uint8_t* gbWram = nullptr;
uint16_t* gbLineBuffer = nullptr;
uint8_t* gbTAMA5ram = nullptr;
uint8_t* gbMemory = NULL;
uint8_t* gbVram = NULL;
uint8_t* gbRom = NULL;
uint8_t* gbRam = NULL;
uint8_t* gbWram = NULL;
uint16_t* gbLineBuffer = NULL;
uint8_t* gbTAMA5ram = NULL;
uint16_t gbPalette[128];
uint8_t gbBgp[4] = { 0, 1, 2, 3 };
@@ -29,4 +30,4 @@ bool gbCgbMode = false;
bool gbSgbMode = false;
bool gbColorOption = false;
uint8_t (*gbSerialFunction)(uint8_t) = nullptr;
uint8_t (*gbSerialFunction)(uint8_t) = NULL;

View File

@@ -16,7 +16,7 @@ extern long soundSampleRate; // current sound quality
gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false };
static gb_effects_config_t gb_effects_config_current;
static Simple_Effects_Buffer* stereo_buffer;
static Simple_Effects_Buffer* stereo_buffer = 0;
static Gb_Apu* gb_apu;
static float soundVolume_ = -1;

View File

@@ -117,7 +117,7 @@ std::map<std::string, uint32_t> dexp_vars;
# ifndef YY_NULLPTR
# if defined __cplusplus
# if 201103L <= __cplusplus
# define YY_NULLPTR nullptr
# define YY_NULLPTR NULL
# else
# define YY_NULLPTR 0
# endif

View File

@@ -1675,16 +1675,31 @@ void GBAMatrixWrite16(GBAMatrix_t *matrix, uint32_t address, uint16_t value)
}
}
static size_t get_gba_rom_size(const char* szFile)
{
size_t size = 0;
FILE *f = fopen(szFile, "rb");
if (f == NULL)
return 0;
fseek(f, 0, SEEK_END);
size = ftell(f);
fclose(f);
return size;
}
int CPULoadRom(const char* szFile)
{
romSize = SIZE_ROM * 4;
romSize = get_gba_rom_size(szFile);
if (g_rom != NULL) {
CPUCleanUp();
}
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
g_rom = (uint8_t*)malloc(SIZE_ROM * 4);
g_rom = (uint8_t*)malloc(romSize);
if (g_rom == NULL) {
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
"ROM");
@@ -1829,14 +1844,14 @@ int CPULoadRom(const char* szFile)
int CPULoadRomData(const char* data, int size)
{
romSize = SIZE_ROM * 4;
romSize = size % 2 == 0 ? size : size + 1;
if (g_rom != NULL) {
CPUCleanUp();
}
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
g_rom = (uint8_t*)malloc(SIZE_ROM * 4);
g_rom = (uint8_t*)malloc(romSize);
if (g_rom == NULL) {
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
"ROM");
@@ -1869,7 +1884,7 @@ int CPULoadRomData(const char* data, int size)
memcpy(&ident, &g_rom[0xAC], 1);
if (ident == 'M') {
g_rom2 = (uint8_t *)malloc(SIZE_ROM * 4);
g_rom2 = (uint8_t *)malloc(romSize);
memcpy(g_rom2, data, size);
romSize = 0x01000000;
@@ -4211,7 +4226,7 @@ void CPULoop(int ticks)
#ifdef __LIBRETRO__
uint8_t* dest = (uint8_t*)g_pix + 240 * VCOUNT;
#else
uint8_t* dest = (uint8_t*)g_pix + 242 * (VCOUNT + 1);
uint8_t* dest = (uint8_t*)g_pix + 244 * (VCOUNT + 1);
#endif
for (int x = 0; x < 240;) {
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
@@ -4234,9 +4249,9 @@ void CPULoop(int ticks)
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap8[g_lineMix[x++] & 0xFFFF];
}
// for filters that read past the screen
// for filters that read past the screen
#ifndef __LIBRETRO__
*dest++ = 0;
* dest++ = 0;
#endif
} break;
case 16: {
@@ -4272,43 +4287,58 @@ void CPULoop(int ticks)
#endif
} break;
case 24: {
uint8_t* dest = (uint8_t*)g_pix + 240 * VCOUNT * 3;
uint8_t* dest = (uint8_t*)g_pix + (240 * 3) * (VCOUNT + 1);
for (int x = 0; x < 240;) {
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
uint32_t color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[g_lineMix[x++] & 0xFFFF];
dest += 3;
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
color = systemColorMap32[g_lineMix[x++] & 0xFFFF];
*dest++ = (uint8_t)(color & 0xFF);
*dest++ = (uint8_t)((color >> 8) & 0xFF);
*dest++ = (uint8_t)((color >> 16) & 0xFF);
}
} break;
case 32: {

View File

@@ -31,7 +31,7 @@ uint32_t systemGetClock() {
void systemSetTitle(const char*) {}
std::unique_ptr<SoundDriver> systemSoundInit() {
return nullptr;
return NULL;
}
void systemOnWriteDataToSoundBuffer(const uint16_t* /*finalWave*/, int /*length*/) {}

View File

@@ -1,7 +1,15 @@
DEBUG=0
TILED_RENDERING=0
STATIC_LINKING=0
FRONTEND_SUPPORTS_RGB565=1
ifeq ($(platform), ps2)
FRONTEND_SUPPORT_RGB565=0
FRONTEND_SUPPORT_BGR1555=1
else
FRONTEND_SUPPORT_RGB565=1
FRONTEND_SUPPORT_BGR1555=0
endif
NO_LINK=1
SPACE :=
@@ -239,6 +247,16 @@ else ifeq ($(platform), psl1ght)
PLATFORM_DEFINES := -D__PS3__ -D__POWERPC__ -D__ppc__
STATIC_LINKING=1
TILED_RENDERING=1
else ifeq ($(platform), ps2)
EXT=a
TARGET := $(TARGET_NAME)_libretro_$(platform).$(EXT)
CC = mips64r5900el-ps2-elf-gcc$(EXE_EXT)
CXX = mips64r5900el-ps2-elf-g++$(EXE_EXT)
AR = mips64r5900el-ps2-elf-ar$(EXE_EXT)
VBA_DEFINES += -DPS2
CFLAGS += -DHAVE_STRLWR -DPS2 -G0 -ffast-math -DABGR1555 -DNO_FAST_SQRT
STATIC_LINKING = 1
TILED_RENDERING=1
# PSP1
else ifeq ($(platform), psp1)

View File

@@ -11,6 +11,10 @@ ifeq ($(FRONTEND_SUPPORTS_RGB565),1)
VBA_DEFINES += -DFRONTEND_SUPPORTS_RGB565
endif
ifeq ($(FRONTEND_SUPPORT_BGR1555),1)
VBA_DEFINES += -DFRONTEND_SUPPORT_BGR1555
endif
ifeq ($(NO_LINK),1)
VBA_DEFINES += -DNO_LINK
endif
@@ -70,4 +74,5 @@ SOURCES_CXX += \
# Filters
SOURCES_CXX += \
$(CORE_DIR)/components/filters_agb/filters_agb.cpp \
$(CORE_DIR)/components/filters_cgb/filters_cgb.cpp \
$(CORE_DIR)/components/filters_interframe/interframe.cpp

View File

@@ -10,6 +10,7 @@
#include "scrc32.h"
#include "components/filters_agb/filters_agb.h"
#include "components/filters_cgb/filters_cgb.h"
#include "components/filters_interframe/interframe.h"
#include "core/base/check.h"
#include "core/base/system.h"
@@ -184,9 +185,9 @@ static void* gb_rtcdata_prt(void)
case gbCartData::MapperType::kGameShark:
case gbCartData::MapperType::kUnknown:
VBAM_NOTREACHED();
return nullptr;
return NULL;
}
return nullptr;
return NULL;
}
static size_t gb_rtcdata_size(void)
@@ -611,7 +612,15 @@ void retro_init(void)
if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
snprintf(retro_system_directory, sizeof(retro_system_directory), "%s", dir);
#ifdef FRONTEND_SUPPORTS_RGB565
#ifdef FRONTEND_SUPPORT_BGR1555
systemColorDepth = 16;
systemRedShift = 0;
systemGreenShift = 5;
systemBlueShift = 10;
enum retro_pixel_format rgb1555 = RETRO_PIXEL_FORMAT_0RGB1555;
if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb1555) && log_cb)
log_cb(RETRO_LOG_INFO, "Frontend supports BGR1555 - will use that instead of XRGB1555.\n");
#elif defined(FRONTEND_SUPPORTS_RGB565)
systemColorDepth = 16;
systemRedShift = 11;
systemGreenShift = 6;
@@ -1012,6 +1021,11 @@ static int option_analogDeadzone;
static int option_gyroSensitivity, option_tiltSensitivity;
static bool option_swapAnalogSticks;
static int color_mode = 0;
static int prev_color_mode = 0;
static float color_change = 0.0f;
static float prev_color_change = 0.0f;
static void update_variables(bool startup)
{
struct retro_variable var = { NULL, NULL };
@@ -1215,14 +1229,47 @@ static void update_variables(bool startup)
gbColorOption = (!strcmp(var.value, "enabled"));
}
var.key = "vbam_lcdfilter_type";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
prev_color_mode = color_mode;
if (!strcmp(var.value, "sRGB"))
color_mode = 0;
else if (!strcmp(var.value, "DCI"))
color_mode = 1;
else if (!strcmp(var.value, "Rec2020"))
color_mode = 2;
}
var.key = "vbam_color_change";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
prev_color_change = color_change;
color_change = ((float)atoi(var.value)) / 100;
}
var.key = "vbam_lcdfilter";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
bool prev_lcdfilter = option_lcdfilter;
option_lcdfilter = (!strcmp(var.value, "enabled")) ? true : false;
if (prev_lcdfilter != option_lcdfilter)
gbafilter_update_colors(option_lcdfilter);
if ((prev_color_change != color_change) || (prev_color_mode != color_mode)) {
if (type == IMAGE_GBA) {
gbafilter_set_params(color_mode, color_change);
} else {
gbcfilter_set_params(color_mode, color_change);
}
}
if ((prev_lcdfilter != option_lcdfilter) || (prev_color_change != color_change) || (prev_color_mode != color_mode)) {
if (type == IMAGE_GBA) {
gbafilter_update_colors(option_lcdfilter);
} else {
gbcfilter_update_colors(option_lcdfilter);
}
}
}
var.key = "vbam_interframeblending";
@@ -1755,9 +1802,9 @@ bool retro_load_game(const struct retro_game_info *game)
return emulating;
}
bool retro_load_game_special(unsigned, const struct retro_game_info *, size_t)
bool retro_load_game_special(unsigned, const struct retro_game_info *game, size_t)
{
return false;
return retro_load_game(game);
}
void retro_unload_game(void)
@@ -1787,8 +1834,10 @@ bool systemCanChangeSoundQuality(void)
void systemDrawScreen(void)
{
unsigned pitch = systemWidth * (systemColorDepth >> 3);
if (ifb_filter_func)
ifb_filter_func(g_pix, pitch, systemWidth, systemHeight);
video_cb(g_pix, systemWidth, systemHeight, pitch);
}

View File

@@ -203,6 +203,54 @@ struct retro_core_option_v2_definition option_defs_us[] = {
},
"disabled"
},
{
"vbam_lcdfilter_type",
"LCD Color Filter Type",
NULL,
"Screen filter type for onscreen colors.",
NULL,
"video",
{
{ "sRGB", NULL },
{ "DCI", NULL },
{ "Rec2020", NULL },
{ NULL, NULL },
},
"sRGB"
},
{
"vbam_color_change",
"LCD Color Lighten/Darken",
NULL,
"Darken GBA or lighten GBC in %.",
NULL,
"video",
{
{ "0", NULL },
{ "5", NULL },
{ "10", NULL },
{ "15", NULL },
{ "20", NULL },
{ "25", NULL },
{ "30", NULL },
{ "35", NULL },
{ "40", NULL },
{ "45", NULL },
{ "50", NULL },
{ "55", NULL },
{ "60", NULL },
{ "65", NULL },
{ "70", NULL },
{ "75", NULL },
{ "80", NULL },
{ "85", NULL },
{ "90", NULL },
{ "95", NULL },
{ "100", NULL },
{ NULL, NULL },
},
"0"
},
{
"vbam_interframeblending",
"Interframe Blending",

View File

@@ -21,3 +21,4 @@ firmware2_desc = "gbc_bios.bin (Game Boy Color BIOS)"
firmware2_path = "gbc_bios.bin"
firmware2_opt = "true"
notes = "(!) gba_bios.bin (md5): a860e8c0b6d573d191e4ec7db1b1e4f6|(!) gb_bios.bin (md5): 32fbbd84168d3482956eb3c5051637f5|(!) gbc_bios.bin (md5): dbfce9db9deaa2567f6a84fde55f9680"

View File

@@ -55,6 +55,7 @@ target_link_libraries(vbam
vbam-components-draw-text
vbam-components-filters
vbam-components-filters-agb
vbam-components-filters-cgb
vbam-components-filters-interframe
vbam-components-user-config
${OPENGL_LIBRARIES}

View File

@@ -111,6 +111,7 @@
#include "components/draw_text/draw_text.h"
#include "components/filters_agb/filters_agb.h"
#include "components/filters_cgb/filters_cgb.h"
#include "components/user_config/user_config.h"
#include "core/base/file_util.h"
#include "core/base/message.h"
@@ -1163,7 +1164,7 @@ void sdlInitVideo()
switch (systemColorDepth)
{
case 8:
srcPitch = sizeX * (systemColorDepth >> 3) + 2;
srcPitch = sizeX * (systemColorDepth >> 3) + 4;
break;
case 16:
@@ -1186,7 +1187,7 @@ void sdlInitVideo()
} else {
#ifdef CONFIG_8BIT
systemColorDepth = 8;
srcPitch = sizeX * (systemColorDepth >> 3) + 2;
srcPitch = sizeX * (systemColorDepth >> 3) + 4;
#elif defined(CONFIG_16BIT)
systemColorDepth = 16;
srcPitch = sizeX * (systemColorDepth >> 3) + 4;
@@ -2376,6 +2377,7 @@ int main(int argc, char** argv)
fprintf(stdout, "Color depth: %d\n", systemColorDepth);
gbafilter_update_colors();
gbcfilter_update_colors();
if (delta == NULL) {
delta = (uint8_t*)malloc(delta_size);

View File

@@ -254,12 +254,12 @@ void SoundSDL::deinit() {
SDL_Delay(100);
SDL_DestroySemaphore(data_available);
data_available = nullptr;
data_available = NULL;
SDL_DestroySemaphore(data_read);
data_read = nullptr;
data_read = NULL;
SDL_DestroyMutex(mutex);
mutex = nullptr;
mutex = NULL;
SDL_CloseAudioDevice(sound_device);

View File

@@ -69,16 +69,29 @@ if(NOT ZIP_PROGRAM)
if(NOT DEFINED POWERSHELL)
message(FATAL_ERROR "Powershell is required for extraction.")
endif()
# Get zip binaries from wxrc.
file(DOWNLOAD "https://www.willus.com/archive/zip64/infozip_binaries_win32.zip" ${CMAKE_CURRENT_BINARY_DIR}/infozip_binaries_win32.zip)
set(_url "https://www.willus.com/archive/zip64/infozip_binaries_win32.zip")
set(_path "${CMAKE_CURRENT_BINARY_DIR}/infozip_binaries_win32.zip")
set(_sha "b338a0f35e1f849d3466d4260fd8a51f2afe9cdf136cc07cc4d54b00cee13650")
foreach(_i RANGE 1 3)
# Get zip binaries from wxrc.
file(DOWNLOAD "${_url}" "${_path}" SHOW_PROGRESS STATUS _s)
list(GET _s 0 _c)
if(_c EQUAL 0)
file(SHA256 "${_path}" _h)
file(SIZE "${_path}" _z)
if(_h STREQUAL _sha AND _z GREATER 0)
break()
endif()
endif()
file(REMOVE "${_path}")
if(_i EQUAL 3)
message(FATAL_ERROR "Download failed or SHA256 mismatch after 3 attempts.")
endif()
endforeach()
# Unzip it.
execute_process(
COMMAND "${POWERSHELL}" -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('${CMAKE_CURRENT_BINARY_DIR}/infozip_binaries_win32.zip', '${CMAKE_CURRENT_BINARY_DIR}'); }"
)
set(ZIP_PROGRAM ${CMAKE_CURRENT_BINARY_DIR}/zip.exe CACHE STRING "zip compressor executable" FORCE)
execute_process(COMMAND "${POWERSHELL}" -NoLogo -NoProfile -ExecutionPolicy Bypass
-Command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('${_path}', '${CMAKE_CURRENT_BINARY_DIR}'); }")
set(ZIP_PROGRAM "${CMAKE_CURRENT_BINARY_DIR}/zip.exe" CACHE STRING "zip compressor executable" FORCE)
endif()
if(ZIP_PROGRAM)
set(ZIP_PROGRAM "${ZIP_PROGRAM}" CACHE STRING "zip compressor executable" FORCE)
@@ -424,6 +437,7 @@ target_link_libraries(
vbam-components-draw-text
vbam-components-filters
vbam-components-filters-agb
vbam-components-filters-cgb
vbam-components-filters-interframe
vbam-components-user-config
vbam-wx-config

View File

@@ -60,6 +60,7 @@ std::vector<AudioDevice> EnumerateAudioDevices(const config::AudioApi& audio_api
VBAM_NOTREACHED();
return {};
}
return {};
}
std::unique_ptr<SoundDriver> CreateSoundDriver(const config::AudioApi& api) {
@@ -95,8 +96,9 @@ std::unique_ptr<SoundDriver> CreateSoundDriver(const config::AudioApi& api) {
case config::AudioApi::kLast:
default:
VBAM_NOTREACHED();
return nullptr;
return NULL;
}
return NULL;
}
} // namespace audio

View File

@@ -106,12 +106,12 @@ public:
uint16_t current_rate = 0;
int current_buffer = 0;
int filled_buffers = 0;
int soundBufferLen = 0;
AudioTimeStamp starttime;
AudioTimeStamp timestamp;
AudioQueueTimelineRef timeline;
private:
int soundBufferLen = 0;
AudioDeviceID GetCoreAudioDevice(wxString name);
void setBuffer(uint16_t* finalWave, int length);
@@ -120,13 +120,29 @@ private:
static void PlaybackBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
int curbuf = 0;
CoreAudioAudio *cadevice = (CoreAudioAudio *)inUserData;
(void)inAQ;
for (curbuf = 0; curbuf < OPTION(kSoundBuffers); curbuf++) {
if (cadevice->buffers[curbuf] == inBuffer) {
break;
}
}
if (curbuf >= OPTION(kSoundBuffers))
return;
// buffer is unexpectedly here? We're probably dying, but try to requeue this buffer with silence.
if (inBuffer) {
memset(inBuffer->mAudioData, 0, inBuffer->mAudioDataBytesCapacity);
inBuffer->mAudioDataByteSize = 0;
if (cadevice->buffers[curbuf] != NULL) {
AudioQueueFreeBuffer(inAQ, cadevice->buffers[curbuf]);
cadevice->soundBufferLen = (soundGetSampleRate() / 60) * cadevice->description.mBytesPerPacket;
AudioQueueAllocateBuffer(inAQ, cadevice->soundBufferLen, &cadevice->buffers[curbuf]);
cadevice->buffers[curbuf]->mAudioDataByteSize = 0;
} else {
cadevice->soundBufferLen = (soundGetSampleRate() / 60) * cadevice->description.mBytesPerPacket;
AudioQueueAllocateBuffer(inAQ, cadevice->soundBufferLen, &cadevice->buffers[curbuf]);
cadevice->buffers[curbuf]->mAudioDataByteSize = 0;
}
if (cadevice->filled_buffers > 0) {
@@ -491,8 +507,8 @@ void CoreAudioAudio::write(uint16_t* finalWave, int length) {
current_buffer = 0;
}
while (filled_buffers >= (OPTION(kSoundBuffers) - 1)) {
wxMilliSleep(1);
while (filled_buffers >= OPTION(kSoundBuffers)) {
wxMilliSleep(((soundGetSampleRate() / 60) * 4) / (soundGetSampleRate() >> 7));
}
}
@@ -507,8 +523,8 @@ void CoreAudioAudio::write(uint16_t* finalWave, int length) {
current_buffer = 0;
}
while (filled_buffers >= (OPTION(kSoundBuffers) - 1)) {
wxMilliSleep(1);
while (filled_buffers >= OPTION(kSoundBuffers)) {
wxMilliSleep(((soundGetSampleRate() / 60) * 4) / (soundGetSampleRate() >> 7));
}
}

View File

@@ -333,7 +333,7 @@ void DirectSound::write(uint16_t* finalWave, int) {
static BOOL CALLBACK DSEnumCB(LPGUID guid, LPCTSTR desc, LPCTSTR /*module*/, LPVOID user) {
std::vector<AudioDevice>* devices = static_cast<std::vector<AudioDevice>*>(user);
if (guid == nullptr) {
if (guid == NULL) {
devices->push_back({desc, {}});
return TRUE;
}

View File

@@ -159,9 +159,9 @@ FAudio_Output::FAudio_Output() : buffer_count_(OPTION(kSoundBuffers)) {
currentBuffer = 0;
sound_buffer_len_ = 0;
device_changed = false;
faud = nullptr;
mVoice = nullptr;
sVoice = nullptr;
faud = NULL;
mVoice = NULL;
sVoice = NULL;
memset(&buf, 0, sizeof(buf));
memset(&vState, 0, sizeof(vState));
}
@@ -179,17 +179,17 @@ void FAudio_Output::close() {
}
FAudioVoice_DestroyVoice(sVoice);
sVoice = nullptr;
sVoice = NULL;
}
if (mVoice) {
FAudioVoice_DestroyVoice(mVoice);
mVoice = nullptr;
mVoice = NULL;
}
if (faud) {
FAudio_Release(faud);
faud = nullptr;
faud = NULL;
}
}
@@ -234,7 +234,7 @@ bool FAudio_Output::init(long sampleRate) {
// create sound receiver
hr = FAudio_CreateMasteringVoice(faud, &mVoice, FAUDIO_DEFAULT_CHANNELS,
FAUDIO_DEFAULT_SAMPLERATE, 0, FAGetDev(faud), nullptr);
FAUDIO_DEFAULT_SAMPLERATE, 0, FAGetDev(faud), NULL);
if (hr != 0) {
wxLogError(_("FAudio: Creating mastering voice failed!"));
@@ -243,7 +243,7 @@ bool FAudio_Output::init(long sampleRate) {
}
// create sound emitter
hr = FAudio_CreateSourceVoice(faud, &sVoice, &wfx, 0, 4.0f, &notify, nullptr, nullptr);
hr = FAudio_CreateSourceVoice(faud, &sVoice, &wfx, 0, 4.0f, &notify, NULL, NULL);
if (hr != 0) {
wxLogError(_("FAudio: Creating source voice failed!"));
@@ -346,7 +346,7 @@ bool FAudio_Output::init(long sampleRate) {
}
if (matrixAvailable) {
hr = FAudioVoice_SetOutputMatrix(sVoice, nullptr, 2, dd.OutputFormat.Format.nChannels,
hr = FAudioVoice_SetOutputMatrix(sVoice, NULL, 2, dd.OutputFormat.Format.nChannels,
matrix.data(), FAUDIO_DEFAULT_CHANNELS);
VBAM_CHECK(hr == 0);
}
@@ -408,7 +408,7 @@ void FAudio_Output::write(uint16_t* finalWave, int) {
buf.pAudioData = &buffers_[currentBuffer * sound_buffer_len_];
currentBuffer++;
currentBuffer %= (buffer_count_ + 1); // + 1 because we need one temporary buffer
[[maybe_unused]] uint32_t hr = FAudioSourceVoice_SubmitSourceBuffer(sVoice, &buf, nullptr);
[[maybe_unused]] uint32_t hr = FAudioSourceVoice_SubmitSourceBuffer(sVoice, &buf, NULL);
VBAM_CHECK(hr == 0);
}
@@ -463,7 +463,7 @@ void FAudio_Output::setThrottle(unsigned short throttle_) {
} // namespace
std::vector<AudioDevice> GetFAudioDevices() {
FAudio* fa = nullptr;
FAudio* fa = NULL;
uint32_t hr;
uint32_t flags = 0;
#ifdef _DEBUG

View File

@@ -94,8 +94,8 @@ private:
OpenAL::OpenAL() {
initialized = false;
buffersLoaded = false;
device = nullptr;
context = nullptr;
device = NULL;
context = NULL;
buffer = (ALuint*)malloc(OPTION(kSoundBuffers) * sizeof(ALuint));
memset(buffer, 0, OPTION(kSoundBuffers) * sizeof(ALuint));
tempBuffer = 0;
@@ -115,7 +115,7 @@ OpenAL::~OpenAL() {
alDeleteBuffers(OPTION(kSoundBuffers), buffer);
ASSERT_SUCCESS;
free(buffer);
alcMakeContextCurrent(nullptr);
alcMakeContextCurrent(NULL);
// Wine incorrectly returns ALC_INVALID_VALUE
// and then fails the rest of these functions as well
// so there will be a leak under Wine, but that's a bug in Wine, not
@@ -175,13 +175,13 @@ bool OpenAL::init(long sampleRate) {
const wxString& audio_device = OPTION(kSoundAudioDevice);
if (!audio_device.empty()) {
device = alcOpenDevice(audio_device.utf8_str());
if (device == nullptr) {
if (device == NULL) {
// Might be the default device. Try again.
OPTION(kSoundAudioDevice) = wxEmptyString;
device = alcOpenDevice(nullptr);
device = alcOpenDevice(NULL);
}
} else {
device = alcOpenDevice(nullptr);
device = alcOpenDevice(NULL);
}
if (!device) {
@@ -189,8 +189,8 @@ bool OpenAL::init(long sampleRate) {
return false;
}
context = alcCreateContext(device, nullptr);
VBAM_CHECK(context != nullptr);
context = alcCreateContext(device, NULL);
VBAM_CHECK(context != NULL);
ALCboolean retVal = alcMakeContextCurrent(context);
VBAM_CHECK(ALC_TRUE == retVal);
alGenBuffers(OPTION(kSoundBuffers), buffer);
@@ -368,12 +368,12 @@ std::vector<AudioDevice> GetOpenALDevices() {
#ifdef ALC_DEVICE_SPECIFIER
if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_FALSE) {
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_FALSE) {
// this extension isn't critical to OpenAL operating
return devices;
}
const char* devs = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
const char* devs = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
while (*devs) {
const wxString device_name(devs, wxConvLibc);

View File

@@ -104,7 +104,7 @@ void SDLAudio::deinit() {
SDL_UnlockMutex(mutex);
SDL_DestroyMutex(mutex);
mutex = nullptr;
mutex = NULL;
SDL_CloseAudioDevice(sound_device);
@@ -152,13 +152,13 @@ bool SDLAudio::init(long sampleRate) {
#endif
return false;
}
#ifdef ENABLE_SDL3
if (SDL_WasInit(SDL_INIT_AUDIO) == false) {
if (SDL_Init(SDL_INIT_AUDIO) == false) {
#else
if (SDL_WasInit(SDL_INIT_AUDIO) < 0) {
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
#endif
SDL_Init(SDL_INIT_AUDIO);
return false;
}
#ifdef ENABLE_SDL3

View File

@@ -584,7 +584,7 @@ void xaudio2_device_changed(XAudio2_Output* instance) {
std::vector<AudioDevice> GetXAudio2Devices() {
HRESULT hr;
IXAudio2* xa = nullptr;
IXAudio2* xa = NULL;
hr = XAudio2Create(&xa, 0);
if (hr != S_OK) {

View File

@@ -36,5 +36,5 @@ SparkleWrapper::~SparkleWrapper()
void SparkleWrapper::checkForUpdatesUi()
{
[d->updater checkForUpdates: nullptr];
[d->updater checkForUpdates: NULL];
}

View File

@@ -42,7 +42,7 @@ WinSparkleDllWrapper::WinSparkleDllWrapper()
winsparkle_dll = LoadLibraryW(temp_file_name.wc_str());
if (winsparkle_dll != nullptr) {
if (winsparkle_dll != NULL) {
winsparkle_init = reinterpret_cast<func_win_sparkle_init>(GetProcAddress(winsparkle_dll, "win_sparkle_init"));
winsparkle_check_update_with_ui = reinterpret_cast<func_win_sparkle_check_update_with_ui>(GetProcAddress(winsparkle_dll, "win_sparkle_check_update_with_ui"));
winsparkle_set_appcast_url = reinterpret_cast<func_win_sparkle_set_appcast_url>(GetProcAddress(winsparkle_dll, "win_sparkle_set_appcast_url"));
@@ -54,7 +54,7 @@ WinSparkleDllWrapper::WinSparkleDllWrapper()
WinSparkleDllWrapper::~WinSparkleDllWrapper()
{
if (winsparkle_dll != nullptr) {
if (winsparkle_dll != NULL) {
while(::FreeLibrary(winsparkle_dll)) {
wxMilliSleep(200);
}

View File

@@ -22,11 +22,11 @@ private:
HMODULE winsparkle_dll;
func_win_sparkle_init winsparkle_init = nullptr;
func_win_sparkle_check_update_with_ui winsparkle_check_update_with_ui = nullptr;
func_win_sparkle_set_appcast_url winsparkle_set_appcast_url = nullptr;
func_win_sparkle_set_app_details winsparkle_set_app_details = nullptr;
func_win_sparkle_cleanup winsparkle_cleanup = nullptr;
func_win_sparkle_init winsparkle_init = NULL;
func_win_sparkle_check_update_with_ui winsparkle_check_update_with_ui = NULL;
func_win_sparkle_set_appcast_url winsparkle_set_appcast_url = NULL;
func_win_sparkle_set_app_details winsparkle_set_app_details = NULL;
func_win_sparkle_cleanup winsparkle_cleanup = NULL;
wxString temp_file_name;

View File

@@ -494,7 +494,7 @@ private:
SHORT previousState[0xFF];
#elif defined(__WXMAC__)
#else // defined(__WXGTK__)
Display *x11display = nullptr;
Display *x11display = NULL;
char previousState[32];
char currentState[32];
int keySymsPerKeycode;
@@ -629,7 +629,7 @@ void BackgroundInput::Cleanup()
#else // defined(__WXGTK__)
if (x11display) {
XCloseDisplay(x11display);
x11display = nullptr;
x11display = NULL;
}
#endif
}
@@ -648,7 +648,7 @@ wxThread::ExitCode BackgroundInput::Entry()
return NO_ERROR;
}
BackgroundInput *input = nullptr;
BackgroundInput *input = NULL;
void enableKeyboardBackgroundInput(wxEvtHandler* handler)
{
@@ -658,7 +658,7 @@ void enableKeyboardBackgroundInput(wxEvtHandler* handler)
{
wxLogError(wxT("Failed to create keyboard thread!"));
delete input;
input = nullptr;
input = NULL;
}
}
@@ -667,5 +667,5 @@ void disableKeyboardBackgroundInput()
if (input && input->IsRunning()) {
input->Delete();
}
input = nullptr;
input = NULL;
}

View File

@@ -58,7 +58,7 @@ void RefreshFrame(void)
if (wxGetApp().frame)
wxGetApp().frame->Destroy();
wxGetApp().frame = wxDynamicCast(xr->LoadFrame(nullptr, "MainFrame"), MainFrame);
wxGetApp().frame = wxDynamicCast(xr->LoadFrame(NULL, "MainFrame"), MainFrame);
if (!wxGetApp().frame) {
wxLogError(_("Could not create main window"));
return;
@@ -2330,7 +2330,7 @@ EVT_HANDLER(UpdateEmu, "Check for updates...")
EVT_HANDLER(FactoryReset, "Factory Reset...")
{
wxMessageDialog dlg(
nullptr, _("YOUR CONFIGURATION WILL BE DELETED!\n\nAre you sure?"),
NULL, _("YOUR CONFIGURATION WILL BE DELETED!\n\nAre you sure?"),
_("FACTORY RESET"), wxYES_NO | wxNO_DEFAULT | wxCENTRE);
if (dlg.ShowModal() == wxID_YES) {
@@ -2800,26 +2800,6 @@ EVT_HANDLER(Language3, "Czech")
RefreshFrame();
}
EVT_HANDLER(Language4, "German")
{
OPTION(kLocale) = wxLANGUAGE_GERMAN;
if (wxvbam_locale != NULL)
wxDELETE(wxvbam_locale);
wxvbam_locale = new wxLocale;
wxvbam_locale->Init(OPTION(kLocale), wxLOCALE_LOAD_DEFAULT);
#ifdef _WIN32
wxTranslations::Get()->SetLoader(new wxResourceTranslationsLoader);
#endif
wxvbam_locale->AddCatalog("wxvbam", wxLANGUAGE_GERMAN);
update_opts();
RefreshFrame();
}
EVT_HANDLER(Language5, "Greek")
{
OPTION(kLocale) = wxLANGUAGE_GREEK;

View File

@@ -29,7 +29,7 @@ cmditem new_cmditem(const wxString cmd = "",
const wxString name = "",
int cmd_id = 0,
int mask_flags = 0,
wxMenuItem* mi = nullptr);
wxMenuItem* mi = NULL);
namespace config {
// Returns the command INI entry name for the given XRC ID. Will assert if

View File

@@ -83,6 +83,15 @@ static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
#endif
};
// These MUST follow the same order as the definitions of the enum.
// Adding an option without adding to this array will result in a compiler
// error since kNbColorCorrectionProfiles is automatically updated.
static const std::array<wxString, kNbColorCorrectionProfiles> kColorCorrectionProfileStrings = {
"srgb",
"dci",
"rec2020"
};
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbAudioApis is automatically updated.
@@ -142,6 +151,7 @@ std::array<Option, kNbOptions>& Option::All() {
struct OwnedOptions {
/// Display
bool bilinear = true;
bool sdl_pixel_art = false;
Filter filter = Filter::kNone;
wxString filter_plugin = wxEmptyString;
Interframe interframe = Interframe::kNone;
@@ -158,27 +168,32 @@ std::array<Option, kNbOptions>& Option::All() {
RenderMethod render_method = RenderMethod::kOpenGL;
#endif
#endif
ColorCorrectionProfile color_correction_profile = ColorCorrectionProfile::kSRGB;
double video_scale = 3;
bool retain_aspect = true;
/// GB
wxString gb_bios = wxEmptyString;
bool colorizer_hack = false;
bool gb_lcd_filter = false;
bool gb_lcd_filter = true;
wxString gbc_bios = wxEmptyString;
bool print_auto_page = true;
bool print_screen_cap = false;
wxString gb_rom_dir = wxEmptyString;
wxString gbc_rom_dir = wxEmptyString;
uint32_t gb_lighten = 0;
/// GBA
bool gba_lcd_filter = false;
bool gba_lcd_filter = true;
#ifndef NO_LINK
bool link_auto = false;
bool link_hacks = true;
bool link_proto = false;
#endif
wxString gba_rom_dir;
uint32_t gba_darken = 37;
/// Core
bool agb_print = false;
@@ -266,6 +281,7 @@ std::array<Option, kNbOptions>& Option::All() {
static std::array<Option, kNbOptions> g_all_opts = {
/// Display
Option(OptionID::kDispBilinear, &g_owned_opts.bilinear),
Option(OptionID::kDispSDLPixelArt, &g_owned_opts.sdl_pixel_art),
Option(OptionID::kDispFilter, &g_owned_opts.filter),
Option(OptionID::kDispFilterPlugin, &g_owned_opts.filter_plugin),
Option(OptionID::kDispIFB, &g_owned_opts.interframe),
@@ -276,6 +292,7 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kDispScale, &g_owned_opts.video_scale, 1, 6),
Option(OptionID::kDispStretch, &g_owned_opts.retain_aspect),
Option(OptionID::kSDLRenderer, &g_owned_opts.sdlrenderer),
Option(OptionID::kDispColorCorrectionProfile, &g_owned_opts.color_correction_profile),
/// GB
Option(OptionID::kGBBiosFile, &g_owned_opts.gb_bios),
@@ -290,6 +307,7 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kGBPrintScreenCap, &g_owned_opts.print_screen_cap),
Option(OptionID::kGBROMDir, &g_owned_opts.gb_rom_dir),
Option(OptionID::kGBGBCROMDir, &g_owned_opts.gbc_rom_dir),
Option(OptionID::kGBLighten, &g_owned_opts.gb_lighten, 0, 100),
/// GBA
Option(OptionID::kGBABiosFile, &gopts.gba_bios),
@@ -305,6 +323,7 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kGBALinkType, &gopts.gba_link_type, 0, 5),
#endif
Option(OptionID::kGBAROMDir, &g_owned_opts.gba_rom_dir),
Option(OptionID::kGBADarken, &g_owned_opts.gba_darken, 0, 100),
/// General
Option(OptionID::kGenAutoLoadLastState, &g_owned_opts.autoload_state),
@@ -410,6 +429,7 @@ namespace internal {
const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
/// Display
OptionData{"Display/Bilinear", "Bilinear", _("Use bilinear filter with 3d renderer")},
OptionData{"Display/SDLPixelArt", "SDLPixelArt", _("Use the SDL pixel art filter with an SDL renderer")},
OptionData{"Display/Filter", "", _("Full-screen filter to apply")},
OptionData{"Display/FilterPlugin", "", _("Filter plugin library")},
OptionData{"Display/IFB", "", _("Interframe blending function")},
@@ -422,6 +442,7 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
OptionData{"Display/Scale", "", _("Default scale factor")},
OptionData{"Display/Stretch", "RetainAspect", _("Retain aspect ratio when resizing")},
OptionData{"Display/SDLRenderer", "", _("SDL renderer")},
OptionData{"Display/ColorCorrectionProfile", "", _("Color correction profile")},
/// GB
OptionData{"GB/BiosFile", "", _("BIOS file to use for Game Boy, if enabled")},
@@ -445,6 +466,7 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
"suffix")},
OptionData{"GB/ROMDir", "", _("Directory to look for ROM files")},
OptionData{"GB/GBCROMDir", "", _("Directory to look for Game Boy Color ROM files")},
OptionData{"GB/GBCLighten", "", _("Color lightness factor")},
/// GBA
OptionData{"GBA/BiosFile", "", _("BIOS file to use, if enabled")},
@@ -472,6 +494,7 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
OptionData{"GBA/LinkType", "LinkType", _("Link cable type")},
#endif
OptionData{"GBA/ROMDir", "", _("Directory to look for ROM files")},
OptionData{"GBA/GBADarken", "", _("Color darkness factor")},
/// General
OptionData{"General/AutoLoadLastState", "", _("Automatically load last saved state")},
@@ -652,6 +675,12 @@ wxString RenderMethodToString(const RenderMethod& value) {
return kRenderMethodStrings[size_value];
}
wxString ColorCorrectionProfileToString(const ColorCorrectionProfile& value) {
const size_t size_value = static_cast<size_t>(value);
VBAM_CHECK(size_value < kNbColorCorrectionProfiles);
return kColorCorrectionProfileStrings[size_value];
}
wxString AudioApiToString(const AudioApi& value) {
const size_t size_value = static_cast<size_t>(value);
VBAM_CHECK(size_value < kNbAudioApis);
@@ -725,6 +754,27 @@ RenderMethod StringToRenderMethod(const wxString& config_name,
return iter->second;
}
ColorCorrectionProfile StringToColorCorrectionProfile(const wxString& config_name,
const wxString& input) {
static const std::map<wxString, ColorCorrectionProfile> kStringToColorCorrectionProfile([] {
std::map<wxString, ColorCorrectionProfile> string_to_color_correction_profile;
for (size_t i = 0; i < kNbColorCorrectionProfiles; i++) {
string_to_color_correction_profile.emplace(kColorCorrectionProfileStrings[i], static_cast<ColorCorrectionProfile>(i));
}
VBAM_CHECK(string_to_color_correction_profile.size() == kNbColorCorrectionProfiles);
return string_to_color_correction_profile;
}());
const auto iter = kStringToColorCorrectionProfile.find(input);
if (iter == kStringToColorCorrectionProfile.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input, config_name,
AllEnumValuesForType(Option::Type::kColorCorrectionProfile));
return ColorCorrectionProfile::kSRGB;
}
return iter->second;
}
AudioApi StringToAudioApi(const wxString& config_name, const wxString& input) {
static const std::map<wxString, AudioApi> kStringToAudioApi([] {
std::map<wxString, AudioApi> string_to_audio_api;
@@ -778,6 +828,10 @@ wxString AllEnumValuesForType(Option::Type type) {
static const wxString kAllRenderValues(AllEnumValuesForArray(kRenderMethodStrings));
return kAllRenderValues;
}
case Option::Type::kColorCorrectionProfile: {
static const wxString kAllColorCorrectionValues(AllEnumValuesForArray(kColorCorrectionProfileStrings));
return kAllColorCorrectionValues;
}
case Option::Type::kAudioApi: {
static const wxString kAllAudioApiValues(AllEnumValuesForArray(kAudioApiStrings));
return kAllAudioApiValues;
@@ -811,6 +865,8 @@ size_t MaxForType(Option::Type type) {
return kNbInterframes;
case Option::Type::kRenderMethod:
return kNbRenderMethods;
case Option::Type::kColorCorrectionProfile:
return kNbColorCorrectionProfiles;
case Option::Type::kAudioApi:
return kNbAudioApis;
case Option::Type::kAudioRate:

View File

@@ -27,11 +27,13 @@ nonstd::optional<OptionID> StringToOptionId(const wxString& input);
wxString FilterToString(const Filter& value);
wxString InterframeToString(const Interframe& value);
wxString RenderMethodToString(const RenderMethod& value);
wxString ColorCorrectionProfileToString(const ColorCorrectionProfile& value);
wxString AudioApiToString(const AudioApi& value);
wxString AudioRateToString(const AudioRate& value);
Filter StringToFilter(const wxString& config_name, const wxString& input);
Interframe StringToInterframe(const wxString& config_name, const wxString& input);
RenderMethod StringToRenderMethod(const wxString& config_name, const wxString& input);
ColorCorrectionProfile StringToColorCorrectionProfile(const wxString& config_name, const wxString& input);
AudioApi StringToAudioApi(const wxString& config_name, const wxString& input);
AudioRate StringToSoundQuality(const wxString& config_name, const wxString& input);

View File

@@ -8,6 +8,7 @@ namespace config {
enum class OptionID {
/// Display
kDispBilinear = 0,
kDispSDLPixelArt,
kDispFilter,
kDispFilterPlugin,
kDispIFB,
@@ -18,6 +19,7 @@ enum class OptionID {
kDispScale,
kDispStretch,
kSDLRenderer,
kDispColorCorrectionProfile,
/// GB
kGBBiosFile,
@@ -32,6 +34,7 @@ enum class OptionID {
kGBPrintScreenCap,
kGBROMDir,
kGBGBCROMDir,
kGBLighten,
/// GBA
kGBABiosFile,
@@ -47,6 +50,7 @@ enum class OptionID {
kGBALinkType,
#endif
kGBAROMDir,
kGBADarken,
/// General
kGenAutoLoadLastState,

View File

@@ -12,6 +12,7 @@ namespace config {
static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/// Display
/*kDispBilinear*/ Option::Type::kBool,
/*kDispSDLPixelArt*/ Option::Type::kBool,
/*kDispFilter*/ Option::Type::kFilter,
/*kDispFilterPlugin*/ Option::Type::kString,
/*kDispIFB*/ Option::Type::kInterframe,
@@ -22,6 +23,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kDispScale*/ Option::Type::kDouble,
/*kDispStretch*/ Option::Type::kBool,
/*kSDLRenderer*/ Option::Type::kString,
/*kDispColorCorrectionProfile*/ Option::Type::kColorCorrectionProfile,
/// GB
/*kGBBiosFile*/ Option::Type::kString,
@@ -36,6 +38,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kGBPrintScreenCap*/ Option::Type::kBool,
/*kGBROMDir*/ Option::Type::kString,
/*kGBGBCROMDir*/ Option::Type::kString,
/*kGBLighten*/ Option::Type::kUnsigned,
/// GBA
/*kGBABiosFile*/ Option::Type::kString,
@@ -51,6 +54,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kGBALinkType*/ Option::Type::kInt,
#endif
/*kGBAROMDir*/ Option::Type::kString,
/*kGBADarken*/ Option::Type::kUnsigned,
/// General
/*kGenAutoLoadLastState*/ Option::Type::kBool,
@@ -346,6 +350,25 @@ private:
Option* option_;
};
template <OptionID ID>
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kColorCorrectionProfile>::type> {
public:
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
ColorCorrectionProfile Get() const { return option_->GetColorCorrectionProfile(); }
bool Set(ColorCorrectionProfile value) { return option_->SetColorCorrectionProfile(value); }
bool operator=(ColorCorrectionProfile value) { return Set(value); }
operator ColorCorrectionProfile() const { return Get(); }
private:
Option* option_;
};
template <OptionID ID>
class OptionProxy<
ID,

View File

@@ -20,7 +20,7 @@ namespace config {
Option* Option::ByName(const wxString& config_name) {
nonstd::optional<OptionID> option_id = internal::StringToOptionId(config_name);
if (!option_id) {
return nullptr;
return NULL;
}
return ByID(option_id.value());
}
@@ -167,6 +167,19 @@ Option::Option(OptionID id, RenderMethod* option)
VBAM_CHECK(is_render_method());
}
Option::Option(OptionID id, ColorCorrectionProfile* option)
: id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(kOptionsTypes[static_cast<size_t>(id)]),
value_(option),
min_(),
max_(nonstd::in_place_type<size_t>, internal::MaxForType(type_)) {
VBAM_CHECK(id != OptionID::Last);
VBAM_CHECK(is_color_correction_profile());
}
Option::Option(OptionID id, AudioApi* option)
: id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
@@ -246,6 +259,11 @@ RenderMethod Option::GetRenderMethod() const {
return *(nonstd::get<RenderMethod*>(value_));
}
ColorCorrectionProfile Option::GetColorCorrectionProfile() const {
VBAM_CHECK(is_color_correction_profile());
return *(nonstd::get<ColorCorrectionProfile*>(value_));
}
AudioApi Option::GetAudioApi() const {
VBAM_CHECK(is_audio_api());
return *(nonstd::get<AudioApi*>(value_));
@@ -264,6 +282,8 @@ wxString Option::GetEnumString() const {
return internal::InterframeToString(GetInterframe());
case Option::Type::kRenderMethod:
return internal::RenderMethodToString(GetRenderMethod());
case Option::Type::kColorCorrectionProfile:
return internal::ColorCorrectionProfileToString(GetColorCorrectionProfile());
case Option::Type::kAudioApi:
return internal::AudioApiToString(GetAudioApi());
case Option::Type::kAudioRate:
@@ -402,6 +422,17 @@ bool Option::SetRenderMethod(const RenderMethod& value) {
return true;
}
bool Option::SetColorCorrectionProfile(const ColorCorrectionProfile& value) {
VBAM_CHECK(is_color_correction_profile());
VBAM_CHECK(value < ColorCorrectionProfile::kLast);
const ColorCorrectionProfile old_value = GetColorCorrectionProfile();
*nonstd::get<ColorCorrectionProfile*>(value_) = value;
if (old_value != value) {
CallObservers();
}
return true;
}
bool Option::SetAudioApi(const AudioApi& value) {
VBAM_CHECK(is_audio_api());
VBAM_CHECK(value < AudioApi::kLast);
@@ -432,6 +463,8 @@ bool Option::SetEnumString(const wxString& value) {
return SetInterframe(internal::StringToInterframe(config_name_, value));
case Option::Type::kRenderMethod:
return SetRenderMethod(internal::StringToRenderMethod(config_name_, value));
case Option::Type::kColorCorrectionProfile:
return SetColorCorrectionProfile(internal::StringToColorCorrectionProfile(config_name_, value));
case Option::Type::kAudioApi:
return SetAudioApi(internal::StringToAudioApi(config_name_, value));
case Option::Type::kAudioRate:
@@ -571,6 +604,7 @@ wxString Option::ToHelperString() const {
case Option::Type::kFilter:
case Option::Type::kInterframe:
case Option::Type::kRenderMethod:
case Option::Type::kColorCorrectionProfile:
case Option::Type::kAudioApi:
case Option::Type::kAudioRate:
helper_string.Append(" (");

View File

@@ -81,6 +81,17 @@ enum class RenderMethod {
};
static constexpr size_t kNbRenderMethods = static_cast<size_t>(RenderMethod::kLast);
// Values for kDispColorCorrectionProfile.
enum class ColorCorrectionProfile {
kSRGB = 0,
kDCI,
kRec2020,
// Do not add anything under here.
kLast,
};
static constexpr size_t kNbColorCorrectionProfiles = static_cast<size_t>(ColorCorrectionProfile::kLast);
// Values for kAudioApi.
enum class AudioApi {
kOpenAL,
@@ -116,7 +127,7 @@ static constexpr size_t kNbSoundRate = static_cast<size_t>(AudioRate::kLast);
// This is incremented whenever we want to change a default value between
// release versions. The option update code is in load_opts.
static constexpr uint32_t kIniLatestVersion = 1;
static constexpr uint32_t kIniLatestVersion = 2;
// Represents a single option saved in the INI file. Option does not own the
// individual option, but keeps a pointer to where the data is actually saved.
@@ -143,6 +154,7 @@ public:
kFilter,
kInterframe,
kRenderMethod,
kColorCorrectionProfile,
kAudioApi,
kAudioRate,
kGbPalette,
@@ -200,6 +212,7 @@ public:
bool is_filter() const { return type() == Type::kFilter; }
bool is_interframe() const { return type() == Type::kInterframe; }
bool is_render_method() const { return type() == Type::kRenderMethod; }
bool is_color_correction_profile() const { return type() == Type::kColorCorrectionProfile; }
bool is_audio_api() const { return type() == Type::kAudioApi; }
bool is_audio_rate() const { return type() == Type::kAudioRate; }
bool is_gb_palette() const { return type() == Type::kGbPalette; }
@@ -214,6 +227,7 @@ public:
Filter GetFilter() const;
Interframe GetInterframe() const;
RenderMethod GetRenderMethod() const;
ColorCorrectionProfile GetColorCorrectionProfile() const;
AudioApi GetAudioApi() const;
AudioRate GetAudioRate() const;
wxString GetEnumString() const;
@@ -231,6 +245,7 @@ public:
bool SetFilter(const Filter& value);
bool SetInterframe(const Interframe& value);
bool SetRenderMethod(const RenderMethod& value);
bool SetColorCorrectionProfile(const ColorCorrectionProfile& value);
bool SetAudioApi(const AudioApi& value);
bool SetAudioRate(const AudioRate& value);
bool SetEnumString(const wxString& value);
@@ -267,6 +282,7 @@ private:
Option(OptionID id, Filter* option);
Option(OptionID id, Interframe* option);
Option(OptionID id, RenderMethod* option);
Option(OptionID id, ColorCorrectionProfile* option);
Option(OptionID id, AudioApi* option);
Option(OptionID id, AudioRate* option);
Option(OptionID id, int* option);
@@ -299,6 +315,7 @@ private:
Filter*,
Interframe*,
RenderMethod*,
ColorCorrectionProfile*,
AudioApi*,
AudioRate*,
uint16_t*>

View File

@@ -223,6 +223,41 @@ private:
const config::RenderMethod render_method_;
};
// Validator for a wxRadioButton with a ColorCorrectionProfile value.
class ColorCorrectionProfileValidator : public widgets::OptionValidator {
public:
explicit ColorCorrectionProfileValidator(config::ColorCorrectionProfile color_correction_profile)
: OptionValidator(config::OptionID::kDispColorCorrectionProfile),
color_correction_profile_(color_correction_profile) {
VBAM_CHECK(color_correction_profile != config::ColorCorrectionProfile::kLast);
}
~ColorCorrectionProfileValidator() override = default;
private:
// OptionValidator implementation.
wxObject* Clone() const override {
return new ColorCorrectionProfileValidator(color_correction_profile_);
}
bool IsWindowValueValid() override { return true; }
bool WriteToWindow() override {
wxDynamicCast(GetWindow(), wxRadioButton)
->SetValue(option()->GetColorCorrectionProfile() == color_correction_profile_);
return true;
}
bool WriteToOption() override {
if (wxDynamicCast(GetWindow(), wxRadioButton)->GetValue()) {
return option()->SetColorCorrectionProfile(color_correction_profile_);
}
return true;
}
const config::ColorCorrectionProfile color_correction_profile_;
};
class PluginSelectorValidator : public widgets::OptionValidator {
public:
PluginSelectorValidator()
@@ -351,6 +386,46 @@ DisplayConfig::DisplayConfig(wxWindow* parent)
sdlrenderer_selector_ = GetValidatedChild<wxChoice>("SDLRenderer");
sdlrenderer_selector_->SetValidator(SDLDevicesValidator());
#if !defined(ENABLE_SDL3) || !defined(HAVE_SDL3_PIXELART)
GetValidatedChild<wxCheckBox>("SDLPixelArt")->Hide();
#else
GetValidatedChild<wxCheckBox>("SDLPixelArt")
->SetValidator(
widgets::OptionBoolValidator(config::OptionID::kDispSDLPixelArt));
#endif
wxWindow* color_profile_srgb = GetValidatedChild("ColorProfileSRGB");
color_profile_srgb->SetValidator(
ColorCorrectionProfileValidator(config::ColorCorrectionProfile::kSRGB));
wxWindow* color_profile_dci = GetValidatedChild("ColorProfileDCI");
color_profile_dci->SetValidator(
ColorCorrectionProfileValidator(config::ColorCorrectionProfile::kDCI));
wxWindow* color_profile_rec2020 = GetValidatedChild("ColorProfileRec2020");
color_profile_rec2020->SetValidator(
ColorCorrectionProfileValidator(config::ColorCorrectionProfile::kRec2020));
switch (OPTION(kDispColorCorrectionProfile)) {
case config::ColorCorrectionProfile::kSRGB:
wxDynamicCast(color_profile_srgb, wxRadioButton)->SetValue(true);
break;
case config::ColorCorrectionProfile::kDCI:
wxDynamicCast(color_profile_dci, wxRadioButton)->SetValue(true);
break;
case config::ColorCorrectionProfile::kRec2020:
wxDynamicCast(color_profile_rec2020, wxRadioButton)->SetValue(true);
break;
default:
wxLogError(_("Invalid color correction profile"));
}
wxSlider* gba_darken_slider = GetValidatedChild<wxSlider>("GBADarken");
gba_darken_slider->SetValidator(widgets::OptionUnsignedValidator(config::OptionID::kGBADarken));
wxSlider* gbc_lighten_slider = GetValidatedChild<wxSlider>("GBCLighten");
gbc_lighten_slider->SetValidator(widgets::OptionUnsignedValidator(config::OptionID::kGBLighten));
filter_selector_ = GetValidatedChild<wxChoice>("Filter");
filter_selector_->SetValidator(FilterValidator());
filter_selector_->Bind(wxEVT_CHOICE, &DisplayConfig::UpdatePlugin, this,

View File

@@ -97,8 +97,8 @@ JoypadConfig::JoypadConfig(wxWindow* parent, const config::BindingsProvider bind
// Set up tab order so input is easy to configure. Note that there are
// two tabs for each panel, so we must check for the parent before
// setting up the tab order.
wxWindow* prev = nullptr;
wxWindow* prev_parent = nullptr;
wxWindow* prev = NULL;
wxWindow* prev_parent = NULL;
for (const config::GameKey& game_key : config::kAllGameKeys) {
const wxString game_key_name = config::GameKeyToString(game_key);
widgets::UserInputCtrl* game_key_control =

View File

@@ -40,7 +40,7 @@ protected:
void AdjustViewport();
void RefreshGL();
#ifndef wxGL_IMPLICIT_CONTEXT
wxGLContext* ctx = nullptr;
wxGLContext* ctx = NULL;
#endif
bool SetContext();
void DrawingPanelInit();

View File

@@ -1830,20 +1830,20 @@ bool MainFrame::BindControls()
// remove this item from the menu completely
wxMenuItem* gdbmi = XRCITEM("GDBMenu");
gdbmi->GetMenu()->Remove(gdbmi);
gdbmi = nullptr;
gdbmi = NULL;
#endif // !defined(VBAM_ENABLE_DEBUGGER)
#ifdef NO_LINK
// remove this item from the menu completely
wxMenuItem* linkmi = XRCITEM("LinkMenu");
linkmi->GetMenu()->Remove(linkmi);
linkmi = nullptr;
linkmi = NULL;
#endif
#ifdef __WXMAC__
// Remove hide menubar in the UI Config submenu on macOS, because it is meaningless there.
wxMenuItem* hide_menu_bar = XRCITEM("HideMenuBar");
hide_menu_bar->GetMenu()->Remove(hide_menu_bar);
hide_menu_bar = nullptr;
hide_menu_bar = NULL;
#endif
// if a recent menu is present, save its location
@@ -1925,7 +1925,6 @@ bool MainFrame::BindControls()
MenuOptionIntRadioValue("Language1", OPTION(kLocale), wxLANGUAGE_BULGARIAN);
MenuOptionIntRadioValue("Language2", OPTION(kLocale), wxLANGUAGE_BRETON);
MenuOptionIntRadioValue("Language3", OPTION(kLocale), wxLANGUAGE_CZECH);
MenuOptionIntRadioValue("Language4", OPTION(kLocale), wxLANGUAGE_GERMAN);
MenuOptionIntRadioValue("Language5", OPTION(kLocale), wxLANGUAGE_GREEK);
MenuOptionIntRadioValue("Language6", OPTION(kLocale), wxLANGUAGE_ENGLISH_US);
MenuOptionIntRadioValue("Language7", OPTION(kLocale), wxLANGUAGE_SPANISH_LATIN_AMERICA);

View File

@@ -268,7 +268,7 @@ void MetalDrawingPanel::DrawArea()
DrawingPanelInit();
if (systemColorDepth == 8) {
srcPitch = std::ceil(width * scale) + 2;
srcPitch = std::ceil(width * scale) + 4;
} else if (systemColorDepth == 16) {
srcPitch = std::ceil(width * scale * 2) + 4;
} else if (systemColorDepth == 24) {
@@ -302,7 +302,7 @@ void MetalDrawingPanel::DrawArea()
src_pos++;
}
pos++;
src_pos += 2;
src_pos += 4;
}
_texture = loadTextureUsingData(dst);

View File

@@ -54,6 +54,7 @@ void SaveOption(config::Option* option) {
case config::Option::Type::kFilter:
case config::Option::Type::kInterframe:
case config::Option::Type::kRenderMethod:
case config::Option::Type::kColorCorrectionProfile:
case config::Option::Type::kAudioApi:
case config::Option::Type::kAudioRate:
cfg->Write(option->config_name(), option->GetEnumString());
@@ -290,6 +291,7 @@ void load_opts(bool first_time_launch) {
case config::Option::Type::kFilter:
case config::Option::Type::kInterframe:
case config::Option::Type::kRenderMethod:
case config::Option::Type::kColorCorrectionProfile:
case config::Option::Type::kAudioApi:
case config::Option::Type::kAudioRate: {
wxString temp;
@@ -380,8 +382,11 @@ void load_opts(bool first_time_launch) {
OPTION(kGBALinkTimeout) = 500;
}
#endif
// Previous default was true.
OPTION(kGBALCDFilter) = false;
}
case 1: { // up to 2.2.2 included.
// Previous defaults were false.
OPTION(kGBALCDFilter) = true;
OPTION(kGBLCDFilter) = true;
}
}
ini_version++;
@@ -475,6 +480,7 @@ void opt_set(const wxString& name, const wxString& val) {
case config::Option::Type::kFilter:
case config::Option::Type::kInterframe:
case config::Option::Type::kRenderMethod:
case config::Option::Type::kColorCorrectionProfile:
case config::Option::Type::kAudioApi:
case config::Option::Type::kAudioRate:
opt->SetEnumString(val);

View File

@@ -39,7 +39,7 @@ extern struct opts_t {
int sound_en = 0x30f; // soundSetEnable()
/// Recent
wxFileHistory* recent = nullptr;
wxFileHistory* recent = NULL;
/// UI Config
bool hide_menu_bar = true;

View File

@@ -35,6 +35,7 @@
#include "components/draw_text/draw_text.h"
#include "components/filters/filters.h"
#include "components/filters_agb/filters_agb.h"
#include "components/filters_cgb/filters_cgb.h"
#include "components/filters_interframe/interframe.h"
#include "core/base/check.h"
#include "core/base/file_util.h"
@@ -175,7 +176,7 @@ GameArea::GameArea()
gb_declick_observer_(
config::OptionID::kSoundGBDeclicking,
[&](config::Option* option) { gbSoundSetDeclicking(option->GetBool()); }),
lcd_filters_observer_({config::OptionID::kGBLCDFilter, config::OptionID::kGBALCDFilter},
lcd_filters_observer_({config::OptionID::kGBLCDFilter, config::OptionID::kGBADarken, config::OptionID::kGBLighten, config::OptionID::kDispColorCorrectionProfile, config::OptionID::kGBALCDFilter},
std::bind(&GameArea::UpdateLcdFilter, this)),
audio_rate_observer_(config::OptionID::kSoundAudioRate,
std::bind(&GameArea::OnAudioRateChanged, this)),
@@ -932,7 +933,7 @@ void GameArea::AdjustSize(bool force)
void GameArea::ResetPanel() {
if (panel) {
panel->Destroy();
panel = nullptr;
panel = NULL;
}
}
@@ -1197,20 +1198,14 @@ void GameArea::OnIdle(wxIdleEvent& event)
if (!panel) {
switch (OPTION(kDispRenderMethod)) {
case config::RenderMethod::kSimple:
no_border = false;
panel = new BasicDrawingPanel(this, basic_width, basic_height);
break;
case config::RenderMethod::kSDL:
no_border = false;
panel = new SDLDrawingPanel(this, basic_width, basic_height);
break;
#ifdef __WXMAC__
#ifndef NO_METAL
case config::RenderMethod::kMetal:
no_border = false;
if (is_macosx_1012_or_newer()) {
panel =
new MetalDrawingPanel(this, basic_width, basic_height);
@@ -1221,27 +1216,17 @@ void GameArea::OnIdle(wxIdleEvent& event)
break;
#endif
case config::RenderMethod::kQuartz2d:
no_border = false;
panel =
new Quartz2DDrawingPanel(this, basic_width, basic_height);
break;
#endif
#ifndef NO_OGL
case config::RenderMethod::kOpenGL:
if (out_8) {
no_border = true;
} else {
no_border = false;
}
panel = new GLDrawingPanel(this, basic_width, basic_height);
break;
#endif
#if defined(__WXMSW__) && !defined(NO_D3D)
case config::RenderMethod::kDirect3d:
no_border = false;
panel = new DXDrawingPanel(this, basic_width, basic_height);
break;
#endif
@@ -1480,7 +1465,7 @@ DrawingPanelBase::DrawingPanelBase(int _width, int _height)
pixbuf1(0),
pixbuf2(0),
nthreads(0),
rpi_(nullptr) {
rpi_(NULL) {
memset(delta, 0xff, sizeof(delta));
if (OPTION(kDispFilter) == config::Filter::kPlugin) {
@@ -1640,12 +1625,12 @@ public:
const int procy = height_ * threadno_ / nthreads_;
height_ = height_ * (threadno_ + 1) / nthreads_ - procy;
const int inbpp = systemColorDepth >> 3;
const int inrb = out_8 ? 2 : out_16 ? 2
const int inrb = out_8 ? 4 : out_16 ? 2
: out_24 ? 0 : 1;
const int instride = (width_ + inrb) * inbpp;
const int instride32 = width_ * 4;
const int outbpp = systemColorDepth >> 3;
const int outrb = out_8 ? 2 : out_24 ? 0 : 4;
const int outrb = out_8 ? 4 : out_24 ? 0 : 4;
const int outstride = std::ceil(width_ * outbpp * scale_) + outrb;
const int outstride32 = std::ceil(width_ * 4 * scale_);
uint8_t *dest = NULL;
@@ -1708,7 +1693,7 @@ public:
pos++;
src_pos++;
}
src_pos += 2;
src_pos += 4;
}
} else if (out_16) {
uint16_t *src16_ = (uint16_t *)src_;
@@ -1761,7 +1746,7 @@ public:
pos++;
dst_pos += 4;
}
pos += 2;
pos += 4;
}
} else if (out_16) {
uint16_t *dest16_ = (uint16_t *)dest;
@@ -2003,7 +1988,7 @@ void DrawingPanelBase::DrawArea(uint8_t** data)
// if filtering, this is filter output, retained for redraws
// if not filtering, we still retain current image for redraws
int outbpp = systemColorDepth >> 3;
int outrb = out_8 ? 2 : out_24 ? 0 : 4;
int outrb = out_8 ? 4 : out_24 ? 0 : 4;
int outstride = std::ceil(width * outbpp * scale) + outrb;
if (!pixbuf2) {
@@ -2589,6 +2574,17 @@ SDL_TEXTUREACCESS_STREAMING, (width * scale), (height * scale));
}
#endif
}
// Set bilinear or nearest on the texture.
#ifdef ENABLE_SDL3
#ifdef HAVE_SDL3_PIXELART
SDL_SetTextureScaleMode(texture, OPTION(kDispSDLPixelArt) ? SDL_SCALEMODE_PIXELART : OPTION(kDispBilinear) ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST);
#else
SDL_SetTextureScaleMode(texture, OPTION(kDispBilinear) ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST);
#endif
#else
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, OPTION(kDispBilinear) ? "1" : "0");
#endif
did_init = true;
}
@@ -2618,7 +2614,7 @@ void SDLDrawingPanel::DrawArea()
DrawingPanelInit();
if (out_8) {
srcPitch = std::ceil(width * scale) + 2;
srcPitch = std::ceil(width * scale) + 4;
} else if (out_16) {
srcPitch = std::ceil(width * scale * 2) + 4;
} else if (out_24) {
@@ -2673,7 +2669,7 @@ void SDLDrawingPanel::DrawArea(uint8_t** data)
// if filtering, this is filter output, retained for redraws
// if not filtering, we still retain current image for redraws
int outbpp = systemColorDepth >> 3;
int outrb = out_8 ? 2 : out_24 ? 0 : 4;
int outrb = out_8 ? 4 : out_24 ? 0 : 4;
int outstride = std::ceil(width * outbpp * scale) + outrb;
// FIXME: filters race condition?
@@ -2847,7 +2843,7 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
} else if (out_8) {
// scaled by filters, top/right borders, transform to 24-bit
im = new wxImage(std::ceil(width * scale), std::ceil(height * scale), false);
uint8_t* src = (uint8_t*)todraw + (int)std::ceil((width + 2) * scale); // skip top border
uint8_t* src = (uint8_t*)todraw + (int)std::ceil((width * scale) + 4); // skip top border
uint8_t* dst = im->GetData();
for (int y = 0; y < std::ceil(height * scale); y++) {
@@ -2864,7 +2860,7 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
}
}
src += 2;
src += 4;
}
} else if (out_16) {
// scaled by filters, top/right borders, transform to 24-bit
@@ -2965,7 +2961,7 @@ bool GLDrawingPanel::SetContext()
// Delete the old context
if (ctx) {
delete ctx;
ctx = nullptr;
ctx = NULL;
}
// Create a new context
@@ -3175,9 +3171,6 @@ void GLDrawingPanel::RefreshGL()
void GLDrawingPanel::DrawArea(wxWindowDC& dc)
{
uint8_t* src = NULL;
uint8_t* dst = NULL;
(void)dc; // unused params
SetContext();
RefreshGL();
@@ -3186,7 +3179,7 @@ void GLDrawingPanel::DrawArea(wxWindowDC& dc)
DrawingPanelInit();
if (todraw) {
int rowlen = std::ceil(width * scale) + (out_8 ? 0 : out_16 ? 2 : out_24 ? 0 : 1);
int rowlen = std::ceil(width * scale) + (out_8 ? 4 : out_16 ? 2 : out_24 ? 0 : 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlen);
#if wxBYTE_ORDER == wxBIG_ENDIAN
@@ -3195,24 +3188,8 @@ void GLDrawingPanel::DrawArea(wxWindowDC& dc)
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
#endif
if (out_8) {
src = (uint8_t*)todraw + (int)std::ceil((width + 2) * ((systemColorDepth >> 3) * scale)); // skip top border
dst = (uint8_t*)todraw;
for (int y = 0; y < std::ceil(height * scale); y++) {
for (int x = 0; x < std::ceil(width * scale); x++) {
*dst++ = *src++;
}
src += 2;
}
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, (int)std::ceil(width * scale), (int)std::ceil(height * scale),
0, tex_fmt, todraw);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, (int)std::ceil(width * scale), (int)std::ceil(height * scale),
0, tex_fmt, todraw + (int)std::ceil(rowlen * ((systemColorDepth >> 3) * scale)));
}
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, (int)std::ceil(width * scale), (int)std::ceil(height * scale),
0, tex_fmt, todraw + (int)std::ceil(rowlen * ((systemColorDepth >> 3) * scale)));
glCallList(vlist);
} else
@@ -3415,7 +3392,7 @@ void GameArea::HideMenuBar()
if (((systemGetClock() - mouse_active_time) > 3000) && !main_frame->MenusOpened()) {
#ifdef __WXMSW__
current_hmenu = static_cast<HMENU>(main_frame->GetMenuBar()->GetHMenu());
::SetMenu(main_frame->GetHandle(), nullptr);
::SetMenu(main_frame->GetHandle(), NULL);
#else
main_frame->GetMenuBar()->Hide();
#endif
@@ -3431,9 +3408,9 @@ void GameArea::ShowMenuBar()
if (!main_frame || !menu_bar_hidden) return;
#ifdef __WXMSW__
if (current_hmenu != nullptr) {
if (current_hmenu != NULL) {
::SetMenu(main_frame->GetHandle(), current_hmenu);
current_hmenu = nullptr;
current_hmenu = NULL;
}
#else
main_frame->GetMenuBar()->Show();
@@ -3455,12 +3432,38 @@ void GameArea::OnGBBorderChanged(config::Option* option) {
}
void GameArea::UpdateLcdFilter() {
if (loaded == IMAGE_GBA)
int DCCP = 0;
switch (OPTION(kDispColorCorrectionProfile)) {
case config::ColorCorrectionProfile::kSRGB:
DCCP = 0;
break;
case config::ColorCorrectionProfile::kDCI:
DCCP = 1;
break;
case config::ColorCorrectionProfile::kRec2020:
DCCP = 2;
break;
case config::ColorCorrectionProfile::kLast:
DCCP = 0;
break;
}
if (loaded == IMAGE_GBA) {
gbafilter_set_params(DCCP, (((float)OPTION(kGBADarken)) / 100));
gbafilter_update_colors(OPTION(kGBALCDFilter));
else if (loaded == IMAGE_GB)
gbafilter_update_colors(OPTION(kGBLCDFilter));
else
} else if (loaded == IMAGE_GB) {
gbcfilter_set_params(DCCP, (((float)OPTION(kGBLighten)) / 100));
gbcfilter_update_colors(OPTION(kGBLCDFilter));
} else {
gbafilter_set_params(DCCP, (((float)OPTION(kGBADarken)) / 100));
gbcfilter_set_params(DCCP, (((float)OPTION(kGBLighten)) / 100));
gbafilter_update_colors(false);
gbcfilter_update_colors(false);
}
}
void GameArea::SuspendScreenSaver() {
@@ -3536,7 +3539,7 @@ void MetalDrawingPanel::DrawArea(uint8_t** data)
// if filtering, this is filter output, retained for redraws
// if not filtering, we still retain current image for redraws
int outbpp = systemColorDepth >> 3;
int outrb = out_8 ? 2 : out_24 ? 0 : 4;
int outrb = out_8 ? 4 : out_24 ? 0 : 4;
int outstride = std::ceil(width * outbpp * scale) + outrb;
// FIXME: filters race condition?

View File

@@ -545,7 +545,7 @@ void MainFrame::IOViewer()
cb->SetValidator(wxBoolIntValidator(&systemVerbose, val, val)); \
} while (0)
LogDialog::LogDialog() :
dialogs::BaseDialog(nullptr, "Logging") {
dialogs::BaseDialog(NULL, "Logging") {
const wxString dname = wxT("Logging");
SetEscapeId(wxID_OK);

View File

@@ -7,7 +7,7 @@ namespace widgets {
namespace {
wxWindow* FindTopLevelWindow(wxWindow* window) {
while (window != nullptr && !window->IsTopLevel()) {
while (window != NULL && !window->IsTopLevel()) {
window = window->GetParent();
}
VBAM_CHECK(window);
@@ -18,7 +18,7 @@ GroupCheckBox* FindGroupCheckBox(wxWindow* window,
const wxString& name,
GroupCheckBox* current) {
if (window == current) {
return nullptr;
return NULL;
}
if (window->IsKindOf(wxCLASSINFO(GroupCheckBox))) {
@@ -35,7 +35,7 @@ GroupCheckBox* FindGroupCheckBox(wxWindow* window,
}
}
return nullptr;
return NULL;
}
} // namespace

View File

@@ -133,6 +133,50 @@ bool OptionIntValidator::WriteToOption() {
return false;
}
OptionUnsignedValidator::OptionUnsignedValidator(config::OptionID option_id) : OptionValidator(option_id) {
VBAM_CHECK(option()->is_unsigned());
}
wxObject* OptionUnsignedValidator::Clone() const {
return new OptionUnsignedValidator(option()->id());
}
bool OptionUnsignedValidator::IsWindowValueValid() {
return true;
}
bool OptionUnsignedValidator::WriteToWindow() {
wxSpinCtrl* spin_ctrl = wxDynamicCast(GetWindow(), wxSpinCtrl);
if (spin_ctrl) {
spin_ctrl->SetValue(option()->GetUnsigned());
return true;
}
wxSlider* slider = wxDynamicCast(GetWindow(), wxSlider);
if (slider) {
slider->SetValue(option()->GetUnsigned());
return true;
}
VBAM_NOTREACHED();
return false;
}
bool OptionUnsignedValidator::WriteToOption() {
const wxSpinCtrl* spin_ctrl = wxDynamicCast(GetWindow(), wxSpinCtrl);
if (spin_ctrl) {
return option()->SetUnsigned(spin_ctrl->GetValue());
}
const wxSlider* slider = wxDynamicCast(GetWindow(), wxSlider);
if (slider) {
return option()->SetUnsigned(slider->GetValue());
}
VBAM_NOTREACHED();
return false;
}
OptionChoiceValidator::OptionChoiceValidator(config::OptionID option_id)
: OptionValidator(option_id) {
VBAM_CHECK(option()->is_unsigned());

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