Restore support for the Nokia N-Gage (#12148)

This commit is contained in:
Michael Fitzmayer 2025-05-22 20:07:22 +02:00 committed by GitHub
parent 26f9940f82
commit 7ae64592c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 4184 additions and 44 deletions

View file

@ -0,0 +1,102 @@
name: 'Setup Nonka N-Gage SDK'
description: 'Download and setup Nokia N-Gage SDK'
inputs:
path:
description: 'Installation path'
default: 'default'
runs:
using: 'composite'
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: 'Verify platform'
id: calc
shell: sh
run: |
case "${{ runner.os }}-${{ runner.arch }}" in
"Windows-X86" | "Windows-X64")
echo "ok!"
echo "cache-key=ngage-sdk-windows" >> ${GITHUB_OUTPUT}
default_install_path="C:/ngagesdk"
;;
*)
echo "Unsupported ${{ runner.os }}-${{ runner.arch }}"
exit 1;
;;
esac
install_path="${{ inputs.path }}"
if [ "x$install_path" = "xdefault" ]; then
install_path="$default_install_path"
fi
echo "install-path=$install_path" >> ${GITHUB_OUTPUT}
toolchain_repo="https://github.com/ngagesdk/ngage-toolchain"
toolchain_branch="main"
echo "toolchain-repo=${toolchain_repo}" >> ${GITHUB_OUTPUT}
echo "toolchain-branch=${toolchain_branch}" >> ${GITHUB_OUTPUT}
sdk_repo="https://github.com/ngagesdk/sdk"
sdk_branch="main"
echo "sdk-repo=${sdk_repo}" >> ${GITHUB_OUTPUT}
echo "sdk-branch=${sdk_branch}" >> ${GITHUB_OUTPUT}
tools_repo="https://github.com/ngagesdk/tools"
tools_branch="main"
echo "tools-repo=${tools_repo}" >> ${GITHUB_OUTPUT}
echo "tools-branch=${tools_branch}" >> ${GITHUB_OUTPUT}
extras_repo="https://github.com/ngagesdk/extras"
extras_branch="main"
echo "extras-repo=${extras_repo}" >> ${GITHUB_OUTPUT}
echo "extras-branch=${extras_branch}" >> ${GITHUB_OUTPUT}
# - name: 'Restore cached ${{ steps.calc.outputs.archive }}'
# id: cache-restore
# uses: actions/cache/restore@v4
# with:
# path: '${{ runner.temp }}'
# key: ${{ steps.calc.outputs.cache-key }}
- name: 'Download N-Gage SDK'
# if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
shell: pwsh
run: |
Invoke-WebRequest "${{ steps.calc.outputs.toolchain-repo }}/archive/refs/heads/${{ steps.calc.outputs.toolchain-branch }}.zip" -OutFile "${{ runner.temp }}/ngage-toolchain.zip"
Invoke-WebRequest "${{ steps.calc.outputs.sdk-repo }}/archive/refs/heads/${{ steps.calc.outputs.sdk-branch }}.zip" -OutFile "${{ runner.temp }}/sdk.zip"
Invoke-WebRequest "${{ steps.calc.outputs.tools-repo }}/archive/refs/heads/${{ steps.calc.outputs.tools-branch }}.zip" -OutFile "${{ runner.temp }}/tools.zip"
Invoke-WebRequest "${{ steps.calc.outputs.extras-repo }}/archive/refs/heads/${{ steps.calc.outputs.extras-branch }}.zip" -OutFile "${{ runner.temp }}/extras.zip"
# - name: 'Cache ${{ steps.calc.outputs.archive }}'
# if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
# uses: actions/cache/save@v4
# with:
# path: |
# ${{ runner.temp }}/apps.zip
# ${{ runner.temp }}/sdk.zip
# ${{ runner.temp }}/tools.zip
# key: ${{ steps.calc.outputs.cache-key }}
- name: 'Extract N-Gage SDK'
shell: pwsh
run: |
New-Item -ItemType Directory -Path "${{ steps.calc.outputs.install-path }}" -Force
New-Item -ItemType Directory -Path "${{ runner.temp }}/ngage-toolchain-temp" -Force
7z "-o${{ runner.temp }}/ngage-toolchain-temp" x "${{ runner.temp }}/ngage-toolchain.zip"
Move-Item -Path "${{ runner.temp }}/ngage-toolchain-temp/ngage-toolchain-${{ steps.calc.outputs.toolchain-branch }}/*" -Destination "${{ steps.calc.outputs.install-path }}"
7z "-o${{ steps.calc.outputs.install-path }}/sdk" x "${{ runner.temp }}/sdk.zip"
Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/sdk-${{ steps.calc.outputs.sdk-branch }}" -Destination "${{ steps.calc.outputs.install-path }}/sdk/sdk"
7z "-o${{ steps.calc.outputs.install-path }}/sdk" x "${{ runner.temp }}/tools.zip"
Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/tools-${{ steps.calc.outputs.tools-branch }}" -Destination "${{ steps.calc.outputs.install-path }}/sdk/tools"
7z "-o${{ steps.calc.outputs.install-path }}/sdk" x "${{ runner.temp }}/extras.zip"
Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/extras-${{ steps.calc.outputs.extras-branch }}" -Destination "${{ steps.calc.outputs.install-path }}/sdk/extras"
- name: 'Set output variables'
id: final
shell: sh
run: |
echo "${{ steps.calc.outputs.install-path }}/sdk/sdk/6.1/Shared/EPOC32/gcc/bin" >> $GITHUB_PATH
echo "${{ steps.calc.outputs.install-path }}/sdk/sdk/6.1/Shared/EPOC32/ngagesdk/bin" >> $GITHUB_PATH
echo "NGAGESDK=${{ steps.calc.outputs.install-path }}" >> $GITHUB_ENV
echo "CMAKE_TOOLCHAIN_FILE=${{ steps.calc.outputs.install-path }}/cmake/ngage-toolchain.cmake" >> $GITHUB_ENV

View file

@ -54,6 +54,7 @@ class SdlPlatform(Enum):
Riscos = "riscos"
FreeBSD = "freebsd"
NetBSD = "netbsd"
NGage = "ngage"
class Msys2Platform(Enum):
@ -139,11 +140,12 @@ JOB_SPECS = {
"riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ),
"netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ),
"freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ),
"ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ),
}
class StaticLibType(Enum):
MSVC = "SDL3-static.lib"
STATIC_LIB = "SDL3-static.lib"
A = "libSDL3.a"
@ -223,6 +225,7 @@ class JobDetails:
check_sources: bool = False
setup_python: bool = False
pypi_packages: list[str] = dataclasses.field(default_factory=list)
setup_gage_sdk_path: str = ""
def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
data = {
@ -290,6 +293,7 @@ class JobDetails:
"check-sources": self.check_sources,
"setup-python": self.setup_python,
"pypi-packages": my_shlex_join(self.pypi_packages),
"setup-ngage-sdk-path": self.setup_gage_sdk_path,
}
return {k: v for k, v in data.items() if v != ""}
@ -365,7 +369,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
job.msvc_project_flags.append("-p:TreatWarningsAsError=true")
job.test_pkg_config = False
job.shared_lib = SharedLibType.WIN32
job.static_lib = StaticLibType.MSVC
job.static_lib = StaticLibType.STATIC_LIB
job.cmake_arguments.extend((
"-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
"-DCMAKE_EXE_LINKER_FLAGS=-DEBUG",
@ -740,6 +744,19 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
job.cpactions_arch = "x86-64"
job.cpactions_setup_cmd = "export PATH=\"/usr/pkg/sbin:/usr/pkg/bin:/sbin:$PATH\"; export PKG_CONFIG_PATH=\"/usr/pkg/lib/pkgconfig\";export PKG_PATH=\"https://cdn.netBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f \"1 2\" -d.)/All/\";echo \"PKG_PATH=$PKG_PATH\";echo \"uname -a -> \"$(uname -a)\"\";sudo -E sysctl -w security.pax.aslr.enabled=0;sudo -E sysctl -w security.pax.aslr.global=0;sudo -E pkgin clean;sudo -E pkgin update"
job.cpactions_install_cmd = "sudo -E pkgin -y install cmake dbus pkgconf ninja-build pulseaudio libxkbcommon wayland wayland-protocols libinotify libusb1"
case SdlPlatform.NGage:
build_parallel = False
job.cmake_build_type = "Release"
job.setup_ninja = True
job.static_lib = StaticLibType.STATIC_LIB
job.shared_lib = None
job.clang_tidy = False
job.werror = False # FIXME: enable SDL_WERROR
job.shared = False
job.run_tests = False
job.setup_gage_sdk_path = "C:/ngagesdk"
job.cmake_toolchain_file = "C:/ngagesdk/cmake/ngage-toolchain.cmake"
job.test_pkg_config = False
case _:
raise ValueError(f"Unsupported platform={spec.platform}")

View file

@ -93,6 +93,11 @@ jobs:
with:
arch: ${{ matrix.platform.msvc-vcvars-arch }}
sdk: ${{ matrix.platform.msvc-vcvars-sdk }}
- name: 'Set up Nokia N-Gage SDK'
uses: ./.github/actions/setup-ngage-sdk
if: ${{ matrix.platform.setup-ngage-sdk-path != '' }}
with:
path: '${{ matrix.platform.setup-ngage-sdk-path }}'
- name: 'Set up Windows GDK Desktop'
uses: ./.github/actions/setup-gdk-desktop
if: ${{ matrix.platform.setup-gdk-folder != '' }}

View file

@ -76,6 +76,7 @@ include("${SDL3_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake")
include("${SDL3_SOURCE_DIR}/cmake/3rdparty.cmake")
include("${SDL3_SOURCE_DIR}/cmake/PreseedMSVCCache.cmake")
include("${SDL3_SOURCE_DIR}/cmake/PreseedEmscriptenCache.cmake")
include("${SDL3_SOURCE_DIR}/cmake/PreseedNokiaNGageCache.cmake")
SDL_DetectCompiler()
SDL_DetectTargetCPUArchitectures(SDL_CPUS)
@ -155,7 +156,7 @@ endif()
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
# so we'll just use libusb when it's available. libusb does not support iOS,
# so we default to yes on iOS.
if(IOS OR TVOS OR VISIONOS OR WATCHOS OR ANDROID)
if(IOS OR TVOS OR VISIONOS OR WATCHOS OR ANDROID OR NGAGE)
set(SDL_HIDAPI_LIBUSB_AVAILABLE FALSE)
else()
set(SDL_HIDAPI_LIBUSB_AVAILABLE TRUE)
@ -219,7 +220,7 @@ if(EMSCRIPTEN)
set(SDL_SHARED_AVAILABLE OFF)
endif()
if(VITA OR PSP OR PS2 OR N3DS OR RISCOS)
if(VITA OR PSP OR PS2 OR N3DS OR RISCOS OR NGAGE)
set(SDL_SHARED_AVAILABLE OFF)
endif()
@ -414,6 +415,24 @@ if(VITA)
set_option(VIDEO_VITA_PVR "Build with PSVita PVR gles/gles2 support" OFF)
endif()
if (NGAGE)
set(SDL_GPU OFF)
set(SDL_CAMERA OFF)
set(SDL_JOYSTICK OFF)
set(SDL_HAPTIC OFF)
set(SDL_HIDAPI OFF)
set(SDL_POWER OFF)
set(SDL_SENSOR OFF)
set(SDL_DIALOG OFF)
set(SDL_DISKAUDIO OFF)
set(SDL_DUMMYAUDIO OFF)
set(SDL_DUMMYCAMERA OFF)
set(SDL_DUMMYVIDEO OFF)
set(SDL_OFFSCREEN OFF)
set(SDL_RENDER_GPU OFF)
set(SDL_VIRTUAL_JOYSTICK OFF)
endif()
if(NOT (SDL_SHARED OR SDL_STATIC))
message(FATAL_ERROR "SDL_SHARED and SDL_STATIC cannot both be disabled")
endif()
@ -2931,6 +2950,81 @@ elseif(N3DS)
set(HAVE_SDL_LOCALE TRUE)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/n3ds/*.c")
elseif(NGAGE)
enable_language(CXX)
set(SDL_MAIN_USE_CALLBACKS 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.c")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.cpp")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ngage/*.cpp")
set(HAVE_SDL_MAIN_CALLBACKS TRUE)
if(SDL_AUDIO)
set(SDL_AUDIO_DRIVER_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.c")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.cpp")
set(HAVE_SDL_AUDIO TRUE)
endif()
set(SDL_FILESYSTEM_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/ngage/*.c")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/ngage/*.cpp")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/posix/*.c")
set(HAVE_SDL_FILESYSTEM TRUE)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/ngage/*.cpp")
if(SDL_RENDER)
set(SDL_VIDEO_RENDER_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.c")
endif()
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/ngage/*.cpp")
set(SDL_TIME_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.cpp")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c")
set(SDL_TIMER_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/ngage/*.cpp")
set(SDL_FSOPS_POSIX 1)
set(SDL_VIDEO_DRIVER_NGAGE 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/ngage/*.c")
set(HAVE_SDL_TIMERS TRUE)
set_option(SDL_LEAN_AND_MEAN "Enable lean and mean" ON)
if(SDL_LEAN_AND_MEAN)
sdl_compile_definitions(
PRIVATE
SDL_LEAN_AND_MEAN
)
endif()
sdl_link_dependency(ngage
LINK_OPTIONS "SHELL:-s MAIN_COMPAT=0"
PKG_CONFIG_LINK_OPTIONS "-s;MAIN_COMPAT=0"
LIBS
NRenderer
3dtypes
cone
libgcc
libgcc_ngage
mediaclientaudiostream
charconv
bitgdi
euser
estlib
ws32
hal
fbscli
efsrv
scdv
gdi
)
endif()
sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c)
@ -3111,8 +3205,8 @@ endif()
# We always need to have threads and timers around
if(NOT HAVE_SDL_THREADS)
# The emscripten platform has been carefully vetted to work without threads
if(EMSCRIPTEN)
# The Emscripten and N-Gage platform has been carefully vetted to work without threads
if(EMSCRIPTEN OR NGAGE)
set(SDL_THREADS_DISABLED 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/generic/*.c")
else()

View file

@ -0,0 +1,189 @@
if(NGAGESDK)
function(SDL_Preseed_CMakeCache)
set(COMPILER_SUPPORTS_ARMNEON "" CACHE INTERNAL "Test COMPILER_SUPPORTS_ARMNEON")
set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS "" CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS")
set(COMPILER_SUPPORTS_SYNC_LOCK_TEST_AND_SET "" CACHE INTERNAL "Test COMPILER_SUPPORTS_SYNC_LOCK_TEST_AND_SET")
set(HAVE_CLANG_COMMENT_BLOCK_COMMANDS "" CACHE INTERNAL "Test HAVE_CLANG_COMMENT_BLOCK_COMMANDS")
set(HAVE_ALLOCA_H "" CACHE INTERNAL "Have include alloca.h")
set(HAVE_LIBM "1" CACHE INTERNAL "Have library m")
set(HAVE_POSIX_SPAWN "" CACHE INTERNAL "Have symbol posix_spawn")
set(HAVE_MALLOC "1" CACHE INTERNAL "Have include malloc.h")
set(LIBC_HAS_ABS "1" CACHE INTERNAL "Have symbol abs")
set(LIBC_HAS_ACOS "1" CACHE INTERNAL "Have symbol acos")
set(LIBC_HAS_ACOSF "" CACHE INTERNAL "Have symbol acosf")
set(LIBC_HAS_ASIN "1" CACHE INTERNAL "Have symbol asin")
set(LIBC_HAS_ASINF "" CACHE INTERNAL "Have symbol asinf")
set(LIBC_HAS_ATAN "1" CACHE INTERNAL "Have symbol atan")
set(LIBC_HAS_ATAN2 "1" CACHE INTERNAL "Have symbol atan2")
set(LIBC_HAS_ATAN2F "" CACHE INTERNAL "Have symbol atan2f")
set(LIBC_HAS_ATANF "" CACHE INTERNAL "Have symbol atanf")
set(LIBC_HAS_ATOF "" CACHE INTERNAL "Have symbol atof")
set(LIBC_HAS_ATOI "" CACHE INTERNAL "Have symbol atoi")
set(LIBC_HAS_BCOPY "1" CACHE INTERNAL "Have symbol bcopy")
set(LIBC_HAS_CALLOC "" CACHE INTERNAL "Have symbol calloc")
set(LIBC_HAS_CEIL "1" CACHE INTERNAL "Have symbol ceil")
set(LIBC_HAS_CEILF "" CACHE INTERNAL "Have symbol ceilf")
set(LIBC_HAS_COPYSIGN "1" CACHE INTERNAL "Have symbol copysign")
set(LIBC_HAS_COPYSIGNF "1" CACHE INTERNAL "Have symbol copysignf")
set(LIBC_HAS_COS "1" CACHE INTERNAL "Have symbol cos")
set(LIBC_HAS_COSF "" CACHE INTERNAL "Have symbol cosf")
set(LIBC_HAS_EXP "1" CACHE INTERNAL "Have symbol exp")
set(LIBC_HAS_EXPF "" CACHE INTERNAL "Have symbol expf")
set(LIBC_HAS_FABS "1" CACHE INTERNAL "Have symbol fabs")
set(LIBC_HAS_FABSF "1" CACHE INTERNAL "Have symbol fabsf")
set(LIBC_HAS_FLOAT_H "1" CACHE INTERNAL "Have include float.h")
set(LIBC_HAS_FLOOR "1" CACHE INTERNAL "Have symbol floor")
set(LIBC_HAS_FLOORF "" CACHE INTERNAL "Have symbol floorf")
set(LIBC_HAS_FMOD "" CACHE INTERNAL "Have symbol fmod")
set(LIBC_HAS_FMODF "" CACHE INTERNAL "Have symbol fmodf")
set(LIBC_HAS_FOPEN64 "" CACHE INTERNAL "Have symbol fopen64")
set(LIBC_HAS_FREE "1" CACHE INTERNAL "Have symbol free")
set(LIBC_HAS_FSEEKO "" CACHE INTERNAL "Have symbol fseeko")
set(LIBC_HAS_FSEEKO64 "" CACHE INTERNAL "Have symbol fseeko64")
set(LIBC_HAS_GETENV "" CACHE INTERNAL "Have symbol getenv")
set(LIBC_HAS_ICONV_H "" CACHE INTERNAL "Have include iconv.h")
set(LIBC_HAS_INDEX "1" CACHE INTERNAL "Have symbol index")
set(LIBC_HAS_INTTYPES_H "1" CACHE INTERNAL "Have include inttypes.h")
set(LIBC_HAS_ISINF "1" CACHE INTERNAL "Have include isinf(double)")
set(LIBC_ISINF_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isinf(float)")
set(LIBC_HAS_ISINFF "1" CACHE INTERNAL "Have include isinff(float)")
set(LIBC_HAS_ISNAN "1" CACHE INTERNAL "Have include isnan(double)")
set(LIBC_ISNAN_HANDLES_FLOAT "1" CACHE INTERNAL "Have include isnan(float)")
set(LIBC_HAS_ISNANF "1" CACHE INTERNAL "Have include isnanf(float)")
set(LIBC_HAS_ITOA "" CACHE INTERNAL "Have symbol itoa")
set(LIBC_HAS_LIMITS_H "1" CACHE INTERNAL "Have include limits.h")
set(LIBC_HAS_LOG "1" CACHE INTERNAL "Have symbol log")
set(LIBC_HAS_LOG10 "" CACHE INTERNAL "Have symbol log10")
set(LIBC_HAS_LOG10F "" CACHE INTERNAL "Have symbol log10f")
set(LIBC_HAS_LOGF "" CACHE INTERNAL "Have symbol logf")
set(LIBC_HAS_LROUND "" CACHE INTERNAL "Have symbol lround")
set(LIBC_HAS_LROUNDF "" CACHE INTERNAL "Have symbol lroundf")
set(LIBC_HAS_MALLOC "1" CACHE INTERNAL "Have symbol malloc")
set(LIBC_HAS_MALLOC_H "" CACHE INTERNAL "Have include malloc.h")
set(LIBC_HAS_MATH_H "1" CACHE INTERNAL "Have include math.h")
set(LIBC_HAS_MEMCMP "1" CACHE INTERNAL "Have symbol memcmp")
set(LIBC_HAS_MEMCPY "" CACHE INTERNAL "Have symbol memcpy")
set(LIBC_HAS_MEMMOVE "" CACHE INTERNAL "Have symbol memmove")
set(LIBC_HAS_MEMORY_H "" CACHE INTERNAL "Have include memory.h")
set(LIBC_HAS_MEMSET "" CACHE INTERNAL "Have symbol memset")
set(LIBC_HAS_MODF "1" CACHE INTERNAL "Have symbol modf")
set(LIBC_HAS_MODFF "" CACHE INTERNAL "Have symbol modff")
set(LIBC_HAS_POW "1" CACHE INTERNAL "Have symbol pow")
set(LIBC_HAS_POWF "" CACHE INTERNAL "Have symbol powf")
set(LIBC_HAS_PUTENV "" CACHE INTERNAL "Have symbol putenv")
set(LIBC_HAS_REALLOC "" CACHE INTERNAL "Have symbol realloc")
set(LIBC_HAS_RINDEX "1" CACHE INTERNAL "Have symbol rindex")
set(LIBC_HAS_ROUND "" CACHE INTERNAL "Have symbol round")
set(LIBC_HAS_ROUNDF "" CACHE INTERNAL "Have symbol roundf")
set(LIBC_HAS_SCALBN "1" CACHE INTERNAL "Have symbol scalbn")
set(LIBC_HAS_SCALBNF "" CACHE INTERNAL "Have symbol scalbnf")
set(LIBC_HAS_SETENV "" CACHE INTERNAL "Have symbol setenv")
set(LIBC_HAS_SIGNAL_H "" CACHE INTERNAL "Have include signal.h")
set(LIBC_HAS_SIN "1" CACHE INTERNAL "Have symbol sin")
set(LIBC_HAS_SINF "" CACHE INTERNAL "Have symbol sinf")
set(LIBC_HAS_SQR "" CACHE INTERNAL "Have symbol sqr")
set(LIBC_HAS_SQRT "1" CACHE INTERNAL "Have symbol sqrt")
set(LIBC_HAS_SQRTF "" CACHE INTERNAL "Have symbol sqrtf")
set(LIBC_HAS_SSCANF "1" CACHE INTERNAL "Have symbol sscanf")
set(LIBC_HAS_STDARG_H "1" CACHE INTERNAL "Have include stdarg.h")
set(LIBC_HAS_STDBOOL_H "1" CACHE INTERNAL "Have include stdbool.h")
set(LIBC_HAS_STDDEF_H "1" CACHE INTERNAL "Have include stddef.h")
set(LIBC_HAS_STDINT_H "1" CACHE INTERNAL "Have include stdint.h")
set(LIBC_HAS_STDIO_H "1" CACHE INTERNAL "Have include stdio.h")
set(LIBC_HAS_STDLIB_H "1" CACHE INTERNAL "Have include stdlib.h")
set(LIBC_HAS_STRCASESTR "" CACHE INTERNAL "Have symbol strcasestr")
set(LIBC_HAS_STRCHR "1" CACHE INTERNAL "Have symbol strchr")
set(LIBC_HAS_STRCMP "1" CACHE INTERNAL "Have symbol strcmp")
set(LIBC_HAS_STRINGS_H "" CACHE INTERNAL "Have include strings.h")
set(LIBC_HAS_STRING_H "1" CACHE INTERNAL "Have include string.h")
set(LIBC_HAS_STRLCAT "" CACHE INTERNAL "Have symbol strlcat")
set(LIBC_HAS_STRLCPY "" CACHE INTERNAL "Have symbol strlcpy")
set(LIBC_HAS_STRLEN "1" CACHE INTERNAL "Have symbol strlen")
set(LIBC_HAS_STRNCMP "1" CACHE INTERNAL "Have symbol strncmp")
set(LIBC_HAS_STRNLEN "" CACHE INTERNAL "Have symbol strnlen")
set(LIBC_HAS_STRNSTR "" CACHE INTERNAL "Have symbol strnstr")
set(LIBC_HAS_STRPBRK "1" CACHE INTERNAL "Have symbol strpbrk")
set(LIBC_HAS_STRRCHR "1" CACHE INTERNAL "Have symbol strrchr")
set(LIBC_HAS_STRSTR "1" CACHE INTERNAL "Have symbol strstr")
set(LIBC_HAS_STRTOD "" CACHE INTERNAL "Have symbol strtod")
set(LIBC_HAS_STRTOK_R "" CACHE INTERNAL "Have symbol strtok_r")
set(LIBC_HAS_STRTOL "" CACHE INTERNAL "Have symbol strtol")
set(LIBC_HAS_STRTOLL "" CACHE INTERNAL "Have symbol strtoll")
set(LIBC_HAS_STRTOUL "" CACHE INTERNAL "Have symbol strtoul")
set(LIBC_HAS_STRTOULL "" CACHE INTERNAL "Have symbol strtoull")
set(LIBC_HAS_SYS_TYPES_H "1" CACHE INTERNAL "Have include sys/types.h")
set(LIBC_HAS_TAN "1" CACHE INTERNAL "Have symbol tan")
set(LIBC_HAS_TANF "" CACHE INTERNAL "Have symbol tanf")
set(LIBC_HAS_TIME_H "1" CACHE INTERNAL "Have include time.h")
set(LIBC_HAS_TRUNC "" CACHE INTERNAL "Have symbol trunc")
set(LIBC_HAS_TRUNCF "" CACHE INTERNAL "Have symbol truncf")
set(LIBC_HAS_UNSETENV "" CACHE INTERNAL "Have symbol unsetenv")
set(LIBC_HAS_VSNPRINTF "" CACHE INTERNAL "Have symbol vsnprintf")
set(LIBC_HAS_VSSCANF "" CACHE INTERNAL "Have symbol vsscanf")
set(LIBC_HAS_WCHAR_H "1" CACHE INTERNAL "Have include wchar.h")
set(LIBC_HAS_WCSCMP "" CACHE INTERNAL "Have symbol wcscmp")
set(LIBC_HAS_WCSDUP "" CACHE INTERNAL "Have symbol wcsdup")
set(LIBC_HAS_WCSLCAT "" CACHE INTERNAL "Have symbol wcslcat")
set(LIBC_HAS_WCSLCPY "" CACHE INTERNAL "Have symbol wcslcpy")
set(LIBC_HAS_WCSLEN "" CACHE INTERNAL "Have symbol wcslen")
set(LIBC_HAS_WCSNCMP "" CACHE INTERNAL "Have symbol wcsncmp")
set(LIBC_HAS_WCSNLEN "" CACHE INTERNAL "Have symbol wcsnlen")
set(LIBC_HAS_WCSSTR "" CACHE INTERNAL "Have symbol wcsstr")
set(LIBC_HAS_WCSTOL "" CACHE INTERNAL "Have symbol wcstol")
set(LIBC_HAS__EXIT "" CACHE INTERNAL "Have symbol _Exit")
set(LIBC_HAS__I64TOA "" CACHE INTERNAL "Have symbol _i64toa")
set(LIBC_HAS__LTOA "" CACHE INTERNAL "Have symbol _ltoa")
set(LIBC_HAS__STRREV "" CACHE INTERNAL "Have symbol _strrev")
set(LIBC_HAS__UI64TOA "" CACHE INTERNAL "Have symbol _ui64toa")
set(LIBC_HAS__UITOA "" CACHE INTERNAL "Have symbol _uitoa")
set(LIBC_HAS__ULTOA "" CACHE INTERNAL "Have symbol _ultoa")
set(LIBC_HAS__WCSDUP "" CACHE INTERNAL "Have symbol _wcsdup")
set(LIBC_IS_GLIBC "" CACHE INTERNAL "Have symbol __GLIBC__")
set(_ALLOCA_IN_MALLOC_H "" CACHE INTERNAL "Have symbol _alloca")
set(HAVE_GCC_WALL "1" CACHE INTERNAL "Test HAVE_GCC_WALL")
set(HAVE_GCC_WUNDEF "1" CACHE INTERNAL "Test HAVE_GCC_WUNDEF")
set(HAVE_GCC_WFLOAT_CONVERSION "" CACHE INTERNAL "Test HAVE_GCC_WFLOAT_CONVERSION")
set(HAVE_GCC_NO_STRICT_ALIASING "1" CACHE INTERNAL "Test HAVE_GCC_NO_STRICT_ALIASING")
set(HAVE_GCC_WDOCUMENTATION "" CACHE INTERNAL "Test HAVE_GCC_WDOCUMENTATION")
set(HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND "" CACHE INTERNAL "Test HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND")
set(HAVE_GCC_COMMENT_BLOCK_COMMANDS "" CACHE INTERNAL "Test HAVE_GCC_COMMENT_BLOCK_COMMANDS")
set(HAVE_GCC_WSHADOW "1" CACHE INTERNAL "Test HAVE_GCC_WSHADOW")
set(HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS "" CACHE INTERNAL "Test HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS")
set(HAVE_GCC_WIMPLICIT_FALLTHROUGH "" CACHE INTERNAL "Test HAVE_GCC_WIMPLICIT_FALLTHROUGH")
set(HAVE_GCC_FVISIBILITY "" CACHE INTERNAL "Test HAVE_GCC_FVISIBILITY")
set(HAVE_ST_MTIM "" CACHE INTERNAL "Test HAVE_ST_MTIM")
#set(HAVE_O_CLOEXEC "" CACHE INTERNAL "Test HAVE_O_CLOEXEC")
#set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR "" CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR")
set(COMPILER_SUPPORTS_GCC_ATOMICS "" CACHE INTERNAL "Test COMPILER_SUPPORTS_GCC_ATOMICS")
set(LINKER_SUPPORTS_VERSION_SCRIPT "" CACHE INTERNAL "Test LINKER_SUPPORTS_VERSION_SCRIPT")
set(LINKER_SUPPORTS_WL_NO_UNDEFINED "" CACHE INTERNAL "Test LINKER_SUPPORTS_WL_NO_UNDEFINED")
set(ICONV_IN_LIBC "" CACHE INTERNAL "Test ICONV_IN_LIBC")
set(ICONV_IN_LIBICONV "" CACHE INTERNAL "Test ICONV_IN_LIBICONV")
#set(LIBC_HAS_WORKING_LIBUNWIND "" CACHE INTERNAL "Test LIBC_HAS_WORKING_LIBUNWIND")
#set(LIBUNWIND_HAS_WORKINGLIBUNWIND "" CACHE INTERNAL "Test LIBUNWIND_HAS_WORKINGLIBUNWIND")
set(HAVE_GETPAGESIZE "" CACHE INTERNAL "Have symbol getpagesize")
set(HAVE_SIGACTION "" CACHE INTERNAL "Have symbol sigaction")
set(HAVE_SA_SIGACTION "" CACHE INTERNAL "Have symbol sa_sigaction")
set(HAVE_SETJMP "" CACHE INTERNAL "Have symbol setjmp")
set(HAVE_NANOSLEEP "" CACHE INTERNAL "Have symbol nanosleep")
set(HAVE_GMTIME_R "" CACHE INTERNAL "Have symbol gmtime_r")
set(HAVE_LOCALTIME_R "" CACHE INTERNAL "Have symbol localtime_r")
set(HAVE_NL_LANGINFO "" CACHE INTERNAL "Have symbol nl_langinfo")
set(HAVE_SYSCONF "" CACHE INTERNAL "Have symbol sysconf")
set(HAVE_SYSCTLBYNAME "" CACHE INTERNAL "Have symbol sysctlbyname")
set(HAVE_GETAUXVAL "" CACHE INTERNAL "Have symbol getauxval")
set(HAVE_ELF_AUX_INFO "" CACHE INTERNAL "Have symbol elf_aux_info")
set(HAVE_POLL "" CACHE INTERNAL "Have symbol poll")
set(HAVE_MEMFD_CREATE "" CACHE INTERNAL "Have symbol memfd_create")
set(HAVE_POSIX_FALLOCATE "" CACHE INTERNAL "Have symbol posix_fallocate")
set(HAVE_DLOPEN_IN_LIBC "" CACHE INTERNAL "Have symbol dlopen")
set(HAVE_GETHOSTNAME "" CACHE INTERNAL "Have symbol gethostname")
set(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR "" CACHE INTERNAL "Have symbol addchdir")
set(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP "" CACHE INTERNAL "Have symbol addchdir_np")
set(HAVE_FDATASYNC "" CACHE INTERNAL "Have symbol fdatasync")
set(HAVE_SDL_FSOPS "1" CACHE INTERNAL "Enable SDL_FSOPS")
set(HAVE_SDL_LOCALE "1" CACHE INTERNAL "Enable SDL_LOCALE")
endfunction()
endif()

View file

@ -22,6 +22,8 @@ function(SDL_DetectCMakePlatform)
set(sdl_cmake_platform Haiku)
elseif(NINTENDO_3DS)
set(sdl_cmake_platform n3ds)
elseif(NGAGESDK)
set(sdl_cmake_platform ngage)
elseif(PS2)
set(sdl_cmake_platform ps2)
elseif(VITA)

View file

@ -96,12 +96,14 @@ if(TEST_STATIC)
add_executable(gui-static WIN32 main_gui.c)
target_link_libraries(gui-static PRIVATE SDL3::SDL3-static)
# Assume SDL library has been built with `set(CMAKE_POSITION_INDEPENDENT_CODE ON)`
add_library(sharedlib-static SHARED main_lib.c)
target_link_libraries(sharedlib-static PRIVATE SDL3::SDL3-static)
generate_export_header(sharedlib-static EXPORT_MACRO_NAME MYLIBRARY_EXPORT)
target_compile_definitions(sharedlib-static PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-static_export.h\"")
set_target_properties(sharedlib-static PROPERTIES C_VISIBILITY_PRESET "hidden")
if(TEST_SHARED)
# Assume SDL library has been built with `set(CMAKE_POSITION_INDEPENDENT_CODE ON)`
add_library(sharedlib-static SHARED main_lib.c)
target_link_libraries(sharedlib-static PRIVATE SDL3::SDL3-static)
generate_export_header(sharedlib-static EXPORT_MACRO_NAME MYLIBRARY_EXPORT)
target_compile_definitions(sharedlib-static PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-static_export.h\"")
set_target_properties(sharedlib-static PROPERTIES C_VISIBILITY_PRESET "hidden")
endif()
if(TEST_TEST)
add_executable(sdltest-static sdltest.c)

View file

@ -1,24 +1,37 @@
#include <SDL3/SDL.h>
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>
int main(int argc, char *argv[])
static SDL_Window *window;
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
SDL_Window *window = NULL;
SDL_Surface *screenSurface = NULL;
screenSurface = SDL_GetWindowSurface(window);
SDL_FillSurfaceRect(screenSurface, NULL, SDL_MapSurfaceRGB(screenSurface, 0xff, 0xff, 0xff));
SDL_UpdateWindowSurface(window);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_Log("Could not initialize SDL: %s", SDL_GetError());
return 1;
return SDL_APP_FAILURE;
}
window = SDL_CreateWindow("Hello SDL", 640, 480, 0);
if (!window) {
SDL_Log("could not create window: %s", SDL_GetError());
return 1;
return SDL_APP_FAILURE;
}
screenSurface = SDL_GetWindowSurface(window);
SDL_FillSurfaceRect(screenSurface, NULL, SDL_MapSurfaceRGB(screenSurface, 0xff, 0xff, 0xff));
SDL_UpdateWindowSurface(window);
SDL_Delay(100);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result) {
SDL_DestroyWindow(window);
}

View file

@ -1,9 +1,24 @@
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_test.h>
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
return SDL_APP_SUCCESS;
}
int main(int argc, char *argv[]) {
SDL_AppResult SDL_AppIterate(void *appstate)
{
return SDL_APP_SUCCESS;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDLTest_CommonState state;
SDLTest_CommonDefaultArgs(&state, argc, argv);
return 0;
return SDL_APP_SUCCESS;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result) {
}

View file

@ -1,5 +1,64 @@
Support for the Nokia N-Gage has been removed from SDL3 (but will make a
comeback when newer compilers are available for the platform).
# Nokia N-Gage
SDL2 still supports this platform.
SDL port for the Nokia N-Gage
[Homebrew toolchain](https://github.com/ngagesdk/ngage-toolchain)
contributed by:
- [Michael Fitzmayer](https://github.com/mupfdev)
- [Anonymous Maarten](https://github.com/madebr)
Many thanks to:
- icculus and slouken for always making room for us — even when we show up in 2025
still waving the N-Gage flag.
- The Nokia N-Gage [Discord community](https://discord.gg/dbUzqJ26vs)
who keeps the platform alive.
- The staff and supporters of the
[Suomen pelimuseo](https://www.vapriikki.fi/nayttelyt/fantastinen-floppi/), and
to Heikki Jungmann, for their ongoing love and dedication for the Nokia N-Gage — you
guys are awesome!
## History
When SDL support was discontinued due to the lack of C99 support at the time,
this version was rebuilt from the ground up after resolving the compiler issues.
In contrast to the earlier SDL2 port, this version features a dedicated rendering
backend and a functional, albeit limited, audio interface. Support for the
software renderer has been removed.
The outcome is a significantly leaner and more efficient SDL port, which we hope
will breathe new life into this beloved yet obscure platform.
## To the Stubborn Legends of the DC Scene
This port is lovingly dedicated to the ever-nostalgic Dreamcast homebrew scene —
because if we managed to pull this off for the N-Gage (yes, the N-Gage), surely
you guys can stop clinging to SDL2 like it's a rare Shenmue prototype and finally
make the leap to SDL3. Its 2025, not 1999 — and lets be honest, youre rocking
a state-of-the-art C23 compiler. The irony writes itself.
## Existing Issues and Limitations
- For now, the new
[SDL3 main callbacks](https://wiki.libsdl.org/SDL3/README/main-functions#how-to-use-main-callbacks-in-sdl3)
are not optional and must be used. This is important as the callbacks
are optional on other platforms.
- If the application is put in the background while sound is playing,
some of the audio is looped until the app is back in focus.
- It is recommended initialising SDLs audio sub-system even when it
is not required. The backend is started at a higher level. Initialising
SDLs audio sub-system ensures that the backend is properly deinitialised.
- Because the audio sample rate can change during phone calls, the sample
rate is currently fixed at 8kHz to ensure stable behavior. Although
dynamically adjusting the sample rate is theoretically possible, the
current implementation doesn't support it yet. This limitation is
expected to be resolved in a future update.
- Dependency tracking is currently non-functional.

View file

@ -111,6 +111,10 @@ macro(add_sdl_example_executable TARGET)
elseif(EMSCRIPTEN)
set_property(TARGET ${TARGET} PROPERTY SUFFIX ".html")
target_link_options(${TARGET} PRIVATE -sALLOW_MEMORY_GROWTH=1)
elseif(NGAGE)
string(MD5 TARGET_MD5 "${TARGET}")
string(SUBSTRING "${TARGET_MD5}" 0 8 TARGET_MD5_8)
target_link_options(${TARGET} PRIVATE "SHELL:-s UID3=0x${TARGET_MD5_8}")
endif()
if(OPENGL_FOUND)

View file

@ -132,7 +132,7 @@ extern "C" {
#define SDL_TriggerBreakpoint() __debugbreak()
#elif defined(_MSC_VER) && defined(_M_IX86)
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
#elif defined(ANDROID)
#elif defined(ANDROID) || defined(__SYMBIAN32__)
#include <assert.h>
#define SDL_TriggerBreakpoint() assert(0)
#elif SDL_HAS_BUILTIN(__builtin_debugtrap)

View file

@ -389,7 +389,7 @@
#endif /* SDL_FORCE_INLINE not defined */
#ifndef SDL_NORETURN
#ifdef __GNUC__
#if defined(__GNUC__)
#define SDL_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define SDL_NORETURN __declspec(noreturn)

View file

@ -317,7 +317,7 @@
#define SDL_PLATFORM_CYGWIN 1
#endif
#if defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(__NGAGE__)
/**
* A preprocessor macro that is only defined if compiling for Windows.
@ -473,4 +473,14 @@
#define SDL_PLATFORM_3DS 1
#endif
#ifdef __NGAGE__
/**
* A preprocessor macro that is only defined if compiling for the Nokia N-Gage.
*
* \since This macro is available since SDL 3.4.0.
*/
#define SDL_PLATFORM_NGAGE 1
#endif
#endif /* SDL_platform_defines_h_ */

View file

@ -277,6 +277,7 @@
#cmakedefine SDL_AUDIO_DRIVER_PSP 1
#cmakedefine SDL_AUDIO_DRIVER_PS2 1
#cmakedefine SDL_AUDIO_DRIVER_N3DS 1
#cmakedefine SDL_AUDIO_DRIVER_NGAGE 1
#cmakedefine SDL_AUDIO_DRIVER_QNX 1
#cmakedefine SDL_AUDIO_DRIVER_PRIVATE 1
@ -365,6 +366,7 @@
#cmakedefine SDL_TIME_PSP 1
#cmakedefine SDL_TIME_PS2 1
#cmakedefine SDL_TIME_N3DS 1
#cmakedefine SDL_TIME_NGAGE 1
/* Enable various timer systems */
#cmakedefine SDL_TIMER_HAIKU 1
@ -387,6 +389,7 @@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC@
#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM@
#cmakedefine SDL_VIDEO_DRIVER_N3DS 1
#cmakedefine SDL_VIDEO_DRIVER_NGAGE 1
#cmakedefine SDL_VIDEO_DRIVER_OFFSCREEN 1
#cmakedefine SDL_VIDEO_DRIVER_PS2 1
#cmakedefine SDL_VIDEO_DRIVER_PSP 1
@ -438,6 +441,7 @@
#cmakedefine SDL_VIDEO_RENDER_VULKAN 1
#cmakedefine SDL_VIDEO_RENDER_OGL 1
#cmakedefine SDL_VIDEO_RENDER_OGL_ES2 1
#cmakedefine SDL_VIDEO_RENDER_NGAGE 1
#cmakedefine SDL_VIDEO_RENDER_PS2 1
#cmakedefine SDL_VIDEO_RENDER_PSP 1
#cmakedefine SDL_VIDEO_RENDER_VITA_GXM 1

View file

@ -728,6 +728,8 @@ const char *SDL_GetPlatform(void)
return "macOS";
#elif defined(SDL_PLATFORM_NETBSD)
return "NetBSD";
#elif defined(SDL_PLATFORM_NGAGE)
return "Nokia N-Gage";
#elif defined(SDL_PLATFORM_OPENBSD)
return "OpenBSD";
#elif defined(SDL_PLATFORM_OS2)

View file

@ -20,6 +20,8 @@
*/
#include "SDL_internal.h"
#include "stdlib/SDL_vacopy.h"
// Simple error handling in SDL
#include "SDL_error_c.h"

View file

@ -587,6 +587,25 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_S
return;
}
#if defined(SDL_PLATFORM_NGAGE)
extern void NGAGE_vnprintf(char *buf, size_t size, const char *fmt, va_list ap);
char buf[1024];
NGAGE_vnprintf(buf, sizeof(buf), fmt, ap);
#ifdef ENABLE_FILE_LOG
FILE* file;
file = fopen("E:/SDL_Log.txt", "a");
if (file)
{
vfprintf(file, fmt, ap);
fprintf(file, "\n");
(void)fclose(file);
}
#endif
return;
#endif
// Render into stack buffer
va_copy(aq, ap);
len = SDL_vsnprintf(stack_buf, sizeof(stack_buf), fmt, aq);
@ -767,9 +786,14 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
(void)fclose(pFile);
}
}
#elif defined(SDL_PLATFORM_NGAGE)
{
/* Nothing to do here. */
}
#endif
#if defined(HAVE_STDIO_H) && \
!(defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))) && \
!(defined(SDL_PLATFORM_NGAGE)) && \
!(defined(SDL_PLATFORM_WIN32))
(void)fprintf(stderr, "%s%s\n", GetLogPriorityPrefix(priority), message);
#endif

View file

@ -77,6 +77,9 @@ static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_N3DS
&N3DSAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_NGAGE
&NGAGEAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
&EMSCRIPTENAUDIO_bootstrap,
#endif

View file

@ -393,6 +393,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap VITAAUD_bootstrap;
extern AudioBootStrap N3DSAUDIO_bootstrap;
extern AudioBootStrap NGAGEAUDIO_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap QSAAUDIO_bootstrap;

View file

@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_AUDIO_DRIVER_NGAGE
#include "../SDL_sysaudio.h"
#include "SDL_ngageaudio.h"
static SDL_AudioDevice *devptr = NULL;
SDL_AudioDevice *NGAGE_GetAudioDeviceAddr()
{
return devptr;
}
static bool NGAGEAUDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_PrivateAudioData *phdata = SDL_calloc(1, sizeof(SDL_PrivateAudioData));
if (!phdata) {
SDL_OutOfMemory();
return false;
}
device->hidden = phdata;
phdata->buffer = SDL_calloc(1, device->buffer_size);
if (!phdata->buffer) {
SDL_OutOfMemory();
SDL_free(phdata);
return false;
}
devptr = device;
// Since the phone can change the sample rate during a phone call,
// we set the sample rate to 8KHz to be safe. Even though it
// might be possible to adjust the sample rate dynamically, it's
// not supported by the current implementation.
device->spec.format = SDL_AUDIO_S16LE;
device->spec.channels = 1;
device->spec.freq = 8000;
SDL_UpdatedAudioDeviceFormat(device);
return true;
}
static Uint8 *NGAGEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
SDL_PrivateAudioData *phdata = (SDL_PrivateAudioData *)device->hidden;
if (!phdata) {
*buffer_size = 0;
return 0;
}
*buffer_size = device->buffer_size;
return phdata->buffer;
}
static void NGAGEAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
SDL_free(device->hidden->buffer);
SDL_free(device->hidden);
}
return;
}
static bool NGAGEAUDIO_Init(SDL_AudioDriverImpl *impl)
{
impl->OpenDevice = NGAGEAUDIO_OpenDevice;
impl->GetDeviceBuf = NGAGEAUDIO_GetDeviceBuf;
impl->CloseDevice = NGAGEAUDIO_CloseDevice;
impl->ProvidesOwnCallbackThread = true;
impl->OnlyHasDefaultPlaybackDevice = true;
return true;
}
AudioBootStrap NGAGEAUDIO_bootstrap = { "N-Gage", "N-Gage audio driver", NGAGEAUDIO_Init, false };
#endif // SDL_AUDIO_DRIVER_NGAGE

View file

@ -0,0 +1,368 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_ngageaudio.h"
#include "../SDL_sysaudio.h"
#include "SDL_internal.h"
#ifdef __cplusplus
}
#endif
#ifdef SDL_AUDIO_DRIVER_NGAGE
#include "SDL_ngageaudio.hpp"
CAudio::CAudio() : CActive(EPriorityStandard), iBufDes(NULL, 0) {}
CAudio *CAudio::NewL(TInt aLatency)
{
CAudio *self = new (ELeave) CAudio();
CleanupStack::PushL(self);
self->ConstructL(aLatency);
CleanupStack::Pop(self);
return self;
}
void CAudio::ConstructL(TInt aLatency)
{
CActiveScheduler::Add(this);
User::LeaveIfError(iTimer.CreateLocal());
iTimerCreated = ETrue;
iStream = CMdaAudioOutputStream::NewL(*this);
if (!iStream) {
SDL_Log("Error: Failed to create audio stream");
User::Leave(KErrNoMemory);
}
iLatency = aLatency;
iLatencySamples = aLatency * 8; // 8kHz.
// Determine minimum and maximum number of samples to write with one
// WriteL request.
iMinWrite = iLatencySamples / 8;
iMaxWrite = iLatencySamples / 2;
// Set defaults.
iState = EStateNone;
iTimerCreated = EFalse;
iTimerActive = EFalse;
}
CAudio::~CAudio()
{
if (iStream) {
iStream->Stop();
while (iState != EStateDone) {
User::After(100000); // 100ms.
}
delete iStream;
}
}
void CAudio::Start()
{
if (iStream) {
// Set to 8kHz mono audio.
iStreamSettings.iChannels = TMdaAudioDataSettings::EChannelsMono;
iStreamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
iStream->Open(&iStreamSettings);
iState = EStateOpening;
} else {
SDL_Log("Error: Failed to open audio stream");
}
}
// Feeds more processed data to the audio stream.
void CAudio::Feed()
{
// If a WriteL is already in progress, or we aren't even playing;
// do nothing!
if ((iState != EStateWriting) && (iState != EStatePlaying)) {
return;
}
// Figure out the number of samples that really have been played
// through the output.
TTimeIntervalMicroSeconds pos = iStream->Position();
TInt played = 8 * (pos.Int64() / TInt64(1000)).GetTInt(); // 8kHz.
played += iBaseSamplesPlayed;
// Determine the difference between the number of samples written to
// CMdaAudioOutputStream and the number of samples it has played.
// The difference is the amount of data in the buffers.
if (played < 0) {
played = 0;
}
TInt buffered = iSamplesWritten - played;
if (buffered < 0) {
buffered = 0;
}
if (iState == EStateWriting) {
return;
}
// The trick for low latency: Do not let the buffers fill up beyond the
// latency desired! We write as many samples as the difference between
// the latency target (in samples) and the amount of data buffered.
TInt samplesToWrite = iLatencySamples - buffered;
// Do not write very small blocks. This should improve efficiency, since
// writes to the streaming API are likely to be expensive.
if (samplesToWrite < iMinWrite) {
// Not enough data to write, set up a timer to fire after a while.
// Try againwhen it expired.
if (iTimerActive) {
return;
}
iTimerActive = ETrue;
SetActive();
iTimer.After(iStatus, (1000 * iLatency) / 8);
return;
}
// Do not write more than the set number of samples at once.
int numSamples = samplesToWrite;
if (numSamples > iMaxWrite) {
numSamples = iMaxWrite;
}
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
if (device) {
SDL_PrivateAudioData *phdata = (SDL_PrivateAudioData *)device->hidden;
iBufDes.Set(phdata->buffer, 2 * numSamples, 2 * numSamples);
iStream->WriteL(iBufDes);
iState = EStateWriting;
// Keep track of the number of samples written (for latency calculations).
iSamplesWritten += numSamples;
} else {
// Output device not ready yet. Let's go for another round.
if (iTimerActive) {
return;
}
iTimerActive = ETrue;
SetActive();
iTimer.After(iStatus, (1000 * iLatency) / 8);
}
}
void CAudio::RunL()
{
iTimerActive = EFalse;
Feed();
}
void CAudio::DoCancel()
{
iTimerActive = EFalse;
iTimer.Cancel();
}
void CAudio::StartThread()
{
TInt heapMinSize = 8192; // 8 KB initial heap size.
TInt heapMaxSize = 1024 * 1024; // 1 MB maximum heap size.
TInt err = iProcess.Create(_L("ProcessThread"), ProcessThreadCB, KDefaultStackSize * 2, heapMinSize, heapMaxSize, this);
if (err == KErrNone) {
iProcess.SetPriority(EPriorityLess);
iProcess.Resume();
} else {
SDL_Log("Error: Failed to create audio processing thread: %d", err);
}
}
void CAudio::StopThread()
{
if (iStreamStarted) {
iProcess.Kill(KErrNone);
iProcess.Close();
iStreamStarted = EFalse;
}
}
TInt CAudio::ProcessThreadCB(TAny *aPtr)
{
CAudio *self = static_cast<CAudio *>(aPtr);
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
while (self->iStreamStarted) {
if (device) {
SDL_PlaybackAudioThreadIterate(device);
} else {
device = NGAGE_GetAudioDeviceAddr();
}
User::After(100000); // 100ms.
}
return KErrNone;
}
void CAudio::MaoscOpenComplete(TInt aError)
{
if (aError == KErrNone) {
iStream->SetVolume(1);
iStreamStarted = ETrue;
StartThread();
} else {
SDL_Log("Error: Failed to open audio stream: %d", aError);
}
}
void CAudio::MaoscBufferCopied(TInt aError, const TDesC8 & /*aBuffer*/)
{
if (aError == KErrNone) {
iState = EStatePlaying;
Feed();
} else if (aError == KErrAbort) {
// The stream has been stopped.
iState = EStateDone;
} else {
SDL_Log("Error: Failed to copy audio buffer: %d", aError);
}
}
void CAudio::MaoscPlayComplete(TInt aError)
{
// If we finish due to an underflow, we'll need to restart playback.
// Normally KErrUnderlow is raised at stream end, but in our case the API
// should never see the stream end -- we are continuously feeding it more
// data! Many underflow errors mean that the latency target is too low.
if (aError == KErrUnderflow) {
// The number of samples played gets resetted to zero when we restart
// playback after underflow.
iBaseSamplesPlayed = iSamplesWritten;
iStream->Stop();
Cancel();
iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz, TMdaAudioDataSettings::EChannelsMono);
iState = EStatePlaying;
Feed();
return;
} else if (aError != KErrNone) {
// Handle error.
}
// We shouldn't get here.
SDL_Log("%s: %d", __FUNCTION__, aError);
}
static TBool gAudioRunning;
TBool AudioIsReady()
{
return gAudioRunning;
}
TInt AudioThreadCB(TAny *aParams)
{
CTrapCleanup *cleanup = CTrapCleanup::New();
if (!cleanup) {
return KErrNoMemory;
}
CActiveScheduler *scheduler = new CActiveScheduler();
if (!scheduler) {
delete cleanup;
return KErrNoMemory;
}
CActiveScheduler::Install(scheduler);
TRAPD(err,
{
TInt latency = *(TInt *)aParams;
CAudio *audio = CAudio::NewL(latency);
CleanupStack::PushL(audio);
gAudioRunning = ETrue;
audio->Start();
TBool once = EFalse;
while (gAudioRunning) {
// Allow active scheduler to process any events.
TInt error;
CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
if (!once) {
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
if (device) {
// Stream ready; start feeding audio data.
// After feeding it once, the callbacks will take over.
audio->iState = CAudio::EStatePlaying;
audio->Feed();
once = ETrue;
}
}
User::After(100000); // 100ms.
}
CleanupStack::PopAndDestroy(audio);
});
delete scheduler;
delete cleanup;
return err;
}
RThread audioThread;
void InitAudio(TInt *aLatency)
{
_LIT(KAudioThreadName, "AudioThread");
TInt err = audioThread.Create(KAudioThreadName, AudioThreadCB, KDefaultStackSize, 0, aLatency);
if (err != KErrNone) {
User::Leave(err);
}
audioThread.Resume();
}
void DeinitAudio()
{
gAudioRunning = EFalse;
TRequestStatus status;
audioThread.Logon(status);
User::WaitForRequest(status);
audioThread.Close();
}
#endif // SDL_AUDIO_DRIVER_NGAGE

View file

@ -0,0 +1,44 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_ngageaudio_h
#define SDL_ngageaudio_h
typedef struct SDL_PrivateAudioData
{
Uint8 *buffer;
} SDL_PrivateAudioData;
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysaudio.h"
SDL_AudioDevice *NGAGE_GetAudioDeviceAddr();
#ifdef __cplusplus
}
#endif
#endif // SDL_ngageaudio_h

View file

@ -0,0 +1,98 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_ngageaudio_hpp
#define SDL_ngageaudio_hpp
#include <e32base.h>
#include <e32std.h>
#include <mda/common/audio.h>
#include <mdaaudiooutputstream.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysaudio.h"
#include "SDL_ngageaudio.h"
#ifdef __cplusplus
}
#endif
TBool AudioIsReady();
void InitAudio(TInt *aLatency);
void DeinitAudio();
class CAudio : public CActive, public MMdaAudioOutputStreamCallback
{
public:
static CAudio *NewL(TInt aLatency);
~CAudio();
void ConstructL(TInt aLatency);
void Start();
void Feed();
void RunL();
void DoCancel();
static TInt ProcessThreadCB(TAny * /*aPtr*/);
// From MMdaAudioOutputStreamCallback
void MaoscOpenComplete(TInt aError);
void MaoscBufferCopied(TInt aError, const TDesC8 &aBuffer);
void MaoscPlayComplete(TInt aError);
enum
{
EStateNone = 0,
EStateOpening,
EStatePlaying,
EStateWriting,
EStateDone
} iState;
private:
CAudio();
void StartThread();
void StopThread();
CMdaAudioOutputStream *iStream;
TMdaAudioDataSettings iStreamSettings;
TBool iStreamStarted;
TPtr8 iBufDes; // Descriptor for the buffer.
TInt iLatency; // Latency target in ms
TInt iLatencySamples; // Latency target in samples.
TInt iMinWrite; // Min number of samples to write per turn.
TInt iMaxWrite; // Max number of samples to write per turn.
TInt iBaseSamplesPlayed; // amples played before last restart.
TInt iSamplesWritten; // Number of samples written so far.
RTimer iTimer;
TBool iTimerCreated;
TBool iTimerActive;
RThread iProcess;
};
#endif // SDL_ngageaudio_hpp

View file

@ -0,0 +1,77 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <e32std.h>
#include <e32svr.h>
#include <hal.h>
#ifdef __cplusplus
extern "C" {
#endif
bool NGAGE_IsClassicModel()
{
int phone_id;
HAL::Get(HALData::EMachineUid, phone_id);
return (0x101f8c19 == phone_id);
}
void NGAGE_printf(const char *fmt, ...)
{
char buffer[512] = { 0 };
va_list ap;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
TBuf<512> buf;
buf.Copy(TPtrC8((TText8 *)buffer));
RDebug::Print(_L("%S"), &buf);
}
void NGAGE_vnprintf(char *buf, size_t size, const char *fmt, va_list ap)
{
char buffer[512] = { 0 };
vsprintf(buffer, fmt, ap);
TBuf<512> tbuf;
tbuf.Copy(TPtrC8((TText8 *)buffer));
RDebug::Print(_L("%S"), &tbuf);
strncpy(buf, buffer, size - 1);
buf[size - 1] = '\0';
}
TInt NGAGE_GetFreeHeapMemory()
{
TInt free = 0;
return User::Available(free);
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_ngage_h
#define SDL_ngage_h
#ifdef __cplusplus
extern "C" {
#endif
bool NGAGE_IsClassicModel();
#ifdef __cplusplus
}
#endif
#endif /* SDL_ngage_h */

View file

@ -421,6 +421,12 @@ static int CPU_haveARMSIMD(void)
return regs.r[0];
}
#elif defined(SDL_PLATFORM_NGAGE)
static int CPU_haveARMSIMD(void)
{
// The RM920T is based on the ARMv4T architecture and doesn't have SIMD.
return 0;
}
#else
static int CPU_haveARMSIMD(void)
{
@ -468,6 +474,8 @@ static int CPU_haveNEON(void)
return 1;
#elif defined(SDL_PLATFORM_3DS)
return 0;
#elif defined(SDL_PLATFORM_NGAGE)
return 0; // The ARM920T is based on the ARMv4T architecture and doesn't have NEON.
#elif defined(SDL_PLATFORM_APPLE) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
// (note that sysctlbyname("hw.optional.neon") doesn't work!)
return 1; // all Apple ARMv7 chips and later have NEON.

View file

@ -63,6 +63,8 @@
#define SDL_DYNAMIC_API 0 // vitasdk doesn't support dynamic linking
#elif defined(SDL_PLATFORM_3DS)
#define SDL_DYNAMIC_API 0 // devkitARM doesn't support dynamic linking
#elif defined(SDL_PLATFORM_NGAGE)
#define SDL_DYNAMIC_API 0
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
#define SDL_DYNAMIC_API 0 // we need dlopen(), but don't have it....
#endif

View file

@ -0,0 +1,67 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
extern void NGAGE_GetAppPath(char* path);
char *SDL_SYS_GetBasePath(void)
{
char app_path[512];
NGAGE_GetAppPath(app_path);
char *base_path = SDL_strdup(app_path);
return base_path;
}
char *SDL_SYS_GetPrefPath(const char *org, const char *app)
{
char *pref_path;
if (SDL_asprintf(&pref_path, "C:/System/Apps/%s/%s/", org, app) < 0)
return NULL;
else
return pref_path;
}
char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{
const char *folder_path = NULL;
switch (folder)
{
case SDL_FOLDER_HOME:
folder_path = "C:/";
break;
case SDL_FOLDER_PICTURES:
folder_path = "C:/Nokia/Pictures/";
break;
case SDL_FOLDER_SAVEDGAMES:
folder_path = "C:/";
break;
case SDL_FOLDER_SCREENSHOTS:
folder_path = "C:/Nokia/Pictures/";
break;
case SDL_FOLDER_VIDEOS:
folder_path = "C:/Nokia/Videos/";
break;
default:
folder_path = "C:/Nokia/Others/";
break;
}
return SDL_strdup(folder_path);
}

View file

@ -0,0 +1,68 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_internal.h"
#ifdef __cplusplus
}
#endif
#include <e32base.h>
#include <e32std.h>
#include <f32file.h>
#include <utf.h>
#ifdef __cplusplus
extern "C" {
#endif
void NGAGE_GetAppPath(char* path)
{
TBuf<512> aPath;
TFileName fullExePath = RProcess().FileName();
TParsePtrC parser(fullExePath);
aPath.Copy(parser.DriveAndPath());
TBuf8<512> utf8Path; // Temporary buffer for UTF-8 data.
CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8Path, aPath);
// Copy UTF-8 data to the provided char* buffer.
strncpy(path, (const char*)utf8Path.Ptr(), utf8Path.Length());
path[utf8Path.Length()] = '\0';
// Replace backslashes with forward slashes.
for (int i = 0; i < utf8Path.Length(); i++)
{
if (path[i] == '\\')
{
path[i] = '/';
}
}
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,307 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_syslocale.h"
#include "SDL_internal.h"
#include <bautils.h>
#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
bool SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
{
TLanguage language = User::Language();
const char *locale;
switch (language) {
case ELangFrench:
case ELangSwissFrench:
locale = "fr_CH";
break;
case ELangBelgianFrench:
locale = "fr_BE";
break;
case ELangInternationalFrench:
locale = "fr_FR";
break;
case ELangGerman:
case ELangSwissGerman:
case ELangAustrian:
locale = "de_DE";
break;
case ELangSpanish:
case ELangInternationalSpanish:
case ELangLatinAmericanSpanish:
locale = "es_ES";
break;
case ELangItalian:
case ELangSwissItalian:
locale = "it_IT";
break;
case ELangSwedish:
case ELangFinlandSwedish:
locale = "sv_SE";
break;
case ELangDanish:
locale = "da_DK";
break;
case ELangNorwegian:
case ELangNorwegianNynorsk:
locale = "no_NO";
break;
case ELangFinnish:
locale = "fi_FI";
break;
case ELangPortuguese:
locale = "pt_PT";
break;
case ELangBrazilianPortuguese:
locale = "pt_BR";
break;
case ELangTurkish:
case ELangCyprusTurkish:
locale = "tr_TR";
break;
case ELangIcelandic:
locale = "is_IS";
break;
case ELangRussian:
locale = "ru_RU";
break;
case ELangHungarian:
locale = "hu_HU";
break;
case ELangDutch:
locale = "nl_NL";
break;
case ELangBelgianFlemish:
locale = "nl_BE";
break;
case ELangAustralian:
case ELangNewZealand:
locale = "en_AU";
break;
case ELangCzech:
locale = "cs_CZ";
break;
case ELangSlovak:
locale = "sk_SK";
break;
case ELangPolish:
locale = "pl_PL";
break;
case ELangSlovenian:
locale = "sl_SI";
break;
case ELangTaiwanChinese:
locale = "zh_TW";
break;
case ELangHongKongChinese:
locale = "zh_HK";
break;
case ELangPrcChinese:
locale = "zh_CN";
break;
case ELangJapanese:
locale = "ja_JP";
break;
case ELangThai:
locale = "th_TH";
break;
case ELangAfrikaans:
locale = "af_ZA";
break;
case ELangAlbanian:
locale = "sq_AL";
break;
case ELangAmharic:
locale = "am_ET";
break;
case ELangArabic:
locale = "ar_SA";
break;
case ELangArmenian:
locale = "hy_AM";
break;
case ELangAzerbaijani:
locale = "az_AZ";
break;
case ELangBelarussian:
locale = "be_BY";
break;
case ELangBengali:
locale = "bn_IN";
break;
case ELangBulgarian:
locale = "bg_BG";
break;
case ELangBurmese:
locale = "my_MM";
break;
case ELangCatalan:
locale = "ca_ES";
break;
case ELangCroatian:
locale = "hr_HR";
break;
case ELangEstonian:
locale = "et_EE";
break;
case ELangFarsi:
locale = "fa_IR";
break;
case ELangCanadianFrench:
locale = "fr_CA";
break;
case ELangScotsGaelic:
locale = "gd_GB";
break;
case ELangGeorgian:
locale = "ka_GE";
break;
case ELangGreek:
case ELangCyprusGreek:
locale = "el_GR";
break;
case ELangGujarati:
locale = "gu_IN";
break;
case ELangHebrew:
locale = "he_IL";
break;
case ELangHindi:
locale = "hi_IN";
break;
case ELangIndonesian:
locale = "id_ID";
break;
case ELangIrish:
locale = "ga_IE";
break;
case ELangKannada:
locale = "kn_IN";
break;
case ELangKazakh:
locale = "kk_KZ";
break;
case ELangKhmer:
locale = "km_KH";
break;
case ELangKorean:
locale = "ko_KR";
break;
case ELangLao:
locale = "lo_LA";
break;
case ELangLatvian:
locale = "lv_LV";
break;
case ELangLithuanian:
locale = "lt_LT";
break;
case ELangMacedonian:
locale = "mk_MK";
break;
case ELangMalay:
locale = "ms_MY";
break;
case ELangMalayalam:
locale = "ml_IN";
break;
case ELangMarathi:
locale = "mr_IN";
break;
case ELangMoldavian:
locale = "ro_MD";
break;
case ELangMongolian:
locale = "mn_MN";
break;
case ELangPunjabi:
locale = "pa_IN";
break;
case ELangRomanian:
locale = "ro_RO";
break;
case ELangSerbian:
locale = "sr_RS";
break;
case ELangSinhalese:
locale = "si_LK";
break;
case ELangSomali:
locale = "so_SO";
break;
case ELangSwahili:
locale = "sw_KE";
break;
case ELangTajik:
locale = "tg_TJ";
break;
case ELangTamil:
locale = "ta_IN";
break;
case ELangTelugu:
locale = "te_IN";
break;
case ELangTibetan:
locale = "bo_CN";
break;
case ELangTigrinya:
locale = "ti_ET";
break;
case ELangTurkmen:
locale = "tk_TM";
break;
case ELangUkrainian:
locale = "uk_UA";
break;
case ELangUrdu:
locale = "ur_PK";
break;
case ELangUzbek:
locale = "uz_UZ";
break;
case ELangVietnamese:
locale = "vi_VN";
break;
case ELangWelsh:
locale = "cy_GB";
break;
case ELangZulu:
locale = "zu_ZA";
break;
case ELangEnglish:
locale = "en_GB";
break;
case ELangAmerican:
case ELangCanadianEnglish:
case ELangInternationalEnglish:
case ELangSouthAfricanEnglish:
default:
locale = "en_US";
break;
}
SDL_strlcpy(buf, locale, buflen);
return true;
}

View file

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_NGAGE
int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
// Intentionally does nothing; Callbacks are called using the RunL() method.
return 0;
}
#endif // SDL_PLATFORM_NGAGE

View file

@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_internal.h"
extern SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]);
extern SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event);
extern SDL_AppResult SDL_AppIterate(void* appstate);
extern void SDL_AppQuit(void* appstate, SDL_AppResult result);
#ifdef __cplusplus
}
#endif
#include <e32std.h>
#include <estlib.h>
#include <stdlib.h>
#include <stdio.h>
#include "SDL_sysmain_main.hpp"
#include "../../audio/ngage/SDL_ngageaudio.hpp"
#include "../../render/ngage/SDL_render_ngage_c.hpp"
CRenderer *gRenderer = 0;
GLDEF_C TInt E32Main()
{
// Get args and environment.
int argc = 1;
char* argv[] = { "game", NULL };
char** envp = NULL;
// Create lvalue variables for __crt0 arguments.
char** argv_lvalue = argv;
char** envp_lvalue = envp;
CTrapCleanup* cleanup = CTrapCleanup::New();
if (!cleanup)
{
return KErrNoMemory;
}
TRAPD(err,
{
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
TInt posixErr = SpawnPosixServerThread();
if (posixErr != KErrNone)
{
SDL_Log("Error: Failed to spawn POSIX server thread: %d", posixErr);
User::Leave(posixErr);
}
__crt0(argc, argv_lvalue, envp_lvalue);
// Increase heap size.
RHeap* newHeap = User::ChunkHeap(NULL, 7500000, 7500000, KMinHeapGrowBy);
if (!newHeap)
{
SDL_Log("Error: Failed to create new heap");
User::Leave(KErrNoMemory);
}
CleanupStack::PushL(newHeap);
RHeap* oldHeap = User::SwitchHeap(newHeap);
TInt targetLatency = 225;
InitAudio(&targetLatency);
// Wait until audio is ready.
while (!AudioIsReady())
{
User::After(100000); // 100ms.
}
// Create and start the rendering backend.
gRenderer = CRenderer::NewL();
CleanupStack::PushL(gRenderer);
// Create and start the SDL main runner.
CSDLmain* mainApp = CSDLmain::NewL();
CleanupStack::PushL(mainApp);
mainApp->Start();
// Start the active scheduler to handle events.
CActiveScheduler::Start();
CleanupStack::PopAndDestroy(gRenderer);
CleanupStack::PopAndDestroy(mainApp);
User::SwitchHeap(oldHeap);
CleanupStack::PopAndDestroy(newHeap);
CleanupStack::PopAndDestroy(scheduler);
});
if (err != KErrNone)
{
SDL_Log("Error: %d", err);
}
return err;
}
CSDLmain* CSDLmain::NewL()
{
CSDLmain* self = new (ELeave) CSDLmain();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CSDLmain::CSDLmain() : CActive(EPriorityLow) {}
void CSDLmain::ConstructL()
{
CActiveScheduler::Add(this);
}
CSDLmain::~CSDLmain()
{
Cancel();
}
void CSDLmain::Start()
{
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
}
void CSDLmain::DoCancel() {}
static bool callbacks_initialized = false;
void CSDLmain::RunL()
{
if (callbacks_initialized)
{
SDL_Event event;
iResult = SDL_AppIterate(NULL);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
SDL_PumpEvents();
if (SDL_PollEvent(&event))
{
iResult = SDL_AppEvent(NULL, &event);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
}
Start();
}
else
{
SDL_SetMainReady();
SDL_AppInit(NULL, 0, NULL);
callbacks_initialized = true;
Start();
}
}

View file

@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_sysmain_main_hpp_
#define SDL_sysmain_main_hpp_
#include <e32std.h>
class CSDLmain : public CActive
{
public:
static CSDLmain* NewL();
~CSDLmain();
void Start();
protected:
void DoCancel() ;
void RunL();
private:
CSDLmain();
void ConstructL();
SDL_AppResult iResult;
};
#endif // SDL_sysmain_main_hpp_

View file

@ -120,6 +120,9 @@ static const SDL_RenderDriver *render_drivers[] = {
#ifdef SDL_VIDEO_RENDER_METAL
&METAL_RenderDriver,
#endif
#ifdef SDL_VIDEO_RENDER_NGAGE
&NGAGE_RenderDriver,
#endif
#ifdef SDL_VIDEO_RENDER_OGL
&GL_RenderDriver,
#endif

View file

@ -357,6 +357,7 @@ extern SDL_RenderDriver D3D12_RenderDriver;
extern SDL_RenderDriver GL_RenderDriver;
extern SDL_RenderDriver GLES2_RenderDriver;
extern SDL_RenderDriver METAL_RenderDriver;
extern SDL_RenderDriver NGAGE_RenderDriver;
extern SDL_RenderDriver VULKAN_RenderDriver;
extern SDL_RenderDriver PS2_RenderDriver;
extern SDL_RenderDriver PSP_RenderDriver;

View file

@ -0,0 +1,544 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_NGAGE
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef Int2Fix
#define Int2Fix(i) ((i) << 16)
#endif
#ifndef Fix2Int
#define Fix2Int(i) ((((unsigned int)(i) > 0xFFFF0000) ? 0 : ((i) >> 16)))
#endif
#ifndef Fix2Real
#define Fix2Real(i) ((i) / 65536.0)
#endif
#ifndef Real2Fix
#define Real2Fix(i) ((int)((i) * 65536.0))
#endif
#include "../SDL_sysrender.h"
#include "SDL_render_ngage_c.h"
static void NGAGE_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event);
static bool NGAGE_GetOutputSize(SDL_Renderer *renderer, int *w, int *h);
static bool NGAGE_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode);
static bool NGAGE_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props);
static bool NGAGE_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd);
static bool NGAGE_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd);
static bool NGAGE_QueueDrawVertices(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count);
static bool NGAGE_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count);
static bool NGAGE_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect);
static bool NGAGE_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y);
static bool NGAGE_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, float scale_x, float scale_y);
static void NGAGE_InvalidateCachedState(SDL_Renderer *renderer);
static bool NGAGE_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
static bool NGAGE_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch);
static bool NGAGE_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch);
static void NGAGE_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
static void NGAGE_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode);
static bool NGAGE_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture);
static SDL_Surface *NGAGE_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect);
static bool NGAGE_RenderPresent(SDL_Renderer *renderer);
static void NGAGE_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
static void NGAGE_DestroyRenderer(SDL_Renderer *renderer);
static bool NGAGE_SetVSync(SDL_Renderer *renderer, int vsync);
static bool NGAGE_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
{
SDL_SetupRendererColorspace(renderer, create_props);
if (renderer->output_colorspace != SDL_COLORSPACE_RGB_DEFAULT) {
return SDL_SetError("Unsupported output colorspace");
}
NGAGE_RendererData *phdata = SDL_calloc(1, sizeof(NGAGE_RendererData));
if (!phdata) {
SDL_OutOfMemory();
return false;
}
renderer->WindowEvent = NGAGE_WindowEvent;
renderer->GetOutputSize = NGAGE_GetOutputSize;
renderer->SupportsBlendMode = NGAGE_SupportsBlendMode;
renderer->CreateTexture = NGAGE_CreateTexture;
renderer->QueueSetViewport = NGAGE_QueueSetViewport;
renderer->QueueSetDrawColor = NGAGE_QueueSetDrawColor;
renderer->QueueDrawPoints = NGAGE_QueueDrawVertices;
renderer->QueueDrawLines = NGAGE_QueueDrawVertices;
renderer->QueueFillRects = NGAGE_QueueFillRects;
renderer->QueueCopy = NGAGE_QueueCopy;
renderer->QueueCopyEx = NGAGE_QueueCopyEx;
renderer->QueueGeometry = NGAGE_QueueGeometry;
renderer->InvalidateCachedState = NGAGE_InvalidateCachedState;
renderer->RunCommandQueue = NGAGE_RunCommandQueue;
renderer->UpdateTexture = NGAGE_UpdateTexture;
renderer->LockTexture = NGAGE_LockTexture;
renderer->UnlockTexture = NGAGE_UnlockTexture;
// renderer->SetTextureScaleMode = NGAGE_SetTextureScaleMode;
renderer->SetRenderTarget = NGAGE_SetRenderTarget;
renderer->RenderReadPixels = NGAGE_RenderReadPixels;
renderer->RenderPresent = NGAGE_RenderPresent;
renderer->DestroyTexture = NGAGE_DestroyTexture;
renderer->DestroyRenderer = NGAGE_DestroyRenderer;
renderer->SetVSync = NGAGE_SetVSync;
renderer->name = NGAGE_RenderDriver.name;
renderer->window = window;
renderer->internal = phdata;
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444);
SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 256);
SDL_SetHintWithPriority(SDL_HINT_RENDER_LINE_METHOD, "2", SDL_HINT_OVERRIDE);
return true;
}
SDL_RenderDriver NGAGE_RenderDriver = {
NGAGE_CreateRenderer,
"N-Gage"
};
static void NGAGE_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
{
return;
}
static bool NGAGE_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
{
return true;
}
static bool NGAGE_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
{
switch (blendMode) {
case SDL_BLENDMODE_NONE:
case SDL_BLENDMODE_MOD:
return true;
default:
return false;
}
}
static bool NGAGE_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{
NGAGE_TextureData *data = (NGAGE_TextureData *)SDL_calloc(1, sizeof(*data));
if (!data) {
return false;
}
if (!NGAGE_CreateTextureData(data, texture->w, texture->h)) {
SDL_free(data);
return false;
}
SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format);
if (!surface) {
SDL_free(data);
return false;
}
data->surface = surface;
texture->internal = data;
return true;
}
static bool NGAGE_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
{
if (!cmd->data.viewport.rect.w && !cmd->data.viewport.rect.h) {
SDL_Rect viewport = { 0, 0, NGAGE_SCREEN_WIDTH, NGAGE_SCREEN_HEIGHT };
SDL_SetRenderViewport(renderer, &viewport);
}
return true;
}
static bool NGAGE_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
{
return true;
}
static bool NGAGE_QueueDrawVertices(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(NGAGE_Vertex), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = count;
for (int i = 0; i < count; i++, points++) {
int fixed_x = Real2Fix(points->x);
int fixed_y = Real2Fix(points->y);
verts[i].x = Fix2Int(fixed_x);
verts[i].y = Fix2Int(fixed_y);
Uint32 color = NGAGE_ConvertColor(cmd->data.draw.color.r, cmd->data.draw.color.g, cmd->data.draw.color.b, cmd->data.draw.color.a, cmd->data.draw.color_scale);
verts[i].color.a = (Uint8)(color >> 24);
verts[i].color.b = (Uint8)(color >> 16);
verts[i].color.g = (Uint8)(color >> 8);
verts[i].color.r = (Uint8)color;
}
return true;
}
static bool NGAGE_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(NGAGE_Vertex), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = count;
for (int i = 0; i < count; i++, rects++) {
verts[i * 2].x = Real2Fix(rects->x);
verts[i * 2].y = Real2Fix(rects->y);
verts[i * 2 + 1].x = Real2Fix(rects->w);
verts[i * 2 + 1].y = Real2Fix(rects->h);
verts[i * 2].x = Fix2Int(verts[i * 2].x);
verts[i * 2].y = Fix2Int(verts[i * 2].y);
verts[i * 2 + 1].x = Fix2Int(verts[i * 2 + 1].x);
verts[i * 2 + 1].y = Fix2Int(verts[i * 2 + 1].y);
Uint32 color = NGAGE_ConvertColor(cmd->data.draw.color.r, cmd->data.draw.color.g, cmd->data.draw.color.b, cmd->data.draw.color.a, cmd->data.draw.color_scale);
verts[i * 2].color.a = (Uint8)(color >> 24);
verts[i * 2].color.b = (Uint8)(color >> 16);
verts[i * 2].color.g = (Uint8)(color >> 8);
verts[i * 2].color.r = (Uint8)color;
}
return true;
}
static bool NGAGE_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect)
{
SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(SDL_Rect), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = 1;
verts->x = (int)srcrect->x;
verts->y = (int)srcrect->y;
verts->w = (int)srcrect->w;
verts->h = (int)srcrect->h;
verts++;
verts->x = (int)dstrect->x;
verts->y = (int)dstrect->y;
verts->w = (int)dstrect->w;
verts->h = (int)dstrect->h;
return true;
}
static bool NGAGE_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
NGAGE_CopyExData *verts = (NGAGE_CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(NGAGE_CopyExData), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = 1;
verts->srcrect.x = (int)srcquad->x;
verts->srcrect.y = (int)srcquad->y;
verts->srcrect.w = (int)srcquad->w;
verts->srcrect.h = (int)srcquad->h;
verts->dstrect.x = (int)dstrect->x;
verts->dstrect.y = (int)dstrect->y;
verts->dstrect.w = (int)dstrect->w;
verts->dstrect.h = (int)dstrect->h;
verts->angle = Real2Fix(angle);
verts->center.x = Real2Fix(center->x);
verts->center.y = Real2Fix(center->y);
verts->scale_x = Real2Fix(scale_x);
verts->scale_y = Real2Fix(scale_y);
verts->flip = flip;
return true;
}
static bool NGAGE_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, float scale_x, float scale_y)
{
return true;
}
static void NGAGE_InvalidateCachedState(SDL_Renderer *renderer)
{
return;
}
static bool NGAGE_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
NGAGE_RendererData *phdata = (NGAGE_RendererData *)renderer->internal;
if (!phdata) {
return false;
}
phdata->viewport = 0;
while (cmd) {
switch (cmd->command) {
case SDL_RENDERCMD_NO_OP:
break;
case SDL_RENDERCMD_SETVIEWPORT:
phdata->viewport = &cmd->data.viewport.rect;
break;
case SDL_RENDERCMD_SETCLIPRECT:
{
const SDL_Rect *rect = &cmd->data.cliprect.rect;
if (cmd->data.cliprect.enabled) {
NGAGE_SetClipRect(rect);
}
break;
}
case SDL_RENDERCMD_SETDRAWCOLOR:
{
break;
}
case SDL_RENDERCMD_CLEAR:
{
Uint32 color = NGAGE_ConvertColor(cmd->data.color.color.r, cmd->data.color.color.g, cmd->data.color.color.b, cmd->data.color.color.a, cmd->data.color.color_scale);
NGAGE_Clear(color);
break;
}
case SDL_RENDERCMD_DRAW_POINTS:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_DrawPoints(verts, count);
break;
}
case SDL_RENDERCMD_DRAW_LINES:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_DrawLines(verts, count);
break;
}
case SDL_RENDERCMD_FILL_RECTS:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_FillRects(verts, count);
break;
}
case SDL_RENDERCMD_COPY:
{
SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first);
SDL_Rect *srcrect = verts;
SDL_Rect *dstrect = verts + 1;
SDL_Texture *texture = cmd->data.draw.texture;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
dstrect->x += phdata->viewport->x;
dstrect->y += phdata->viewport->y;
}
NGAGE_Copy(renderer, texture, srcrect, dstrect);
break;
}
case SDL_RENDERCMD_COPY_EX:
{
NGAGE_CopyExData *copydata = (NGAGE_CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first);
SDL_Texture *texture = cmd->data.draw.texture;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
copydata->dstrect.x += phdata->viewport->x;
copydata->dstrect.y += phdata->viewport->y;
}
NGAGE_CopyEx(renderer, texture, copydata);
break;
}
case SDL_RENDERCMD_GEOMETRY:
{
break;
}
}
cmd = cmd->next;
}
return true;
}
static bool NGAGE_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
SDL_Surface *surface = phdata->surface;
Uint8 *src, *dst;
int row;
size_t length;
if (SDL_MUSTLOCK(surface)) {
if (!SDL_LockSurface(surface)) {
return false;
}
}
src = (Uint8 *)pixels;
dst = (Uint8 *)surface->pixels +
rect->y * surface->pitch +
rect->x * surface->fmt->bytes_per_pixel;
length = (size_t)rect->w * surface->fmt->bytes_per_pixel;
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
dst += surface->pitch;
}
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
return true;
}
static bool NGAGE_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
SDL_Surface *surface = phdata->surface;
*pixels =
(void *)((Uint8 *)surface->pixels + rect->y * surface->pitch +
rect->x * surface->fmt->bytes_per_pixel);
*pitch = surface->pitch;
return true;
}
static void NGAGE_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
}
static void NGAGE_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
{
}
static bool NGAGE_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
{
return true;
}
static SDL_Surface *NGAGE_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
{
return (SDL_Surface *)0;
}
static bool NGAGE_RenderPresent(SDL_Renderer *renderer)
{
NGAGE_Flip();
return true;
}
static void NGAGE_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
NGAGE_TextureData *data = (NGAGE_TextureData *)texture->internal;
if (data) {
SDL_DestroySurface(data->surface);
NGAGE_DestroyTextureData(data);
SDL_free(data);
texture->internal = 0;
}
}
static void NGAGE_DestroyRenderer(SDL_Renderer *renderer)
{
NGAGE_RendererData *phdata = (NGAGE_RendererData *)renderer->internal;
if (phdata) {
SDL_free(phdata);
renderer->internal = 0;
}
}
static bool NGAGE_SetVSync(SDL_Renderer *renderer, int vsync)
{
return true;
}
#endif // SDL_VIDEO_RENDER_NGAGE

View file

@ -0,0 +1,744 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "../../events/SDL_keyboard_c.h"
#include "../SDL_sysrender.h"
#include "SDL_internal.h"
#include "SDL_render_ngage_c.h"
#ifdef __cplusplus
}
#endif
#ifdef SDL_VIDEO_RENDER_NGAGE
#include "SDL_render_ngage_c.hpp"
#include "SDL_render_ops.hpp"
const TUint32 WindowClientHandle = 0x571D0A;
extern CRenderer *gRenderer;
#ifdef __cplusplus
extern "C" {
#endif
void NGAGE_Clear(const Uint32 color)
{
gRenderer->Clear(color);
}
bool NGAGE_Copy(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcrect, SDL_Rect *dstrect)
{
return gRenderer->Copy(renderer, texture, srcrect, dstrect);
}
bool NGAGE_CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, NGAGE_CopyExData *copydata)
{
return gRenderer->CopyEx(renderer, texture, copydata);
}
bool NGAGE_CreateTextureData(NGAGE_TextureData *data, const int width, const int height)
{
return gRenderer->CreateTextureData(data, width, height);
}
void NGAGE_DestroyTextureData(NGAGE_TextureData *data)
{
if (data) {
delete data->bitmap;
data->bitmap = NULL;
}
}
void NGAGE_DrawLines(NGAGE_Vertex *verts, const int count)
{
gRenderer->DrawLines(verts, count);
}
void NGAGE_DrawPoints(NGAGE_Vertex *verts, const int count)
{
gRenderer->DrawPoints(verts, count);
}
void NGAGE_FillRects(NGAGE_Vertex *verts, const int count)
{
gRenderer->FillRects(verts, count);
}
void NGAGE_Flip()
{
gRenderer->Flip();
}
void NGAGE_SetClipRect(const SDL_Rect *rect)
{
gRenderer->SetClipRect(rect->x, rect->y, rect->w, rect->h);
}
void NGAGE_SetDrawColor(const Uint32 color)
{
if (gRenderer) {
gRenderer->SetDrawColor(color);
}
}
void NGAGE_PumpEventsInternal()
{
gRenderer->PumpEvents();
}
void NGAGE_SuspendScreenSaverInternal(bool suspend)
{
gRenderer->SuspendScreenSaver(suspend);
}
#ifdef __cplusplus
}
#endif
CRenderer *CRenderer::NewL()
{
CRenderer *self = new (ELeave) CRenderer();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0) {}
CRenderer::~CRenderer()
{
delete iRenderer;
iRenderer = 0;
}
void CRenderer::ConstructL()
{
TInt error = KErrNone;
error = iWsSession.Connect();
if (error != KErrNone) {
SDL_Log("Failed to connect to window server: %d", error);
User::Leave(error);
}
iWsScreen = new (ELeave) CWsScreenDevice(iWsSession);
error = iWsScreen->Construct();
if (error != KErrNone) {
SDL_Log("Failed to construct screen device: %d", error);
User::Leave(error);
}
iWsWindowGroup = RWindowGroup(iWsSession);
error = iWsWindowGroup.Construct(WindowClientHandle);
if (error != KErrNone) {
SDL_Log("Failed to construct window group: %d", error);
User::Leave(error);
}
iWsWindowGroup.SetOrdinalPosition(0);
RProcess thisProcess;
TParse exeName;
exeName.Set(thisProcess.FileName(), NULL, NULL);
TBuf<32> winGroupName;
winGroupName.Append(0);
winGroupName.Append(0);
winGroupName.Append(0); // UID
winGroupName.Append(0);
winGroupName.Append(exeName.Name()); // Caption
winGroupName.Append(0);
winGroupName.Append(0); // DOC name
iWsWindowGroup.SetName(winGroupName);
iWsWindow = RWindow(iWsSession);
error = iWsWindow.Construct(iWsWindowGroup, WindowClientHandle - 1);
if (error != KErrNone) {
SDL_Log("Failed to construct window: %d", error);
User::Leave(error);
}
iWsWindow.SetBackgroundColor(KRgbWhite);
iWsWindow.SetRequiredDisplayMode(EColor4K);
iWsWindow.Activate();
iWsWindow.SetSize(iWsScreen->SizeInPixels());
iWsWindow.SetVisible(ETrue);
iWsWindowGroupID = iWsWindowGroup.Identifier();
TRAPD(errc, iRenderer = iRenderer->NewL());
if (errc != KErrNone) {
SDL_Log("Failed to create renderer: %d", errc);
return;
}
iDirectScreen = CDirectScreenAccess::NewL(
iWsSession,
*(iWsScreen),
iWsWindow, *this);
// Select font.
TFontSpec fontSpec(_L("LatinBold12"), 12);
TInt errd = iWsScreen->GetNearestFontInTwips((CFont *&)iFont, fontSpec);
if (errd != KErrNone) {
SDL_Log("Failed to get font: %d", errd);
return;
}
// Activate events.
iWsEventStatus = KRequestPending;
iWsSession.EventReady(&iWsEventStatus);
DisableKeyBlocking();
iIsFocused = ETrue;
iShowFPS = EFalse;
iSuspendScreenSaver = EFalse;
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
}
}
void CRenderer::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
}
}
void CRenderer::AbortNow(RDirectScreenAccess::TTerminationReasons aReason)
{
if (iDirectScreen->IsActive()) {
iDirectScreen->Cancel();
}
}
void CRenderer::Clear(TUint32 iColor)
{
if (iRenderer && iRenderer->Gc()) {
iRenderer->Gc()->SetBrushColor(iColor);
iRenderer->Gc()->Clear();
}
}
#ifdef __cplusplus
extern "C" {
#endif
Uint32 NGAGE_ConvertColor(float r, float g, float b, float a, float color_scale)
{
TFixed ff = 255 << 16; // 255.f
TFixed scalef = Real2Fix(color_scale);
TFixed rf = Real2Fix(r);
TFixed gf = Real2Fix(g);
TFixed bf = Real2Fix(b);
TFixed af = Real2Fix(a);
rf = FixMul(rf, scalef);
gf = FixMul(gf, scalef);
bf = FixMul(bf, scalef);
rf = SDL_clamp(rf, 0, ff);
gf = SDL_clamp(gf, 0, ff);
bf = SDL_clamp(bf, 0, ff);
af = SDL_clamp(af, 0, ff);
rf = FixMul(rf, ff) >> 16;
gf = FixMul(gf, ff) >> 16;
bf = FixMul(bf, ff) >> 16;
af = FixMul(af, ff) >> 16;
return (af << 24) | (bf << 16) | (gf << 8) | rf;
}
#ifdef __cplusplus
}
#endif
bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect)
{
if (!texture) {
return false;
}
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
if (!phdata) {
return false;
}
SDL_FColor *c = &texture->color;
int w = phdata->surface->w;
int h = phdata->surface->h;
int pitch = phdata->surface->pitch;
void *source = phdata->surface->pixels;
void *dest;
if (!source) {
return false;
}
void *pixel_buffer_a = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
return false;
}
dest = pixel_buffer_a;
void *pixel_buffer_b = SDL_calloc(1, pitch * h);
if (!pixel_buffer_b) {
SDL_free(pixel_buffer_a);
return false;
}
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
ApplyColorMod(dest, source, pitch, w, h, texture->color);
source = dest;
}
float sx;
float sy;
SDL_GetRenderScale(renderer, &sx, &sy);
if (sx != 1.f || sy != 1.f) {
TFixed scale_x = Real2Fix(sx);
TFixed scale_y = Real2Fix(sy);
TFixed center_x = Int2Fix(w / 2);
TFixed center_y = Int2Fix(h / 2);
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyScale(dest, source, pitch, w, h, center_x, center_y, scale_x, scale_y);
source = dest;
}
Mem::Copy(phdata->bitmap->DataAddress(), source, pitch * h);
SDL_free(pixel_buffer_a);
SDL_free(pixel_buffer_b);
if (phdata->bitmap) {
TRect aSource(TPoint(srcrect->x, srcrect->y), TSize(srcrect->w, srcrect->h));
TPoint aDest(dstrect->x, dstrect->y);
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
}
return true;
}
bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE_CopyExData *copydata)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
if (!phdata) {
return false;
}
SDL_FColor *c = &texture->color;
int w = phdata->surface->w;
int h = phdata->surface->h;
int pitch = phdata->surface->pitch;
void *source = phdata->surface->pixels;
void *dest;
if (!source) {
return false;
}
void *pixel_buffer_a = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
return false;
}
dest = pixel_buffer_a;
void *pixel_buffer_b = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
SDL_free(pixel_buffer_a);
return false;
}
if (copydata->flip) {
ApplyFlip(dest, source, pitch, w, h, copydata->flip);
source = dest;
}
if (copydata->scale_x != 1.f || copydata->scale_y != 1.f) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyScale(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->scale_x, copydata->scale_y);
source = dest;
}
if (copydata->angle) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyRotation(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->angle);
source = dest;
}
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyColorMod(dest, source, pitch, w, h, texture->color);
source = dest;
}
Mem::Copy(phdata->bitmap->DataAddress(), source, pitch * h);
SDL_free(pixel_buffer_a);
SDL_free(pixel_buffer_b);
if (phdata->bitmap) {
TRect aSource(TPoint(copydata->srcrect.x, copydata->srcrect.y), TSize(copydata->srcrect.w, copydata->srcrect.h));
TPoint aDest(copydata->dstrect.x, copydata->dstrect.y);
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
}
return true;
}
bool CRenderer::CreateTextureData(NGAGE_TextureData *aTextureData, const TInt aWidth, const TInt aHeight)
{
if (!aTextureData) {
return false;
}
aTextureData->bitmap = new CFbsBitmap();
if (!aTextureData->bitmap) {
return false;
}
TInt error = aTextureData->bitmap->Create(TSize(aWidth, aHeight), EColor4K);
if (error != KErrNone) {
delete aTextureData->bitmap;
aTextureData->bitmap = NULL;
return false;
}
return true;
}
void CRenderer::DrawLines(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
TPoint *aPoints = new TPoint[aCount];
for (TInt i = 0; i < aCount; i++) {
aPoints[i] = TPoint(aVerts[i].x, aVerts[i].y);
}
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->DrawPolyLineNoEndPoint(aPoints, aCount);
delete[] aPoints;
}
}
void CRenderer::DrawPoints(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
for (TInt i = 0; i < aCount; i++, aVerts++) {
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->Plot(TPoint(aVerts->x, aVerts->y));
}
}
}
void CRenderer::FillRects(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
for (TInt i = 0; i < aCount; i++, aVerts++) {
TPoint pos(aVerts[i].x, aVerts[i].y);
TSize size(
aVerts[i + 1].x,
aVerts[i + 1].y);
TRect rect(pos, size);
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->SetBrushColor(aColor);
iRenderer->Gc()->DrawRect(rect);
}
}
}
void CRenderer::Flip()
{
if (!iRenderer) {
SDL_Log("iRenderer is NULL.");
return;
}
if (!iIsFocused) {
return;
}
iRenderer->Gc()->UseFont(iFont);
if (iShowFPS && iRenderer->Gc()) {
UpdateFPS();
TBuf<64> info;
iRenderer->Gc()->SetPenStyle(CGraphicsContext::ESolidPen);
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ENullBrush);
iRenderer->Gc()->SetPenColor(KRgbCyan);
TRect aTextRect(TPoint(3, 203 - iFont->HeightInPixels()), TSize(45, iFont->HeightInPixels() + 2));
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ESolidBrush);
iRenderer->Gc()->SetBrushColor(KRgbBlack);
iRenderer->Gc()->DrawRect(aTextRect);
// Draw messages.
info.Format(_L("FPS: %d"), iFPS);
iRenderer->Gc()->DrawText(info, TPoint(5, 203));
} else {
// This is a workaround that helps regulating the FPS.
iRenderer->Gc()->DrawText(_L(""), TPoint(0, 0));
}
iRenderer->Gc()->DiscardFont();
iRenderer->Flip(iDirectScreen);
// Keep the backlight on.
if (iSuspendScreenSaver) {
User::ResetInactivityTime();
}
// Suspend the current thread for a short while.
// Give some time to other threads and active objects.
User::After(0);
}
void CRenderer::SetDrawColor(TUint32 iColor)
{
if (iRenderer && iRenderer->Gc()) {
iRenderer->Gc()->SetPenColor(iColor);
iRenderer->Gc()->SetBrushColor(iColor);
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ESolidBrush);
TRAPD(err, iRenderer->SetCurrentColor(iColor));
if (err != KErrNone) {
return;
}
}
}
void CRenderer::SetClipRect(TInt aX, TInt aY, TInt aWidth, TInt aHeight)
{
if (iRenderer && iRenderer->Gc()) {
TRect viewportRect(aX, aY, aX + aWidth, aY + aHeight);
iRenderer->Gc()->SetClippingRect(viewportRect);
}
}
void CRenderer::UpdateFPS()
{
static TTime lastTime;
static TInt frameCount = 0;
TTime currentTime;
const TUint KOneSecond = 1000000; // 1s in ms.
currentTime.HomeTime();
++frameCount;
TTimeIntervalMicroSeconds timeDiff = currentTime.MicroSecondsFrom(lastTime);
if (timeDiff.Int64() >= KOneSecond) {
// Calculate FPS.
iFPS = frameCount;
// Reset frame count and last time.
frameCount = 0;
lastTime = currentTime;
}
}
void CRenderer::SuspendScreenSaver(TBool aSuspend)
{
iSuspendScreenSaver = aSuspend;
}
static SDL_Scancode ConvertScancode(int key)
{
SDL_Keycode keycode;
switch (key) {
case EStdKeyBackspace: // Clear key
keycode = SDLK_BACKSPACE;
break;
case 0x31: // 1
keycode = SDLK_1;
break;
case 0x32: // 2
keycode = SDLK_2;
break;
case 0x33: // 3
keycode = SDLK_3;
break;
case 0x34: // 4
keycode = SDLK_4;
break;
case 0x35: // 5
keycode = SDLK_5;
break;
case 0x36: // 6
keycode = SDLK_6;
break;
case 0x37: // 7
keycode = SDLK_7;
break;
case 0x38: // 8
keycode = SDLK_8;
break;
case 0x39: // 9
keycode = SDLK_9;
break;
case 0x30: // 0
keycode = SDLK_0;
break;
case 0x2a: // Asterisk
keycode = SDLK_ASTERISK;
break;
case EStdKeyHash: // Hash
keycode = SDLK_HASH;
break;
case EStdKeyDevice0: // Left softkey
keycode = SDLK_SOFTLEFT;
break;
case EStdKeyDevice1: // Right softkey
keycode = SDLK_SOFTRIGHT;
break;
case EStdKeyApplication0: // Call softkey
keycode = SDLK_CALL;
break;
case EStdKeyApplication1: // End call softkey
keycode = SDLK_ENDCALL;
break;
case EStdKeyDevice3: // Middle softkey
keycode = SDLK_SELECT;
break;
case EStdKeyUpArrow: // Up arrow
keycode = SDLK_UP;
break;
case EStdKeyDownArrow: // Down arrow
keycode = SDLK_DOWN;
break;
case EStdKeyLeftArrow: // Left arrow
keycode = SDLK_LEFT;
break;
case EStdKeyRightArrow: // Right arrow
keycode = SDLK_RIGHT;
break;
default:
keycode = SDLK_UNKNOWN;
break;
}
return SDL_GetScancodeFromKey(keycode, NULL);
}
void CRenderer::HandleEvent(const TWsEvent &aWsEvent)
{
Uint64 timestamp;
switch (aWsEvent.Type()) {
case EEventKeyDown: /* Key events */
timestamp = SDL_GetPerformanceCounter();
SDL_SendKeyboardKey(timestamp, 1, aWsEvent.Key()->iCode, ConvertScancode(aWsEvent.Key()->iScanCode), true);
if (aWsEvent.Key()->iScanCode == EStdKeyHash) {
if (iShowFPS) {
iShowFPS = EFalse;
} else {
iShowFPS = ETrue;
}
}
break;
case EEventKeyUp: /* Key events */
timestamp = SDL_GetPerformanceCounter();
SDL_SendKeyboardKey(timestamp, 1, aWsEvent.Key()->iCode, ConvertScancode(aWsEvent.Key()->iScanCode), false);
case EEventFocusGained:
DisableKeyBlocking();
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
iIsFocused = ETrue;
}
Flip();
break;
case EEventFocusLost:
{
if (iDirectScreen->IsActive()) {
iDirectScreen->Cancel();
}
iIsFocused = EFalse;
break;
}
default:
break;
}
}
void CRenderer::DisableKeyBlocking()
{
TRawEvent aEvent;
aEvent.Set((TRawEvent::TType) /*EDisableKeyBlock*/ 51);
iWsSession.SimulateRawEvent(aEvent);
}
void CRenderer::PumpEvents()
{
while (iWsEventStatus != KRequestPending) {
iWsSession.GetEvent(iWsEvent);
HandleEvent(iWsEvent);
iWsEventStatus = KRequestPending;
iWsSession.EventReady(&iWsEventStatus);
}
}
#endif // SDL_VIDEO_RENDER_NGAGE

View file

@ -0,0 +1,105 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ngage_c_h
#define ngage_video_render_ngage_c_h
#define NGAGE_SCREEN_WIDTH 176
#define NGAGE_SCREEN_HEIGHT 208
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysrender.h"
typedef struct NGAGE_RendererData
{
SDL_Rect *viewport;
} NGAGE_RendererData;
typedef struct NGAGE_Vertex
{
int x;
int y;
struct
{
Uint8 a;
Uint8 r;
Uint8 g;
Uint8 b;
} color;
} NGAGE_Vertex;
typedef struct CFbsBitmap CFbsBitmap;
typedef struct NGAGE_TextureData
{
CFbsBitmap *bitmap;
SDL_Surface *surface;
} NGAGE_TextureData;
typedef struct NGAGE_CopyExData
{
SDL_Rect srcrect;
SDL_Rect dstrect;
int angle;
struct
{
int x;
int y;
} center;
SDL_FlipMode flip;
int scale_x;
int scale_y;
} NGAGE_CopyExData;
void NGAGE_Clear(const Uint32 color);
Uint32 NGAGE_ConvertColor(float r, float g, float b, float a, float color_scale);
bool NGAGE_Copy(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcrect, SDL_Rect *dstrect);
bool NGAGE_CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, NGAGE_CopyExData *copydata);
bool NGAGE_CreateTextureData(NGAGE_TextureData *data, const int width, const int height);
void NGAGE_DestroyTextureData(NGAGE_TextureData *data);
void NGAGE_DrawLines(NGAGE_Vertex *verts, const int count);
void NGAGE_DrawPoints(NGAGE_Vertex *verts, const int count);
void NGAGE_FillRects(NGAGE_Vertex *verts, const int count);
void NGAGE_Flip(void);
void NGAGE_SetClipRect(const SDL_Rect *rect);
void NGAGE_SetDrawColor(const Uint32 color);
void NGAGE_PumpEventsInternal(void);
void NGAGE_SuspendScreenSaverInternal(bool suspend);
#ifdef __cplusplus
}
#endif
#endif // ngage_video_render_ngage_c_h

View file

@ -0,0 +1,91 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ngage_c_hpp
#define ngage_video_render_ngage_c_hpp
#include "SDL_render_ngage_c.h"
#include <NRenderer.h>
#include <e32std.h>
#include <w32std.h>
class CRenderer : public MDirectScreenAccess
{
public:
static CRenderer *NewL();
virtual ~CRenderer();
// Rendering functions.
void Clear(TUint32 iColor);
bool Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect);
bool CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE_CopyExData *copydata);
bool CreateTextureData(NGAGE_TextureData *aTextureData, const TInt aWidth, const TInt aHeight);
void DrawLines(NGAGE_Vertex *aVerts, const TInt aCount);
void DrawPoints(NGAGE_Vertex *aVerts, const TInt aCount);
void FillRects(NGAGE_Vertex *aVerts, const TInt aCount);
void Flip();
void SetDrawColor(TUint32 iColor);
void SetClipRect(TInt aX, TInt aY, TInt aWidth, TInt aHeight);
void UpdateFPS();
void SuspendScreenSaver(TBool aSuspend);
// Event handling.
void DisableKeyBlocking();
void HandleEvent(const TWsEvent &aWsEvent);
void PumpEvents();
private:
CRenderer();
void ConstructL(void);
// BackBuffer.
CNRenderer *iRenderer;
// Direct screen access.
CDirectScreenAccess *iDirectScreen;
CFbsBitGc *iScreenGc;
TBool iIsFocused;
// Window server session.
RWsSession iWsSession;
RWindowGroup iWsWindowGroup;
TInt iWsWindowGroupID;
RWindow iWsWindow;
CWsScreenDevice *iWsScreen;
// Event handling.
TRequestStatus iWsEventStatus;
TWsEvent iWsEvent;
// MDirectScreenAccess functions.
void Restart(RDirectScreenAccess::TTerminationReasons aReason);
void AbortNow(RDirectScreenAccess::TTerminationReasons aReason);
// Frame per second.
TBool iShowFPS;
TUint iFPS;
const CFont *iFont;
// Screen saver.
TBool iSuspendScreenSaver;
};
#endif // ngage_video_render_ngage_c_hpp

View file

@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <3dtypes.h>
#include "SDL_render_ops.hpp"
void ApplyColorMod(void *dest, void *source, int pitch, int width, int height, SDL_FColor color)
{
TUint16 *src_pixels = static_cast<TUint16 *>(source);
TUint16 *dst_pixels = static_cast<TUint16 *>(dest);
TFixed rf = Real2Fix(color.r);
TFixed gf = Real2Fix(color.g);
TFixed bf = Real2Fix(color.b);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
TUint16 pixel = src_pixels[y * pitch / 2 + x];
TUint8 r = (pixel & 0xF800) >> 8;
TUint8 g = (pixel & 0x07E0) >> 3;
TUint8 b = (pixel & 0x001F) << 3;
r = FixMul(r, rf);
g = FixMul(g, gf);
b = FixMul(b, bf);
dst_pixels[y * pitch / 2 + x] = (r << 8) | (g << 3) | (b >> 3);
}
}
}
void ApplyFlip(void* dest, void* source, int pitch, int width, int height, SDL_FlipMode flip)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
int src_x = x;
int src_y = y;
if (flip & SDL_FLIP_HORIZONTAL)
{
src_x = width - 1 - x;
}
if (flip & SDL_FLIP_VERTICAL)
{
src_y = height - 1 - y;
}
dst_pixels[y * pitch / 2 + x] = src_pixels[src_y * pitch / 2 + src_x];
}
}
}
void ApplyRotation(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed angle)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
TFixed cos_angle = 0;
TFixed sin_angle = 0;
if (angle != 0)
{
FixSinCos(angle, sin_angle, cos_angle);
}
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Translate point to origin.
TFixed translated_x = Int2Fix(x) - center_x;
TFixed translated_y = Int2Fix(y) - center_y;
// Rotate point (clockwise).
TFixed rotated_x = FixMul(translated_x, cos_angle) + FixMul(translated_y, sin_angle);
TFixed rotated_y = FixMul(translated_y, cos_angle) - FixMul(translated_x, sin_angle);
// Translate point back.
int final_x = Fix2Int(rotated_x + center_x);
int final_y = Fix2Int(rotated_y + center_y);
// Check bounds.
if (final_x >= 0 && final_x < width && final_y >= 0 && final_y < height)
{
dst_pixels[y * pitch / 2 + x] = src_pixels[final_y * pitch / 2 + final_x];
}
else
{
dst_pixels[y * pitch / 2 + x] = 0;
}
}
}
}
void ApplyScale(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed scale_x, TFixed scale_y)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Translate point to origin.
TFixed translated_x = Int2Fix(x) - center_x;
TFixed translated_y = Int2Fix(y) - center_y;
// Scale point.
TFixed scaled_x = FixDiv(translated_x, scale_x);
TFixed scaled_y = FixDiv(translated_y, scale_y);
// Translate point back.
int final_x = Fix2Int(scaled_x + center_x);
int final_y = Fix2Int(scaled_y + center_y);
// Check bounds.
if (final_x >= 0 && final_x < width && final_y >= 0 && final_y < height)
{
dst_pixels[y * pitch / 2 + x] = src_pixels[final_y * pitch / 2 + final_x];
}
else
{
dst_pixels[y * pitch / 2 + x] = 0;
}
}
}
}

View file

@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ops_hpp
#define ngage_video_render_ops_hpp
#include <3dtypes.h>
void ApplyColorMod(void* dest, void* source, int pitch, int width, int height, SDL_FColor color);
void ApplyFlip(void* dest, void* source, int pitch, int width, int height, SDL_FlipMode flip);
void ApplyRotation(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed angle);
void ApplyScale(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed scale_x, TFixed scale_y);
#endif // ngage_video_render_ops_hpp

View file

@ -34,6 +34,8 @@
#if defined(__SIZEOF_WCHAR_T__)
#define SDL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__
#elif defined(SDL_PLATFORM_NGAGE)
#define SDL_SIZEOF_WCHAR_T 2
#elif defined(SDL_PLATFORM_WINDOWS)
#define SDL_SIZEOF_WCHAR_T 2
#else // assume everything else is UTF-32 (add more tests if compiler-assert fails below!)

View file

@ -20,11 +20,12 @@
*/
// Do our best to make sure va_copy is working
#if defined(_MSC_VER) && _MSC_VER <= 1800
#if (defined(_MSC_VER) && _MSC_VER <= 1800) || defined(__SYMBIAN32__)
// Visual Studio 2013 tries to link with _vacopy in the C runtime. Newer versions do an inline assignment
#undef va_copy
#define va_copy(dst, src) dst = src
#elif defined(__GNUC__) && (__GNUC__ < 3)
#define va_copy(dst, src) __va_copy(dst, src)
#endif

View file

@ -0,0 +1,184 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_TIME_NGAGE
#include <bautils.h>
#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
#ifdef __cplusplus
extern "C" {
#endif
static TTime UnixEpoch();
void SDL_GetSystemTimeLocalePreferences(SDL_DateFormat *df, SDL_TimeFormat *tf)
{
TLanguage language = User::Language();
switch (language) {
case ELangFrench:
case ELangSwissFrench:
case ELangBelgianFrench:
case ELangInternationalFrench:
case ELangGerman:
case ELangSwissGerman:
case ELangAustrian:
case ELangSpanish:
case ELangInternationalSpanish:
case ELangLatinAmericanSpanish:
case ELangItalian:
case ELangSwissItalian:
case ELangSwedish:
case ELangFinlandSwedish:
case ELangDanish:
case ELangNorwegian:
case ELangNorwegianNynorsk:
case ELangFinnish:
case ELangPortuguese:
case ELangBrazilianPortuguese:
case ELangTurkish:
case ELangCyprusTurkish:
case ELangIcelandic:
case ELangRussian:
case ELangHungarian:
case ELangDutch:
case ELangBelgianFlemish:
case ELangCzech:
case ELangSlovak:
case ELangPolish:
case ELangSlovenian:
case ELangTaiwanChinese:
case ELangHongKongChinese:
case ELangPrcChinese:
case ELangJapanese:
case ELangThai:
case ELangAfrikaans:
case ELangAlbanian:
case ELangAmharic:
case ELangArabic:
case ELangArmenian:
case ELangAzerbaijani:
case ELangBelarussian:
case ELangBengali:
case ELangBulgarian:
case ELangBurmese:
case ELangCatalan:
case ELangCroatian:
case ELangEstonian:
case ELangFarsi:
case ELangScotsGaelic:
case ELangGeorgian:
case ELangGreek:
case ELangCyprusGreek:
case ELangGujarati:
case ELangHebrew:
case ELangHindi:
case ELangIndonesian:
case ELangIrish:
case ELangKannada:
case ELangKazakh:
case ELangKhmer:
case ELangKorean:
case ELangLao:
case ELangLatvian:
case ELangLithuanian:
case ELangMacedonian:
case ELangMalay:
case ELangMalayalam:
case ELangMarathi:
case ELangMoldavian:
case ELangMongolian:
case ELangPunjabi:
case ELangRomanian:
case ELangSerbian:
case ELangSinhalese:
case ELangSomali:
case ELangSwahili:
case ELangTajik:
case ELangTamil:
case ELangTelugu:
case ELangTibetan:
case ELangTigrinya:
case ELangTurkmen:
case ELangUkrainian:
case ELangUrdu:
case ELangUzbek:
case ELangVietnamese:
case ELangWelsh:
case ELangZulu:
*df = SDL_DATE_FORMAT_DDMMYYYY;
*tf = SDL_TIME_FORMAT_24HR;
break;
case ELangAmerican:
case ELangCanadianEnglish:
case ELangInternationalEnglish:
case ELangSouthAfricanEnglish:
case ELangAustralian:
case ELangNewZealand:
case ELangCanadianFrench:
*df = SDL_DATE_FORMAT_MMDDYYYY;
*tf = SDL_TIME_FORMAT_12HR;
break;
case ELangEnglish:
case ELangOther:
default:
*df = SDL_DATE_FORMAT_DDMMYYYY;
*tf = SDL_TIME_FORMAT_24HR;
break;
}
}
bool SDL_GetCurrentTime(SDL_Time *ticks)
{
if (!ticks) {
return SDL_InvalidParamError("ticks");
}
TTime now;
now.UniversalTime();
TTimeIntervalMicroSeconds interval = now.MicroSecondsFrom(UnixEpoch());
TInt64 interval_ns = interval.Int64() * 1000;
Uint32 ns_low = interval_ns.Low();
Uint32 ns_high = interval_ns.High();
*ticks = ((Uint64)ns_high << 32) | ns_low;
return true;
}
static TTime UnixEpoch()
{
_LIT(KUnixEpoch, "19700101:000000.000000");
TTime epochTime;
epochTime.Set(KUnixEpoch);
return epochTime;
}
#ifdef __cplusplus
}
#endif
#endif // SDL_TIME_NGAGE

View file

@ -0,0 +1,47 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <e32hal.h>
#include <e32std.h>
#ifdef __cplusplus
extern "C" {
#endif
Uint64 SDL_GetPerformanceCounter(void)
{
return (Uint64)User::TickCount();
}
Uint64 SDL_GetPerformanceFrequency(void)
{
return (Uint64)1000000u;
}
void SDL_SYS_DelayNS(Uint64 ns)
{
User::After(SDL_NS_TO_US(ns));
}
#ifdef __cplusplus
}
#endif

View file

@ -530,6 +530,7 @@ extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap VITA_bootstrap;
extern VideoBootStrap RISCOS_bootstrap;
extern VideoBootStrap N3DS_bootstrap;
extern VideoBootStrap NGAGE_bootstrap;
extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap DUMMY_bootstrap;

View file

@ -119,6 +119,9 @@ static VideoBootStrap *bootstrap[] = {
#ifdef SDL_VIDEO_DRIVER_N3DS
&N3DS_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_NGAGE
&NGAGE_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_KMSDRM
&KMSDRM_bootstrap,
#endif

View file

@ -0,0 +1,175 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_sysvideo.h"
#ifdef SDL_VIDEO_DRIVER_NGAGE
#include "SDL_ngagevideo.h"
#define NGAGE_VIDEO_DRIVER_NAME "N-Gage"
static void NGAGE_DeleteDevice(SDL_VideoDevice *device);
static bool NGAGE_VideoInit(SDL_VideoDevice *device);
static void NGAGE_VideoQuit(SDL_VideoDevice *device);
static bool NGAGE_GetDisplayBounds(SDL_VideoDevice *device, SDL_VideoDisplay *display, SDL_Rect *rect);
static bool NGAGE_GetDisplayModes(SDL_VideoDevice *device, SDL_VideoDisplay *display);
static void NGAGE_PumpEvents(SDL_VideoDevice *device);
static bool NGAGE_SuspendScreenSaver(SDL_VideoDevice *device);
static SDL_VideoDevice *NGAGE_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *phdata;
// Initialize all variables that we clean on shutdown.
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
SDL_OutOfMemory();
return (SDL_VideoDevice *)0;
}
// Initialize internal N-Gage specific data.
phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
if (!phdata) {
SDL_OutOfMemory();
SDL_free(device);
return (SDL_VideoDevice *)0;
}
device->internal = phdata;
device->name = "Nokia N-Gage";
device->VideoInit = NGAGE_VideoInit;
device->VideoQuit = NGAGE_VideoQuit;
device->GetDisplayBounds = NGAGE_GetDisplayBounds;
device->GetDisplayModes = NGAGE_GetDisplayModes;
device->PumpEvents = NGAGE_PumpEvents;
device->SuspendScreenSaver = NGAGE_SuspendScreenSaver;
device->free = NGAGE_DeleteDevice;
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
return device;
}
VideoBootStrap NGAGE_bootstrap = {
NGAGE_VIDEO_DRIVER_NAME,
"N-Gage Video Driver",
NGAGE_CreateDevice,
0
};
static void NGAGE_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device->internal);
SDL_free(device);
}
static bool NGAGE_VideoInit(SDL_VideoDevice *device)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
if (!phdata) {
return false;
}
SDL_zero(phdata->mode);
SDL_zero(phdata->display);
phdata->mode.w = 176;
phdata->mode.h = 208;
phdata->mode.refresh_rate = 60.0f;
phdata->mode.format = SDL_PIXELFORMAT_ARGB4444;
phdata->display.name = "N-Gage";
phdata->display.desktop_mode = phdata->mode;
if (SDL_AddVideoDisplay(&phdata->display, false) == 0) {
return false;
}
return true;
}
static void NGAGE_VideoQuit(SDL_VideoDevice *device)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
if (phdata) {
SDL_zero(phdata->mode);
SDL_zero(phdata->display);
}
}
static bool NGAGE_GetDisplayBounds(SDL_VideoDevice *device, SDL_VideoDisplay *display, SDL_Rect *rect)
{
if (!display) {
return false;
}
rect->x = 0;
rect->y = 0;
rect->w = display->current_mode->w;
rect->h = display->current_mode->h;
return true;
}
static bool NGAGE_GetDisplayModes(SDL_VideoDevice *device, SDL_VideoDisplay *display)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
SDL_DisplayMode mode;
SDL_zero(mode);
mode.w = phdata->mode.w;
mode.h = phdata->mode.h;
mode.refresh_rate = phdata->mode.refresh_rate;
mode.format = phdata->mode.format;
if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
return false;
}
return true;
}
#include "../../render/ngage/SDL_render_ngage_c.h"
static void NGAGE_PumpEvents(SDL_VideoDevice *device)
{
NGAGE_PumpEventsInternal();
}
static bool NGAGE_SuspendScreenSaver(SDL_VideoDevice *device)
{
NGAGE_SuspendScreenSaverInternal(device->suspend_screensaver);
return true;
}
#endif // SDL_VIDEO_DRIVER_NGAGE

View file

@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_NGAGE
#include "../SDL_sysvideo.h"
#ifndef _SDL_ngagevideo_h
#define _SDL_ngagevideo_h
typedef struct SDL_VideoData
{
SDL_DisplayMode mode;
SDL_VideoDisplay display;
} SDL_VideoData;
#endif // _SDL_ngagevideo_h
#endif // SDL_VIDEO_DRIVER_NGAGE

View file

@ -32,8 +32,6 @@ if(NOT (MSVC AND SDL_CPU_ARM64))
find_package(OpenGL)
endif()
set(SDL_TEST_EXECUTABLES)
add_library(sdltests_utils OBJECT
testutils.c
)
@ -101,7 +99,7 @@ define_property(TARGET PROPERTY SDL_NONINTERACTIVE BRIEF_DOCS "If true, target i
define_property(TARGET PROPERTY SDL_NONINTERACTIVE_ARGUMENTS BRIEF_DOCS "Argument(s) to run executable in non-interactive mode." FULL_DOCS "Argument(s) to run executable in non-interactive mode.")
define_property(TARGET PROPERTY SDL_NONINTERACTIVE_TIMEOUT BRIEF_DOCS "Timeout for noninteractive executable." FULL_DOCS "Timeout for noninteractive executable.")
macro(add_sdl_test_executable TARGET)
function(add_sdl_test_executable TARGET)
cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;THREADS;NO_C90;MAIN_CALLBACKS;NOTRACKMEM" "" "DEPENDS;DISABLE_THREADS_ARGS;NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;INSTALLED_ARGS;SOURCES" ${ARGN})
if(AST_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown argument(s): ${AST_UNPARSED_ARGUMENTS}")
@ -133,7 +131,8 @@ macro(add_sdl_test_executable TARGET)
add_dependencies(${TARGET} ${AST_DEPENDS})
endif()
list(APPEND SDL_TEST_EXECUTABLES ${TARGET})
set_propertY(TARGET ${TARGET} PROPERTY SDL_INSTALL "1")
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY SDL_TEST_EXECUTABLES "${TARGET}")
set_property(TARGET ${TARGET} PROPERTY SDL_NOTRACKMEM ${AST_NOTRACKMEM})
if(AST_NONINTERACTIVE)
set_property(TARGET ${TARGET} PROPERTY SDL_NONINTERACTIVE 1)
@ -192,6 +191,14 @@ macro(add_sdl_test_executable TARGET)
target_link_options(${TARGET} PRIVATE "SHELL:--pre-js ${CMAKE_CURRENT_SOURCE_DIR}/emscripten/pre.js")
target_link_options(${TARGET} PRIVATE "-sEXIT_RUNTIME=1")
set_property(TARGET ${TARGET} APPEND PROPERTY LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/emscripten/pre.js")
elseif(NGAGE)
string(MD5 TARGET_MD5 "${TARGET}")
string(SUBSTRING "${TARGET_MD5}" 0 8 TARGET_MD5_8)
target_link_options(${TARGET} PRIVATE "SHELL:-s UID3=0x${TARGET_MD5_8}")
if(NOT AST_MAIN_CALLBACKS)
set_property(TARGET ${TARGET} PROPERTY "EXCLUDE_FROM_ALL" "1")
set_propertY(TARGET ${TARGET} PROPERTY SDL_INSTALL "0")
endif()
endif()
if(OPENGL_FOUND)
@ -200,10 +207,10 @@ macro(add_sdl_test_executable TARGET)
# FIXME: only add "${SDL3_BINARY_DIR}/include-config-$<LOWER_CASE:$<CONFIG>>" + include paths of external dependencies
target_include_directories(${TARGET} PRIVATE "$<TARGET_PROPERTY:SDL3::${sdl_name_component},INCLUDE_DIRECTORIES>")
endmacro()
endfunction()
check_include_file(signal.h HAVE_SIGNAL_H)
if(HAVE_SIGNAL_H)
check_include_file(signal.h LIBC_HAS_SIGNAL_H)
if(LIBC_HAS_SIGNAL_H)
add_definitions(-DHAVE_SIGNAL_H)
endif()
@ -425,6 +432,8 @@ add_sdl_test_executable(testprocess
add_sdl_test_executable(childprocess SOURCES childprocess.c)
add_dependencies(testprocess childprocess)
get_property(SDL_TEST_EXECUTABLES DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY SDL_TEST_EXECUTABLES)
if (HAVE_WAYLAND)
# Set the GENERATED property on the protocol file, since it is first created at build time
set_property(SOURCE ${SDL3_BINARY_DIR}/wayland-generated-protocols/xdg-shell-protocol.c PROPERTY GENERATED 1)
@ -654,10 +663,15 @@ if(SDL_INSTALL_TESTS)
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL3
)
else()
install(
TARGETS ${SDL_TEST_EXECUTABLES}
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL3
)
foreach(test IN LISTS SDL_TEST_EXECUTABLES)
get_property(install_target TARGET ${test} PROPERTY "SDL_INSTALL")
if(install_target)
install(
TARGETS ${test}
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL3
)
endif()
endforeach()
endif()
if(MSVC)
foreach(test IN LISTS SDL_TEST_EXECUTABLES)