Merge commit '8821e99ab51434f24f3e64dd7ec4cfeeb761a018' as 'external/SDL'

This commit is contained in:
SimoneN64
2024-09-04 22:32:48 +02:00
1913 changed files with 947421 additions and 0 deletions

441
external/SDL/examples/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,441 @@
#
# CMake script for building the SDL examples
#
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake")
include(CheckIncludeFile)
include(CheckStructHasMember)
include(CMakePushCheckState)
include(sdlcompilers)
if(SDL_EXAMPLES_LINK_SHARED)
set(sdl_name_component SDL3-shared)
else()
set(sdl_name_component SDL3-static)
endif()
set(HAVE_EXAMPLES_LINK_SHARED "${SDL_EXAMPLES_LINK_SHARED}" PARENT_SCOPE)
# CMake incorrectly detects opengl32.lib being present on MSVC ARM64
if(NOT (MSVC AND SDL_CPU_ARM64))
# Prefer GLVND, if present
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL)
endif()
if(WINDOWS_STORE)
cmake_minimum_required(VERSION 3.19)
# CMP0112: Target file component generator expressions do not add target dependencies.
cmake_policy(SET CMP0112 NEW)
endif()
set(SDL_EXAMPLE_EXECUTABLES)
if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(example_bin_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
if(NOT IS_ABSOLUTE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
set(example_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif()
else()
set(example_bin_dir "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT CMAKE_VERSION VERSION_LESS 3.20)
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
set(example_bin_dir "${example_bin_dir}$<$<BOOL:${is_multi_config}>:/$<CONFIG>>")
endif()
file(GLOB RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/*.bmp ${CMAKE_CURRENT_SOURCE_DIR}/../test/*.wav ${CMAKE_CURRENT_SOURCE_DIR}/../test/*.hex)
set(RESOURCE_FILE_NAMES)
set(RESOURCE_FILES_BINDIR)
foreach(resource_file IN LISTS RESOURCE_FILES)
get_filename_component(res_file_name ${resource_file} NAME)
list(APPEND RESOURCE_FILE_NAMES "${res_file_name}")
set(resource_file_bindir "${example_bin_dir}/${res_file_name}")
add_custom_command(OUTPUT "${resource_file_bindir}"
COMMAND "${CMAKE_COMMAND}" -E copy "${resource_file}" "${resource_file_bindir}"
DEPENDS "${resource_file}"
)
list(APPEND RESOURCE_FILES_BINDIR "${resource_file_bindir}")
endforeach()
add_custom_target(copy-sdl-example-resources
DEPENDS "${RESOURCE_FILES_BINDIR}"
)
if(WINDOWS_STORE)
add_library(sdl_example_main_callbacks_uwp OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/../test/main.cpp)
target_link_libraries(sdl_example_main_callbacks_uwp PRIVATE SDL3::Headers)
target_compile_options(sdl_example_main_callbacks_uwp PRIVATE "/ZW")
target_compile_definitions(sdl_example_main_callbacks_uwp PRIVATE "SDL_MAIN_USE_CALLBACKS")
set_source_files_properties(${RESOURCE_FILES} PROPERTIES VS_DEPLOYENT_LOCATION "Assets")
endif()
macro(add_sdl_example_executable TARGET)
cmake_parse_arguments(AST "BUILD_DEPENDENT" "" "SOURCES;DATAFILES" ${ARGN})
if(AST_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown argument(s): ${AST_UNPARSED_ARGUMENTS}")
endif()
if(NOT AST_SOURCES)
message(FATAL_ERROR "add_sdl_example_executable needs at least one source")
endif()
set(EXTRA_SOURCES "")
if(WINDOWS_STORE)
set(uwp_bindir "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.dir")
if(NOT IS_DIRECTORY "${uwp_bindir}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${uwp_bindir}")
endif()
string(REGEX REPLACE "[_]" "" SAFE_TARGET "${TARGET}")
file(GENERATE OUTPUT "${uwp_bindir}/${TARGET}.appxmanifest"
INPUT "${CMAKE_CURRENT_SOURCE_DIR}/../test/uwp/Package.appxmanifest.in"
TARGET "${TARGET}"
)
set_property(SOURCE "${uwp_bindir}/${TARGET}.appxmanifest" PROPERTY VS_DEPLOYMENT_CONTENT 1)
list(APPEND EXTRA_SOURCES "$<TARGET_OBJECTS:sdl_example_main_callbacks_uwp>")
list(APPEND EXTRA_SOURCES
"${uwp_bindir}/${TARGET}.appxmanifest"
"${CMAKE_CURRENT_SOURCE_DIR}/../test/uwp/logo-50x50.png"
"${CMAKE_CURRENT_SOURCE_DIR}/../test/uwp/square-44x44.png"
"${CMAKE_CURRENT_SOURCE_DIR}/../test/uwp/square-150x150.png"
"${CMAKE_CURRENT_SOURCE_DIR}/../test/uwp/splash-620x300.png"
)
endif()
if(AST_DATAFILES)
list(APPEND EXTRA_SOURCES ${DATAFILES})
endif()
if(ANDROID)
add_library(${TARGET} SHARED ${AST_SOURCES} ${EXTRA_SOURCES})
else()
add_executable(${TARGET} ${AST_SOURCES} ${EXTRA_SOURCES})
endif()
SDL_AddCommonCompilerFlags(${TARGET})
target_include_directories(${TARGET} PRIVATE "${SDL3_SOURCE_DIR}/src/video/khronos")
target_link_libraries(${TARGET} PRIVATE SDL3::${sdl_name_component})
list(APPEND SDL_EXAMPLE_EXECUTABLES ${TARGET})
if(AST_DATAFILES)
if(PSP OR PS2)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E make_directory $<TARGET_FILE_DIR:${TARGET}>/sdl-${TARGET}
COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${AST_DATAFILES} $<TARGET_FILE_DIR:${TARGET}>/sdl-${TARGET}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
elseif(WINDOWS_STORE)
# MSVC does build the dependent targets (or POST_BUILD commands) when building an application
# after starting to debug. By copying the resources in a custom target, the files can be copied afterwards.
# FIXME: find out proper way to add assets to UWP package
cmake_minimum_required(VERSION 3.19)
add_custom_target(zzz-resources-copy-${TARGET}
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${TARGET}>/AppX"
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${AST_DATAFILES} "$<TARGET_FILE_DIR:${TARGET}>/AppX"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
add_dependencies(${TARGET} zzz-resources-copy-${TARGET})
else()
add_dependencies(${TARGET} copy-sdl-example-resources)
endif()
if(APPLE)
# Make sure resource files get installed into macOS/iOS .app bundles.
set_target_properties(${TARGET} PROPERTIES RESOURCE "${AST_DATAFILES}")
endif()
if(EMSCRIPTEN)
foreach(res IN LISTS AST_DATAFILES)
get_filename_component(res_name "${res}" NAME)
target_link_options(${TARGET} PRIVATE "SHELL:--embed-file ${res}@${res_name}")
endforeach()
endif()
set_property(TARGET ${TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES "$<TARGET_FILE_DIR:${TARGET}>/$<JOIN:${AST_DATAFILES},$<SEMICOLON>$<TARGET_FILE_DIR:${TARGET}>/>")
endif()
if(WINDOWS)
# CET support was added in VS 16.7
if(MSVC_VERSION GREATER 1926 AND CMAKE_GENERATOR_PLATFORM MATCHES "Win32|x64")
set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -CETCOMPAT")
endif()
elseif(PSP)
target_link_libraries(${TARGET} PRIVATE GL)
endif()
if(WINDOWS_STORE)
target_compile_definitions(${TARGET} PRIVATE "SDL_MAIN_NOIMPL")
set_property(TARGET ${TARGET} PROPERTY WIN32_EXECUTABLE TRUE)
set_property(TARGET ${TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY "${uwp_bindir}")
target_link_options(${TARGET} PRIVATE
-nodefaultlib:vccorlib$<$<CONFIG:Debug>:d>
-nodefaultlib:msvcrt$<$<CONFIG:Debug>:d>
vccorlib$<$<CONFIG:Debug>:d>.lib
msvcrt$<$<CONFIG:Debug>:d>.lib
)
endif()
if(EMSCRIPTEN)
set_property(TARGET ${TARGET} PROPERTY SUFFIX ".html")
endif()
if(OPENGL_FOUND)
target_compile_definitions(${TARGET} PRIVATE HAVE_OPENGL)
endif()
# 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()
add_sdl_example_executable(renderer-clear SOURCES renderer/01-clear/renderer-clear.c)
add_sdl_example_executable(renderer-primitives SOURCES renderer/02-primitives/renderer-primitives.c)
add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c)
add_sdl_example_executable(pen-drawing-lines SOURCES pen/01-drawing-lines/drawing-lines.c)
add_sdl_example_executable(game-snake SOURCES game/01-snake/snake.c)
if(PSP)
# Build EBOOT files if building for PSP
foreach(APP ${SDL_EXAMPLE_EXECUTABLES})
create_pbp_file(
TARGET ${APP}
TITLE SDL-${APP}
ICON_PATH NULL
BACKGROUND_PATH NULL
PREVIEW_PATH NULL
)
add_custom_command(
TARGET ${APP} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
$<TARGET_FILE_DIR:${ARG_TARGET}>/sdl-${APP}
)
add_custom_command(
TARGET ${APP} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rename
$<TARGET_FILE_DIR:${ARG_TARGET}>/EBOOT.PBP
$<TARGET_FILE_DIR:${ARG_TARGET}>/sdl-${APP}/EBOOT.PBP
)
if(BUILD_PRX)
add_custom_command(
TARGET ${APP} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE_DIR:${ARG_TARGET}>/${APP}
$<TARGET_FILE_DIR:${ARG_TARGET}>/sdl-${APP}/${APP}
)
add_custom_command(
TARGET ${APP} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rename
$<TARGET_FILE_DIR:${ARG_TARGET}>/${APP}.prx
$<TARGET_FILE_DIR:${ARG_TARGET}>/sdl-${APP}/${APP}.prx
)
endif()
add_custom_command(
TARGET ${APP} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove
$<TARGET_FILE_DIR:${ARG_TARGET}>/PARAM.SFO
)
endforeach()
endif()
if(N3DS)
set(ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/romfs")
file(MAKE_DIRECTORY "${ROMFS_DIR}")
file(COPY ${RESOURCE_FILES} DESTINATION "${ROMFS_DIR}")
foreach(APP ${SDL_EXAMPLE_EXECUTABLES})
get_target_property(TARGET_BINARY_DIR ${APP} BINARY_DIR)
set(SMDH_FILE "${TARGET_BINARY_DIR}/${APP}.smdh")
ctr_generate_smdh("${SMDH_FILE}"
NAME "SDL-${APP}"
DESCRIPTION "SDL3 Test suite"
AUTHOR "SDL3 Contributors"
ICON "${CMAKE_CURRENT_SOURCE_DIR}/../test/n3ds/logo48x48.png"
)
ctr_create_3dsx(
${APP}
ROMFS "${ROMFS_DIR}"
SMDH "${SMDH_FILE}"
)
endforeach()
endif()
if(RISCOS)
set(SDL_EXAMPLE_EXECUTABLES_AIF)
foreach(APP ${SDL_EXAMPLE_EXECUTABLES})
set_property(TARGET ${APP} APPEND_STRING PROPERTY LINK_FLAGS " -static")
add_custom_command(
OUTPUT ${APP},ff8
COMMAND elf2aif ${APP} ${APP},ff8
DEPENDS ${APP}
)
add_custom_target(${APP}-aif ALL DEPENDS ${APP},ff8)
list(APPEND SDL_EXAMPLE_EXECUTABLES_AIF ${CMAKE_CURRENT_BINARY_DIR}/${APP},ff8)
endforeach()
endif()
# Set Apple App ID / Bundle ID. This is needed to launch apps on some Apple
# platforms (iOS, for example).
if(APPLE)
foreach(CURRENT_TARGET ${SDL_EXAMPLE_EXECUTABLES})
set_target_properties("${CURRENT_TARGET}" PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "org.libsdl.${CURRENT_TARGET}"
MACOSX_BUNDLE_BUNDLE_VERSION "${SDL3_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${SDL3_VERSION}"
)
endforeach()
endif()
if(SDL_INSTALL_EXAMPLES)
if(RISCOS)
install(
FILES ${SDL_EXAMPLE_EXECUTABLES_AIF}
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3
)
else()
install(
TARGETS ${SDL_EXAMPLE_EXECUTABLES}
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3
)
endif()
if(MSVC)
foreach(example IN LISTS SDL_EXAMPLE_EXECUTABLES)
SDL_install_pdb(${example} "${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3")
endforeach()
endif()
install(
FILES ${RESOURCE_FILES}
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-examples/SDL3
)
endif()
if(ANDROID AND TARGET SDL3::Jar)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/android")
find_package(SdlAndroid MODULE)
if(SdlAndroid_FOUND)
set(apks "")
set(packages "")
include(SdlAndroidFunctions)
sdl_create_android_debug_keystore(SDL_example-debug-keystore)
sdl_android_compile_resources(SDL_example-resources RESFOLDER ${CMAKE_CURRENT_SOURCE_DIR}/../test/android/res)
add_custom_target(sdl-example-apks)
foreach(EXAMPLE ${SDL_EXAMPLE_EXECUTABLES})
set(ANDROID_MANIFEST_APP_NAME "${EXAMPLE}")
set(ANDROID_MANIFEST_LABEL "${EXAMPLE}")
set(ANDROID_MANIFEST_LIB_NAME "$<TARGET_FILE_BASE_NAME:${EXAMPLE}>")
set(ANDROID_MANIFEST_PACKAGE "org.libsdl.sdl.example.${EXAMPLE}")
set(generated_manifest_path "${CMAKE_CURRENT_BINARY_DIR}/android/${EXAMPLE}-src/AndroidManifest.xml")
string(REPLACE "." "/" JAVA_PACKAGE_DIR "${ANDROID_MANIFEST_PACKAGE}")
set(GENERATED_SRC_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/android/${EXAMPLE}-src")
set(GENERATED_RES_FOLDER "${GENERATED_SRC_FOLDER}/res")
set(JAVA_PACKAGE_DIR "${GENERATED_SRC_FOLDER}/${JAVA_PACKAGE_DIR}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test/android/cmake/SDLEntryTestActivity.java.cmake "${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test/android/cmake/SDLTestActivity.java.cmake "${JAVA_PACKAGE_DIR}/SDLTestActivity.java" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test/android/cmake/res/values/strings.xml.cmake android/res/values/strings-${EXAMPLE}.xml @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test/android/cmake/res/xml/shortcuts.xml.cmake "${GENERATED_RES_FOLDER}/xml/shortcuts.xml" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../test/android/cmake/AndroidManifest.xml.cmake "${generated_manifest_path}" @ONLY)
file(GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/android/${EXAMPLE}-$<CONFIG>/res/values/strings.xml"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/android/res/values/strings-${EXAMPLE}.xml"
)
sdl_android_compile_resources(${EXAMPLE}-resources
RESOURCES
"${CMAKE_CURRENT_BINARY_DIR}/android/${EXAMPLE}-$<CONFIG>/res/values/strings.xml"
"${GENERATED_RES_FOLDER}/xml/shortcuts.xml"
)
sdl_android_link_resources(${EXAMPLE}-apk-linked
MANIFEST "${generated_manifest_path}"
PACKAGE ${ANDROID_MANIFEST_PACKAGE}
RES_TARGETS SDL_example-resources ${EXAMPLE}-resources
TARGET_SDK_VERSION 31
)
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding;utf-8")
set(classes_path "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${EXAMPLE}-java.dir/classes")
# Some CMake versions have a slow `cmake -E make_directory` implementation
if(NOT IS_DIRECTORY "${classes_path}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}")
endif()
set(OUT_JAR "${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}.jar")
add_custom_command(
OUTPUT "${OUT_JAR}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${classes_path}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}"
COMMAND ${Java_JAVAC_EXECUTABLE}
-source 1.8 -target 1.8
-bootclasspath "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>"
"${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java"
"${JAVA_PACKAGE_DIR}/SDLTestActivity.java"
$<TARGET_PROPERTY:${EXAMPLE}-apk-linked,JAVA_R>
-cp "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>:${SDL_ANDROID_PLATFORM_ANDROID_JAR}"
-d "${classes_path}"
COMMAND ${Java_JAR_EXECUTABLE} cf "${OUT_JAR}" -C "${classes_path}" .
DEPENDS $<TARGET_PROPERTY:${EXAMPLE}-apk-linked,OUTPUTS> "$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>" "${JAVA_PACKAGE_DIR}/SDLTestActivity.java" "${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java"
)
add_custom_target(${EXAMPLE}-jar DEPENDS "${OUT_JAR}")
set_property(TARGET ${EXAMPLE}-jar PROPERTY OUTPUT "${OUT_JAR}")
set(dexworkdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${EXAMPLE}-dex.dir")
# Some CMake versions have a slow `cmake -E make_directory` implementation
if(NOT IS_DIRECTORY "${dexworkdir}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${dexworkdir}")
endif()
set(classes_dex_base_name "classes.dex")
set(classes_dex "${dexworkdir}/${classes_dex_base_name}")
add_custom_command(
OUTPUT "${classes_dex}"
COMMAND SdlAndroid::d8
$<TARGET_PROPERTY:${EXAMPLE}-jar,OUTPUT>
$<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>
--lib "${SDL_ANDROID_PLATFORM_ANDROID_JAR}"
--output "${dexworkdir}"
DEPENDS $<TARGET_PROPERTY:${EXAMPLE}-jar,OUTPUT> $<TARGET_PROPERTY:SDL3::Jar,JAR_FILE>
)
add_custom_target(${EXAMPLE}-dex DEPENDS "${classes_dex}")
set_property(TARGET ${EXAMPLE}-dex PROPERTY OUTPUT "${classes_dex}")
set_property(TARGET ${EXAMPLE}-dex PROPERTY OUTPUT_BASE_NAME "${classes_dex_base_name}")
sdl_add_to_apk_unaligned(${EXAMPLE}-unaligned-apk
APK_IN ${EXAMPLE}-apk-linked
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
ASSETS ${RESOURCE_FILES}
NATIVE_LIBS SDL3::SDL3-shared ${EXAMPLE}
DEX ${EXAMPLE}-dex
)
sdl_apk_align(${EXAMPLE}-aligned-apk ${EXAMPLE}-unaligned-apk
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
)
sdl_apk_sign(${EXAMPLE}-apk ${EXAMPLE}-aligned-apk
KEYSTORE SDL_example-debug-keystore
)
add_dependencies(sdl-example-apks ${EXAMPLE}-apk)
if(TARGET SdlAndroid::adb)
add_custom_target(install-${EXAMPLE}
COMMAND "${CMAKE_COMMAND}" -DACTION=install "-DAPKS=$<TARGET_PROPERTY:${EXAMPLE}-apk,OUTPUT>" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
DEPENDS "${EXAMPLE}-apk"
)
add_custom_target(start-${EXAMPLE}
COMMAND "${ADB_BIN}" shell am start-activity -S "${ANDROID_MANIFEST_PACKAGE}/.SDLTestActivity"
)
add_custom_target(build-install-start-${EXAMPLE}
COMMAND "${CMAKE_COMMAND}" -DACTION=build-install-run "-DEXECUTABLES=${EXAMPLE}" "-DBUILD_FOLDER=${CMAKE_BINARY_DIR}" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
)
endif()
list(APPEND packages "${ANDROID_MANIFEST_PACKAGE}")
list(APPEND install_targets install-${EXAMPLE})
endforeach()
if(TARGET SdlAndroid::adb)
add_custom_target(install-sdl-example-apks
DEPENDS ${install_targets}
VERBATIM
)
add_custom_target(uninstall-sdl-example-apks
COMMAND "${CMAKE_COMMAND}" "-DADB=$<TARGET_FILE:SdlAndroid::adb>" -DACTION=uninstall "-DPACKAGES=${packages}" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
VERBATIM
)
endif()
endif()
endif()

67
external/SDL/examples/README.md vendored Normal file
View File

@@ -0,0 +1,67 @@
# Examples
## What is this?
In here are a collection of standalone SDL application examples. Unless
otherwise stated, they should work on all supported platforms out of the box.
If they don't [please file a bug to let us know](https://github.com/libsdl-org/SDL/issues/new).
## What is this SDL_AppIterate thing?
SDL can optionally build apps as a collection of callbacks instead of the
usual program structure that starts and ends in a function called `main`.
The examples use this format for two reasons.
First, it allows the examples to work when built as web applications without
a pile of ugly `#ifdef`s, and all of these examples are published on the web
at [examples.libsdl.org](https://examples.libsdl.org/), so you can easily see
them in action.
Second, it's example code! The callbacks let us cleanly break the program up
into the four logical pieces most apps care about:
- Program startup
- Event handling
- What the program actually does in a single frame
- Program shutdown
A detailed technical explanation of these callbacks is in
docs/README-main-functions.md (or view that page on the web on
[the wiki](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)).
## I would like to build and run these examples myself.
When you build SDL with CMake, you can add `-DSDL_EXAMPLES=On` to the
CMake command line. When you build SDL, these examples will be built with it.
But most of these can just be built as a single .c file, as long as you point
your compiler at SDL3's headers and link against SDL.
## What is the license on the example code? Can I paste this into my project?
All code in the examples directory is considered public domain! You can do
anything you like with it, including copy/paste it into your closed-source
project, sell it, and pretend you wrote it yourself. We do not require you to
give us credit for this code (but we always appreciate if you do!).
This is only true for the examples directory. The rest of SDL falls under the
[zlib license](https://github.com/libsdl-org/SDL/blob/main/LICENSE.txt).
## What is template.html and highlight-plugin.lua in this directory?
This is what [examples.libsdl.org](https://examples.libsdl.org/) uses when
generating the web versions of these example programs. You can ignore this,
unless you are improving it, in which case we definitely would love to hear
from you!
## What is template.c in this directory?
If writing new examples, this is the skeleton code we start from, to keep
everything consistent. You can ignore it.

View File

@@ -0,0 +1,5 @@
If you're running this in a web browser, you need to click the window before you'll hear anything!
This example code creates an simple audio stream for playing sound, and
generates a sine wave sound effect for it to play as time goes on. This is the
simplest way to get up and running with procedural sound.

View File

@@ -0,0 +1,99 @@
/*
* This example code creates an simple audio stream for playing sound, and
* generates a sine wave sound effect for it to play as time goes on. This
* is the simplest way to get up and running with procedural sound.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_AudioStream *stream = NULL;
static int total_samples_generated = 0;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_AudioSpec spec;
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* we don't _need_ a window for audio-only things but it's good policy to have one. */
if (!SDL_CreateWindowAndRenderer("examples/audio/simple-playback", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* We're just playing a single thing here, so we'll use the simplified option.
We are always going to feed audio in as mono, float32 data at 8000Hz.
The stream will convert it to whatever the hardware wants on the other side. */
spec.channels = 1;
spec.format = SDL_AUDIO_F32;
spec.freq = 8000;
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
if (!stream) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(), window);
return SDL_APP_FAILURE;
}
/* SDL_OpenAudioDeviceStream starts the device paused. You have to tell it to start! */
SDL_ResumeAudioStreamDevice(stream);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
/* see if we need to feed the audio stream more data yet.
We're being lazy here, but if there's less than half a second queued, generate more.
A sine wave is unchanging audio--easy to stream--but for video games, you'll want
to generate significantly _less_ audio ahead of time! */
const int minimum_audio = (8000 * sizeof (float)) / 2; /* 8000 float samples per second. Half of that. */
if (SDL_GetAudioStreamAvailable(stream) < minimum_audio) {
static float samples[512]; /* this will feed 512 samples each frame until we get to our maximum. */
int i;
for (i = 0; i < SDL_arraysize(samples); i++) {
/* You don't have to care about this math; we're just generating a simple sine wave as we go.
https://en.wikipedia.org/wiki/Sine_wave */
const float time = total_samples_generated / 8000.0f;
const int sine_freq = 500; /* run the wave at 500Hz */
samples[i] = SDL_sinf(6.283185f * sine_freq * time);
total_samples_generated++;
}
/* feed the new data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */
SDL_PutAudioStreamData(stream, samples, sizeof (samples));
}
/* we're not doing anything with the renderer, so just blank it out. */
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1,5 @@
If you're running this in a web browser, you need to click the window before you'll hear anything!
This example code creates an simple audio stream for playing sound, and
generates a sine wave sound effect for it to play as time goes on. Unlike
the previous example, this uses a callback to generate sound.

View File

@@ -0,0 +1,111 @@
/*
* This example code creates an simple audio stream for playing sound, and
* generates a sine wave sound effect for it to play as time goes on. Unlike
* the previous example, this uses a callback to generate sound.
*
* This might be the path of least resistance if you're moving an SDL2
* program's audio code to SDL3.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_AudioStream *stream = NULL;
static int total_samples_generated = 0;
/* this function will be called (usually in a background thread) when the audio stream is consuming data. */
static void SDLCALL FeedTheAudioStreamMore(void *userdata, SDL_AudioStream *astream, int additional_amount, int total_amount)
{
/* total_amount is how much data the audio stream is eating right now, additional_amount is how much more it needs
than what it currently has queued (which might be zero!). You can supply any amount of data here; it will take what
it needs and use the extra later. If you don't give it enough, it will take everything and then feed silence to the
hardware for the rest. Ideally, though, we always give it what it needs and no extra, so we aren't buffering more
than necessary. */
additional_amount /= sizeof (float); /* convert from bytes to samples */
while (additional_amount > 0) {
float samples[128]; /* this will feed 128 samples each iteration until we have enough. */
const int total = SDL_min(additional_amount, SDL_arraysize(samples));
int i;
for (i = 0; i < total; i++) {
/* You don't have to care about this math; we're just generating a simple sine wave as we go.
https://en.wikipedia.org/wiki/Sine_wave */
const float time = total_samples_generated / 8000.0f;
const int sine_freq = 500; /* run the wave at 500Hz */
samples[i] = SDL_sinf(6.283185f * sine_freq * time);
total_samples_generated++;
}
/* feed the new data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */
SDL_PutAudioStreamData(astream, samples, total * sizeof (float));
additional_amount -= total; /* subtract what we've just fed the stream. */
}
}
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_AudioSpec spec;
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* we don't _need_ a window for audio-only things but it's good policy to have one. */
if (!SDL_CreateWindowAndRenderer("examples/audio/simple-playback-callback", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* We're just playing a single thing here, so we'll use the simplified option.
We are always going to feed audio in as mono, float32 data at 8000Hz.
The stream will convert it to whatever the hardware wants on the other side. */
spec.channels = 1;
spec.format = SDL_AUDIO_F32;
spec.freq = 8000;
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, FeedTheAudioStreamMore, NULL);
if (!stream) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(), window);
return SDL_APP_FAILURE;
}
/* SDL_OpenAudioDeviceStream starts the device paused. You have to tell it to start! */
SDL_ResumeAudioStreamDevice(stream);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
/* we're not doing anything with the renderer, so just blank it out. */
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
/* all the work of feeding the audio stream is happening in a callback in a background thread. */
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1,5 @@
If you're running this in a web browser, you need to click the window before you'll hear anything!
This example code creates an simple audio stream for playing sound, and
loads a .wav file that is pushed through the stream in a loop.

View File

@@ -0,0 +1,101 @@
/*
* This example code creates an simple audio stream for playing sound, and
* loads a .wav file that is pushed through the stream in a loop.
*
* This code is public domain. Feel free to use it for any purpose!
*
* The .wav file is a sample from Will Provost's song, The Living Proof,
* used with permission.
*
* From the album The Living Proof
* Publisher: 5 Guys Named Will
* Copyright 1996 Will Provost
* https://itunes.apple.com/us/album/the-living-proof/id4153978
* http://www.amazon.com/The-Living-Proof-Will-Provost/dp/B00004R8RH
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_AudioStream *stream = NULL;
static Uint8 *wav_data = NULL;
static Uint32 wav_data_len = 0;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_AudioSpec spec;
char *wav_path = NULL;
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* we don't _need_ a window for audio-only things but it's good policy to have one. */
if (!SDL_CreateWindowAndRenderer("examples/audio/load-wav", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* Load the .wav file from wherever the app is being run from. */
SDL_asprintf(&wav_path, "%ssample.wav", SDL_GetBasePath()); /* allocate a string of the full file path */
if (!SDL_LoadWAV(wav_path, &spec, &wav_data, &wav_data_len)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load .wav file!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
SDL_free(wav_path); /* done with this string. */
/* Create our audio stream in the same format as the .wav file. It'll convert to what the audio hardware wants. */
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
if (!stream) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audio stream!", SDL_GetError(), window);
return SDL_APP_FAILURE;
}
/* SDL_OpenAudioDeviceStream starts the device paused. You have to tell it to start! */
SDL_ResumeAudioStreamDevice(stream);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
/* see if we need to feed the audio stream more data yet.
We're being lazy here, but if there's less than the entire wav file left to play,
just shove a whole copy of it into the queue, so we always have _tons_ of
data queued for playback. */
if (SDL_GetAudioStreamAvailable(stream) < (int)wav_data_len) {
/* feed more data to the stream. It will queue at the end, and trickle out as the hardware needs more data. */
SDL_PutAudioStreamData(stream, wav_data, wav_data_len);
}
/* we're not doing anything with the renderer, so just blank it out. */
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
SDL_free(wav_data); /* strictly speaking, this isn't necessary because the process is ending, but it's good policy. */
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1 @@
This reads from a webcam and draws frames of video to the screen.

View File

@@ -0,0 +1,112 @@
/*
* This example code reads frames from a camera and draws it to the screen.
*
* This is a very simple approach that is often Good Enough. You can get
* fancier with this: multiple cameras, front/back facing cameras on phones,
* color spaces, choosing formats and framerates...this just requests
* _anything_ and goes with what it is handed.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Camera *camera = NULL;
static SDL_Texture *texture = NULL;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_CameraID *devices = NULL;
int devcount = 0;
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_CAMERA)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("examples/camera/read-and-draw", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
devices = SDL_GetCameras(&devcount);
if (devices == NULL) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't enumerate camera devices!", SDL_GetError(), window);
return SDL_APP_FAILURE;
} else if (devcount == 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't find any camera devices!", "Please connect a camera and try again.", window);
return SDL_APP_FAILURE;
}
camera = SDL_OpenCamera(devices[0], NULL); // just take the first thing we see in any format it wants.
SDL_free(devices);
if (camera == NULL) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't open camera!", SDL_GetError(), window);
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
} else if (event->type == SDL_EVENT_CAMERA_DEVICE_APPROVED) {
SDL_Log("Camera use approved by user!");
} else if (event->type == SDL_EVENT_CAMERA_DEVICE_DENIED) {
SDL_Log("Camera use denied by user!");
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Camera permission denied!", "User denied access to the camera!", window);
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
Uint64 timestampNS = 0;
SDL_Surface *frame = SDL_AcquireCameraFrame(camera, &timestampNS);
if (frame != NULL) {
/* Some platforms (like Emscripten) don't know _what_ the camera offers
until the user gives permission, so we build the texture and resize
the window when we get a first frame from the camera. */
if (!texture) {
SDL_SetWindowSize(window, frame->w, frame->h); /* Resize the window to match */
texture = SDL_CreateTexture(renderer, frame->format, SDL_TEXTUREACCESS_STREAMING, frame->w, frame->h);
}
if (texture) {
SDL_UpdateTexture(texture, NULL, frame->pixels, frame->pitch);
}
SDL_ReleaseCameraFrame(camera, frame);
}
SDL_SetRenderDrawColor(renderer, 0x99, 0x99, 0x99, 255);
SDL_RenderClear(renderer);
if (texture) { /* draw the latest camera frame, if available. */
SDL_RenderTexture(renderer, texture, NULL, NULL);
}
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
SDL_CloseCamera(camera);
SDL_DestroyTexture(texture);
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1 @@
A complete game of Snake, written in SDL.

View File

@@ -0,0 +1,332 @@
/*
* Logic implementation of the Snake game. It is designed to efficiently
* represent in memory the state of the game.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#define STEP_RATE_IN_MILLISECONDS 125
#define SNAKE_BLOCK_SIZE_IN_PIXELS 24
#define SDL_WINDOW_WIDTH (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_WIDTH)
#define SDL_WINDOW_HEIGHT (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_HEIGHT)
#define SNAKE_GAME_WIDTH 24U
#define SNAKE_GAME_HEIGHT 18U
#define SNAKE_MATRIX_SIZE (SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT)
#define THREE_BITS 0x7U /* ~CHAR_MAX >> (CHAR_BIT - SNAKE_CELL_MAX_BITS) */
#define SHIFT(x, y) (((x) + ((y) * SNAKE_GAME_WIDTH)) * SNAKE_CELL_MAX_BITS)
typedef enum
{
SNAKE_CELL_NOTHING = 0U,
SNAKE_CELL_SRIGHT = 1U,
SNAKE_CELL_SUP = 2U,
SNAKE_CELL_SLEFT = 3U,
SNAKE_CELL_SDOWN = 4U,
SNAKE_CELL_FOOD = 5U
} SnakeCell;
#define SNAKE_CELL_MAX_BITS 3U /* floor(log2(SNAKE_CELL_FOOD)) + 1 */
typedef enum
{
SNAKE_DIR_RIGHT,
SNAKE_DIR_UP,
SNAKE_DIR_LEFT,
SNAKE_DIR_DOWN
} SnakeDirection;
typedef struct
{
unsigned char cells[(SNAKE_MATRIX_SIZE * SNAKE_CELL_MAX_BITS) / 8U];
char head_xpos;
char head_ypos;
char tail_xpos;
char tail_ypos;
char next_dir;
char inhibit_tail_step;
unsigned occupied_cells;
} SnakeContext;
typedef struct
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_TimerID step_timer;
SnakeContext snake_ctx;
} AppState;
SnakeCell snake_cell_at(const SnakeContext *ctx, char x, char y)
{
const int shift = SHIFT(x, y);
unsigned short range;
SDL_memcpy(&range, ctx->cells + (shift / 8), sizeof(range));
return (SnakeCell)((range >> (shift % 8)) & THREE_BITS);
}
static void set_rect_xy_(SDL_FRect *r, short x, short y)
{
r->x = (float)(x * SNAKE_BLOCK_SIZE_IN_PIXELS);
r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS);
}
static void put_cell_at_(SnakeContext *ctx, char x, char y, SnakeCell ct)
{
const int shift = SHIFT(x, y);
const int adjust = shift % 8;
unsigned char *const pos = ctx->cells + (shift / 8);
unsigned short range;
SDL_memcpy(&range, pos, sizeof(range));
range &= ~(THREE_BITS << adjust); /* clear bits */
range |= (ct & THREE_BITS) << adjust;
SDL_memcpy(pos, &range, sizeof(range));
}
static int are_cells_full_(SnakeContext *ctx)
{
return ctx->occupied_cells == SNAKE_GAME_WIDTH * SNAKE_GAME_HEIGHT;
}
static void new_food_pos_(SnakeContext *ctx)
{
while (SDL_TRUE) {
const char x = (char) SDL_rand(SNAKE_GAME_WIDTH);
const char y = (char) SDL_rand(SNAKE_GAME_HEIGHT);
if (snake_cell_at(ctx, x, y) == SNAKE_CELL_NOTHING) {
put_cell_at_(ctx, x, y, SNAKE_CELL_FOOD);
break;
}
}
}
void snake_initialize(SnakeContext *ctx)
{
int i;
SDL_zeroa(ctx->cells);
ctx->head_xpos = ctx->tail_xpos = SNAKE_GAME_WIDTH / 2;
ctx->head_ypos = ctx->tail_ypos = SNAKE_GAME_HEIGHT / 2;
ctx->next_dir = SNAKE_DIR_RIGHT;
ctx->inhibit_tail_step = ctx->occupied_cells = 4;
--ctx->occupied_cells;
put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_SRIGHT);
for (i = 0; i < 4; i++) {
new_food_pos_(ctx);
++ctx->occupied_cells;
}
}
void snake_redir(SnakeContext *ctx, SnakeDirection dir)
{
SnakeCell ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos);
if ((dir == SNAKE_DIR_RIGHT && ct != SNAKE_CELL_SLEFT) ||
(dir == SNAKE_DIR_UP && ct != SNAKE_CELL_SDOWN) ||
(dir == SNAKE_DIR_LEFT && ct != SNAKE_CELL_SRIGHT) ||
(dir == SNAKE_DIR_DOWN && ct != SNAKE_CELL_SUP)) {
ctx->next_dir = dir;
}
}
static void wrap_around_(char *val, char max)
{
if (*val < 0) {
*val = max - 1;
} else if (*val > max - 1) {
*val = 0;
}
}
void snake_step(SnakeContext *ctx)
{
const SnakeCell dir_as_cell = (SnakeCell)(ctx->next_dir + 1);
SnakeCell ct;
char prev_xpos;
char prev_ypos;
/* Move tail forward */
if (--ctx->inhibit_tail_step == 0) {
++ctx->inhibit_tail_step;
ct = snake_cell_at(ctx, ctx->tail_xpos, ctx->tail_ypos);
put_cell_at_(ctx, ctx->tail_xpos, ctx->tail_ypos, SNAKE_CELL_NOTHING);
switch (ct) {
case SNAKE_CELL_SRIGHT:
ctx->tail_xpos++;
break;
case SNAKE_CELL_SUP:
ctx->tail_ypos--;
break;
case SNAKE_CELL_SLEFT:
ctx->tail_xpos--;
break;
case SNAKE_CELL_SDOWN:
ctx->tail_ypos++;
break;
default:
break;
}
wrap_around_(&ctx->tail_xpos, SNAKE_GAME_WIDTH);
wrap_around_(&ctx->tail_ypos, SNAKE_GAME_HEIGHT);
}
/* Move head forward */
prev_xpos = ctx->head_xpos;
prev_ypos = ctx->head_ypos;
switch (ctx->next_dir) {
case SNAKE_DIR_RIGHT:
++ctx->head_xpos;
break;
case SNAKE_DIR_UP:
--ctx->head_ypos;
break;
case SNAKE_DIR_LEFT:
--ctx->head_xpos;
break;
case SNAKE_DIR_DOWN:
++ctx->head_ypos;
break;
}
wrap_around_(&ctx->head_xpos, SNAKE_GAME_WIDTH);
wrap_around_(&ctx->head_ypos, SNAKE_GAME_HEIGHT);
/* Collisions */
ct = snake_cell_at(ctx, ctx->head_xpos, ctx->head_ypos);
if (ct != SNAKE_CELL_NOTHING && ct != SNAKE_CELL_FOOD) {
snake_initialize(ctx);
return;
}
put_cell_at_(ctx, prev_xpos, prev_ypos, dir_as_cell);
put_cell_at_(ctx, ctx->head_xpos, ctx->head_ypos, dir_as_cell);
if (ct == SNAKE_CELL_FOOD) {
if (are_cells_full_(ctx)) {
snake_initialize(ctx);
return;
}
new_food_pos_(ctx);
++ctx->inhibit_tail_step;
++ctx->occupied_cells;
}
}
static Uint32 sdl_timer_callback_(void *payload, SDL_TimerID timer_id, Uint32 interval)
{
/* NOTE: snake_step is not called here directly for multithreaded concerns. */
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_USER;
SDL_PushEvent(&event);
return interval;
}
static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
{
switch (key_code) {
/* Quit. */
case SDL_SCANCODE_ESCAPE:
case SDL_SCANCODE_Q:
return SDL_APP_SUCCESS;
/* Restart the game as if the program was launched. */
case SDL_SCANCODE_R:
snake_initialize(ctx);
break;
/* Decide new direction of the snake. */
case SDL_SCANCODE_RIGHT:
snake_redir(ctx, SNAKE_DIR_RIGHT);
break;
case SDL_SCANCODE_UP:
snake_redir(ctx, SNAKE_DIR_UP);
break;
case SDL_SCANCODE_LEFT:
snake_redir(ctx, SNAKE_DIR_LEFT);
break;
case SDL_SCANCODE_DOWN:
snake_redir(ctx, SNAKE_DIR_DOWN);
break;
default:
break;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
AppState *as;
SnakeContext *ctx;
SDL_FRect r;
unsigned i;
unsigned j;
int ct;
as = (AppState *)appstate;
ctx = &as->snake_ctx;
r.w = r.h = SNAKE_BLOCK_SIZE_IN_PIXELS;
SDL_SetRenderDrawColor(as->renderer, 0, 0, 0, 255);
SDL_RenderClear(as->renderer);
for (i = 0; i < SNAKE_GAME_WIDTH; i++) {
for (j = 0; j < SNAKE_GAME_HEIGHT; j++) {
ct = snake_cell_at(ctx, i, j);
if (ct == SNAKE_CELL_NOTHING)
continue;
set_rect_xy_(&r, i, j);
if (ct == SNAKE_CELL_FOOD)
SDL_SetRenderDrawColor(as->renderer, 80, 80, 255, 255);
else /* body */
SDL_SetRenderDrawColor(as->renderer, 0, 128, 0, 255);
SDL_RenderFillRect(as->renderer, &r);
}
}
SDL_SetRenderDrawColor(as->renderer, 255, 255, 0, 255); /*head*/
set_rect_xy_(&r, ctx->head_xpos, ctx->head_ypos);
SDL_RenderFillRect(as->renderer, &r);
SDL_RenderPresent(as->renderer);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
return SDL_APP_FAILURE;
}
AppState *as = SDL_calloc(1, sizeof(AppState));
*appstate = as;
if (!SDL_CreateWindowAndRenderer("examples/game/snake", SDL_WINDOW_WIDTH, SDL_WINDOW_HEIGHT, 0, &as->window, &as->renderer)) {
return SDL_APP_FAILURE;
}
snake_initialize(&as->snake_ctx);
as->step_timer = SDL_AddTimer(STEP_RATE_IN_MILLISECONDS, sdl_timer_callback_, NULL);
if (as->step_timer == 0) {
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
SnakeContext *ctx = &((AppState *)appstate)->snake_ctx;
switch (event->type) {
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
case SDL_EVENT_USER:
snake_step(ctx);
break;
case SDL_EVENT_KEY_DOWN:
return handle_key_event_(ctx, event->key.scancode);
}
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate)
{
if (appstate != NULL) {
AppState *as = (AppState *)appstate;
SDL_RemoveTimer(as->step_timer);
SDL_DestroyRenderer(as->renderer);
SDL_DestroyWindow(as->window);
SDL_free(as);
}
}

View File

@@ -0,0 +1,77 @@
-- This code adapted from https://gitlab.com/saalen/highlight/-/wikis/Plug-Ins
-- first add a description of what the plug-in does
Description="Add wiki.libsdl.org reference links to HTML, LaTeX or RTF output"
-- define the plugin categories (ie. supported output formats; languages)
Categories = { "c", "c++" }
-- the syntaxUpdate function contains code related to syntax recognition
function syntaxUpdate(desc)
-- if the current file is not C/C++ file we exit
if desc~="C and C++" then
return
end
-- this function returns a qt-project reference link of the given token
function getURL(token)
-- generate the URL
url='https://wiki.libsdl.org/SDL3/'.. token
-- embed the URL in a hyperlink according to the output format
-- first HTML, then LaTeX and RTF
if (HL_OUTPUT== HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
return '<a class="hl" target="new" href="'
.. url .. '">'.. token .. '</a>'
elseif (HL_OUTPUT == HL_FORMAT_LATEX) then
return '\\href{'..url..'}{'..token..'}'
elseif (HL_OUTPUT == HL_FORMAT_RTF) then
return '{{\\field{\\*\\fldinst HYPERLINK "'
..url..'" }{\\fldrslt\\ul\\ulc0 '..token..'}}}'
end
end
-- the Decorate function will be invoked for every recognized token
function Decorate(token, state)
-- we are only interested in keywords, preprocessor or default items
if (state ~= HL_STANDARD and state ~= HL_KEYWORD and
state ~=HL_PREPROC) then
return
end
-- SDL keywords start with SDL_
-- if this pattern applies to the token, we return the URL
-- if we return nothing, the token is outputted as is
if string.find(token, "SDL_")==1 then
return getURL(token)
end
end
end
-- the themeUpdate function contains code related to the theme
function themeUpdate(desc)
-- the Injections table can be used to add style information to the theme
-- HTML: we add additional CSS style information to beautify hyperlinks,
-- they should have the same color as their surrounding tags
if (HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
Injections[#Injections+1]=
"a.hl, a.hl:visited {color:inherit;font-weight:inherit;text-decoration:none}"
-- LaTeX: hyperlinks require the hyperref package, so we add this here
-- the colorlinks and pdfborderstyle options remove ugly boxes in the output
elseif (HL_OUTPUT==HL_FORMAT_LATEX) then
Injections[#Injections+1]=
"\\usepackage[colorlinks=false, pdfborderstyle={/S/U/W 1}]{hyperref}"
end
end
-- let highlight load the chunks
Plugins={
{ Type="lang", Chunk=syntaxUpdate },
{ Type="theme", Chunk=themeUpdate },
}

View File

@@ -0,0 +1,3 @@
You need something with a pen/stylus for this to work.
This takes pen input and draws lines. Lines are darker when you press harder.

View File

@@ -0,0 +1,104 @@
/*
* This example code reads pen/stylus input and draws lines. Darker lines
* for harder pressure.
*
* SDL can track multiple pens, but for simplicity here, this assumes any
* pen input we see was from one device.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *render_target = NULL;
static float pressure = 0.0f;
static float previous_touch_x = -1.0f;
static float previous_touch_y = -1.0f;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("examples/pen/drawing-lines", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* we make a render target so we can draw lines to it and not have to record and redraw every pen stroke each frame.
Instead rendering a frame for us is a single texture draw. */
render_target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480);
if (!render_target) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create render target!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* just blank the render target to gray to start. */
SDL_SetRenderTarget(renderer, render_target);
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
/* There are several events that track the specific stages of pen activity,
but we're only going to look for motion and pressure, for simplicity. */
if (event->type == SDL_EVENT_PEN_MOTION) {
/* you can check for when the pen is touching, but if pressure > 0.0f, it's definitely touching! */
if (pressure > 0.0f) {
if (previous_touch_x >= 0.0f) { /* only draw if we're moving while touching */
/* draw with the alpha set to the pressure, so you effectively get a fainter line for lighter presses. */
SDL_SetRenderTarget(renderer, render_target);
SDL_SetRenderDrawColorFloat(renderer, 0, 0, 0, pressure);
SDL_RenderLine(renderer, previous_touch_x, previous_touch_y, event->pmotion.x, event->pmotion.y);
}
previous_touch_x = event->pmotion.x;
previous_touch_y = event->pmotion.y;
} else {
previous_touch_x = previous_touch_y = -1.0f;
}
} else if (event->type == SDL_EVENT_PEN_AXIS) {
if (event->paxis.axis == SDL_PEN_AXIS_PRESSURE) {
pressure = event->paxis.value; /* remember new pressure for later draws. */
}
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
/* make sure we're drawing to the window and not the render target */
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer); /* just in case. */
SDL_RenderTexture(renderer, render_target, NULL, NULL);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
SDL_DestroyTexture(render_target);
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1,3 @@
This example code creates an SDL window and renderer, and then clears the
window to a different color every frame, so you'll effectively get a window
that's smoothly fading between colors.

View File

@@ -0,0 +1,85 @@
/*
* This example code creates an SDL window and renderer, and then clears the
* window to a different color every frame, so you'll effectively get a window
* that's smoothly fading between colors.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
/* the current red color we're clearing to. */
static Uint8 red = 0;
/* When fading up, this is 1, when fading down, it's -1. */
static int fade_direction = 1;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("examples/renderer/clear", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
SDL_SetRenderVSync(renderer, 1); /* try to show frames at the monitor refresh rate. */
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
/* since we're always fading red, we leave green and blue at zero.
alpha doesn't mean much here, so leave it at full (255, no transparency). */
SDL_SetRenderDrawColor(renderer, red, 0, 0, 255);
/* clear the window to the draw color. */
SDL_RenderClear(renderer);
/* put the newly-cleared rendering on the screen. */
SDL_RenderPresent(renderer);
/* update the color for the next frame we will draw. */
if (fade_direction > 0) {
if (red == 255) {
fade_direction = -1;
} else {
red++;
}
} else if (fade_direction < 0) {
if (red == 0) {
fade_direction = 1;
} else {
red--;
}
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
/* SDL will clean up the window/renderer for us. */
}

View File

@@ -0,0 +1,3 @@
This example creates an SDL window and renderer, and then draws some lines,
rectangles and points to it every frame.

View File

@@ -0,0 +1,93 @@
/*
* This example creates an SDL window and renderer, and then draws some lines,
* rectangles and points to it every frame.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_FPoint points[500];
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
int i;
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("examples/renderer/primitives", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
/* set up some random points */
for (i = 0; i < SDL_arraysize(points); i++) {
points[i].x = (SDL_randf() * 440.0f) + 100.0f;
points[i].y = (SDL_randf() * 280.0f) + 100.0f;
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
SDL_FRect rect;
/* as you can see from this, rendering draws over whatever was drawn before it. */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); /* black, full alpha */
SDL_RenderClear(renderer); /* start with a blank canvas. */
/* draw a filled rectangle in the middle of the canvas. */
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); /* blue, full alpha */
rect.x = rect.y = 100;
rect.w = 440;
rect.h = 280;
SDL_RenderFillRect(renderer, &rect);
/* draw some points across the canvas. */
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); /* red, full alpha */
SDL_RenderPoints(renderer, points, SDL_arraysize(points));
/* draw a unfilled rectangle in-set a little bit. */
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); /* green, full alpha */
rect.x += 30;
rect.y += 30;
rect.w -= 60;
rect.h -= 60;
SDL_RenderRect(renderer, &rect);
/* draw two lines in an X across the whole canvas. */
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); /* yellow, full alpha */
SDL_RenderLine(renderer, 0, 0, 640, 480);
SDL_RenderLine(renderer, 0, 480, 640, 0);
SDL_RenderPresent(renderer); /* put it all on the screen! */
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
/* SDL will clean up the window/renderer for us. */
}

51
external/SDL/examples/template.c vendored Normal file
View File

@@ -0,0 +1,51 @@
/*
* This example code $WHAT_IT_DOES.
*
* This code is public domain. Feel free to use it for any purpose!
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* We will use this renderer to draw into this window every frame. */
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("examples/CATEGORY/NAME", 640, 480, 0, &window, &renderer)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window/renderer!", SDL_GetError(), NULL);
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
return SDL_APP_CONTINUE; /* carry on with the program! */
}
/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate)
{
/* SDL will clean up the window/renderer for us. */
}

218
external/SDL/examples/template.html vendored Normal file
View File

@@ -0,0 +1,218 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>@project_name@ Example: @category_name@/@example_name@</title>
<style>
html, body {
width: 100vw;
height: 100vh;
overflow: hidden;
font-family: 'Liberation Sans', sans-serif;
}
.canvas-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background: black;
}
#canvas {
box-shadow: 0 0 0.5rem #7787;
}
#output-container {
position: absolute;
top: 100%;
left: 0;
right: 0;
bottom: 0;
background-color: black;
border: none;
border-top: 1px solid #778;
margin: 0;
padding: 1rem;
transition: top 0.25s;
}
#output-container::before {
position: absolute;
bottom: 100%;
right: 1rem;
content: 'Console';
font-size: 1.5rem;
color: white;
background: black;
border: 1px solid #778;
border-bottom: none;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem 0.5rem 0 0;
}
#output-container:hover,
#output-container:focus-within {
top: 50%;
}
#output-container:focus-within {
border-top: 2px solid orange;
}
#output-container:focus-within::before {
border: 2px solid orange;
border-bottom: none;
}
#output {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: none;
background: black;
color: white;
outline: none;
resize: none;
font-family: 'Lucida Console', Monaco, monospace;
}
#source-code {
position: absolute;
top: 100%;
left: 0;
right: 0;
bottom: 0;
background: #e0eaee;
padding: 1rem;
transition: top 0.25s;
}
#source-code::before {
position: absolute;
bottom: 100%;
left: 1rem;
content: 'Source code';
font-size: 1.5rem;
background: linear-gradient(to bottom, #789, #e0eaee);
padding: 0.75rem 1.5rem;
border-radius: 0.5rem 0.5rem 0 0;
}
#source-code:hover,
#source-code:focus-within {
top: 50%;
}
#source-code:focus-within {
border-top: 2px solid orange;
}
#source-code:focus-within::before {
border: 2px solid orange;
border-bottom: none;
}
#source-code-contents {
height: 100%;
overflow: scroll;
}
#example-description {
color: white;
text-align: center;
position: relative; /* required for proper positioning */
}
</style>
<link rel="stylesheet" type="text/css" href="highlight.css">
</head>
<body>
<div class="canvas-container">
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
</div>
<div id="example-description">
@description@
</div>
<div id="output-container">
<textarea id="output" rows="8" spellcheck="false" readonly></textarea>
</div>
<div id="source-code" tabindex="1">
<div id="source-code-contents">@htmlified_source_code@</div>
</div>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
var elem = document.getElementById('output-container');
if (elem.style['top'] == '') {
elem.style['top'] = '50%';
setTimeout(function() { elem.style['top'] = ''; }, 3000);
}
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) { Module.print(text) },
canvas: (() => {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", (e) => { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: (text) => {},
totalDependencies: 0,
monitorRunDependencies: (left) => {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
window.onerror = (event) => {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console');
Module.setStatus = (text) => {
if (text) console.error('[post-exception status] ' + text);
};
};
</script>
<script async type="text/javascript" src="@javascript_file@"></script>
</body>
</html>