Compare commits

...

No commits in common. "portable" and "accurate" have entirely different histories.

185 changed files with 7128 additions and 59384 deletions

View File

@ -8,15 +8,12 @@ dist: bionic
# Enable C++ language support
language: cpp
osx_image: xcode11.3
compiler:
- gcc
- clang
os:
- linux
- osx
# - windows
addons:
apt:
@ -26,54 +23,44 @@ addons:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
packages:
- make
- cmake
- gcc-9
- g++-9
- clang-9
- libsdl1.2-dev
- libsdl2-dev
- libglfw3-dev
- libfreetype6-dev
homebrew:
packages:
- make
- cmake
- gcc@9
- llvm@9
- sdl
- sdl2
- glfw
- freetype
- mingw-w64
env:
- PLATFORM=SDL2 AUDIO=SDL2 RENDERER=Software
- PLATFORM=SDL2 AUDIO=SDL2 RENDERER=SDLSurface
- PLATFORM=SDL2 AUDIO=SDL2 RENDERER=SDLTexture
- PLATFORM=SDL2 AUDIO=SDL2 RENDERER=OpenGL3
- PLATFORM=SDL2 AUDIO=SDL2 RENDERER=OpenGLES2
- PLATFORM=SDL1 AUDIO=SDL1 RENDERER=Software
- PLATFORM=SDL1 AUDIO=SDL1 RENDERER=OpenGL3
- PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=Software
- PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=OpenGL3
- PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=OpenGLES2
- PLATFORM=Null AUDIO=Null RENDERER=Software
jobs:
exclude:
# macOS doesn't support OpenGLES2, apparently
- os: osx
env: PLATFORM=SDL2 AUDIO=SDL2 RENDERER=OpenGLES2
- os: osx
env: PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=OpenGLES2
# GCC is mysteriously broken when trying to parse macOS headers for miniaudio
- os: osx
compiler: gcc
env: PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=OpenGL3
- os: osx
compiler: gcc
env: PLATFORM=GLFW3 AUDIO=miniaudio RENDERER=Software
- SIXTY_FOUR_BIT=false FIX_BUGS=0 JAPANESE=0
- SIXTY_FOUR_BIT=false FIX_BUGS=0 JAPANESE=1
- SIXTY_FOUR_BIT=false FIX_BUGS=1 JAPANESE=0
- SIXTY_FOUR_BIT=false FIX_BUGS=1 JAPANESE=1
- SIXTY_FOUR_BIT=true FIX_BUGS=0 JAPANESE=0
- SIXTY_FOUR_BIT=true FIX_BUGS=0 JAPANESE=1
- SIXTY_FOUR_BIT=true FIX_BUGS=1 JAPANESE=0
- SIXTY_FOUR_BIT=true FIX_BUGS=1 JAPANESE=1
before_install:
# Setup MSYS2
- |
if [ "$TRAVIS_OS_NAME" == "windows" ]; then
[[ ! -f C:/tools/msys64/msys2_shell.cmd ]] && rm -rf C:/tools/msys64
choco uninstall -y mingw
choco upgrade --no-progress -y msys2
export msys2='cmd //C RefreshEnv.cmd '
export msys2+='& set MSYS=winsymlinks:nativestrict '
export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start'
if [ "$SIXTY_FOUR_BIT" == "true" ]; then
export mingw="$msys2 -mingw64 -full-path -here -c "\"\$@"\" --"
else
export mingw="$msys2 -mingw32 -full-path -here -c "\"\$@"\" --"
fi
export msys2+=" -msys2 -c "\"\$@"\" --"
if [ "$SIXTY_FOUR_BIT" == "true" ]; then
$msys2 pacman --sync --noconfirm --needed make mingw-w64-x86_64-toolchain
else
$msys2 pacman --sync --noconfirm --needed make mingw-w64-i686-toolchain
fi
taskkill //IM gpg-agent.exe //F # https://travis-ci.community/t/4967
export PATH=/C/tools/msys64/mingw64/bin:$PATH
export MAKE=mingw32-make # so that Autotools can find it
fi
# Set URL for Discord send script
- DISCORD_SEND_SCRIPT_URL=https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
- DISCORD_SEND_SCRIPT_FILENAME=discordSendNotification.sh
@ -84,48 +71,54 @@ before_install:
# Display Travis OS name
- echo $TRAVIS_OS_NAME
# The following Homebrew packages aren't linked by default, and need to be prepended to the path explicitly.
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
export PATH="$(brew --prefix llvm)/bin:$PATH";
# Define CC and CXX
- |
if [ "$SIXTY_FOUR_BIT" == "true" ]; then
export CC="x86_64-w64-mingw32-gcc"
export CXX="x86_64-w64-mingw32-g++"
else
export CC="i686-w64-mingw32-gcc"
export CXX="i686-w64-mingw32-g++"
fi
# /usr/bin/gcc points to an older compiler on both Linux and macOS.
- if [ "$CXX" = "g++" ]; then export CXX="g++-9" CC="gcc-9"; fi
# /usr/bin/clang points to an older compiler on both Linux and macOS.
#
# Homebrew's llvm package doesn't ship a versioned clang++ binary, so the values
# below don't work on macOS. Fortunately, the path change above makes the
# default values (clang and clang++) resolve to the correct compiler on macOS.
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$CXX" = "clang++" ]; then export CXX="clang++-9" CC="clang-9"; fi;
# Define WINDRES
- |
if [ "$TRAVIS_OS_NAME" == "windows" ]; then
export WINDRES="windres"
else
if [ "$SIXTY_FOUR_BIT" == "true" ]; then
export WINDRES="x86_64-w64-mingw32-windres"
else
export WINDRES="i686-w64-mingw32-windres"
fi
fi
# Display compilers/cmake name/version
- echo ${CC}
- echo ${CXX}
- ${CC} --version
- ${CXX} --version
- cmake --version
# Display compilers name/version
- $mingw echo ${CC}
- $mingw echo ${CXX}
- $mingw ${CC} --version
- $mingw ${CXX} --version
before_cache:
- |
if [ "$TRAVIS_OS_NAME" == "windows" ]; then
# https://unix.stackexchange.com/a/137322/107554
$msys2 pacman --sync --clean --noconfirm
fi
cache:
directories:
- $HOME/AppData/Local/Temp/chocolatey
- /C/tools/msys64
install:
# Get number of cores (or 2 by default if somehow none of these are available somehow)
- JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2)
- echo $JOBS
# Recommanded build directory
- CMAKE_BUILD_DIR=build
before_script:
# Make build directory and generate CMake build files
- mkdir -p ${CMAKE_BUILD_DIR} && cd ${CMAKE_BUILD_DIR}
- cmake .. -DCMAKE_BUILD_TYPE=Release -DFIX_BUGS=ON -DBACKEND_PLATFORM=$PLATFORM -DBACKEND_AUDIO=$AUDIO -DBACKEND_RENDERER=$RENDERER -DCMAKE_C_FLAGS="-Wall -Wextra -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -pedantic"
- cd ..
script:
- cd ${CMAKE_BUILD_DIR}
- cmake --build . --config Release --parallel $JOBS
- cd ..
# Build
- $mingw make -j ${JOBS} FIX_BUGS=${FIX_BUGS} JAPANESE=${JAPANESE} RELEASE=1 WINDOWS=1 STATIC=1 CXXFLAGS="-Wall -Wextra -pedantic"
after_success:
# Send success notification to Discord through DISCORD_WEBHOOK_URL

View File

@ -1,8 +1,4 @@
cmake_minimum_required(VERSION 3.8)
if((${CMAKE_VERSION} VERSION_EQUAL 3.9) OR (${CMAKE_VERSION} VERSION_GREATER 3.9))
cmake_policy(SET CMP0069 NEW)
endif()
cmake_minimum_required(VERSION 3.5.1)
#############
@ -18,21 +14,11 @@ set(ASSETS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets")
option(JAPANESE "Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation)" OFF)
option(FIX_BUGS "Fix various bugs in the game" OFF)
option(FIX_MAJOR_BUGS "Fix bugs that invoke undefined behaviour or cause memory leaks" ON)
option(DEBUG_SAVE "Re-enable the ability to drag-and-drop save files onto the window" OFF)
option(DOCONFIG "Compile a DoConfig clone tool - not useful for console ports" ON)
option(LANCZOS_RESAMPLER "Use Lanczos filtering for audio resampling instead of linear-interpolation (Lanczos is more performance-intensive, but higher quality)" OFF)
option(FREETYPE_FONTS "Use FreeType2 to render the DejaVu Mono (English) or Migu1M (Japanese) fonts, instead of using pre-rendered copies of Courier New (English) and MS Gothic (Japanese)" OFF)
set(BACKEND_RENDERER "SDLTexture" CACHE STRING "Which renderer the game should use: 'OpenGL3' for an OpenGL 3.2 renderer, 'OpenGLES2' for an OpenGL ES 2.0 renderer, 'SDLTexture' for SDL2's hardware-accelerated Texture API, 'SDLSurface' for SDL2's software-rendered Surface API, 'Wii U' for the Wii U's hardware-accelerated GX2 API, '3DS' for the 3DS's hardware accelerated Citro2D/Citro3D API, or 'Software' for a handwritten software renderer")
set(BACKEND_AUDIO "SDL2" CACHE STRING "Which audio backend the game should use: 'SDL2', 'SDL1', 'miniaudio', 'WiiU-Hardware', 'WiiU-Software', '3DS-Hardware', '3DS-Software', or 'Null'")
set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'SDL1', 'GLFW3', 'WiiU', '3DS', or 'Null'")
option(FIX_MAJOR_BUGS "Fix bugs that invoke undefined behaviour or cause memory leaks" OFF)
option(DEBUG_SAVE "Re-enable the dummied-out 'Debug Save' option, and the ability to drag-and-drop save files onto the window" OFF)
option(LTO "Enable link-time optimisation" OFF)
option(PKG_CONFIG_STATIC_LIBS "On platforms with pkg-config, static-link the dependencies (good for Windows builds, so you don't need to bundle DLL files)" OFF)
option(MSVC_LINK_STATIC_RUNTIME "Link the static MSVC runtime library (Visual Studio only)" OFF)
option(FORCE_LOCAL_LIBS "Compile the built-in versions of SDL2, GLFW3, and FreeType instead of using the system-provided ones" OFF)
option(MSVC_LINK_STATIC_RUNTIME "Link the static MSVC runtime library" OFF)
#########
@ -43,13 +29,10 @@ project(CSE2 LANGUAGES C CXX)
add_executable(CSE2 WIN32
"${ASSETS_DIRECTORY}/resources/CSE2.rc"
"${ASSETS_DIRECTORY}/resources/CSE2.manifest"
"src/ArmsItem.cpp"
"src/ArmsItem.h"
"src/Back.cpp"
"src/Back.h"
"src/Bitmap.cpp"
"src/Bitmap.h"
"src/Boss.cpp"
"src/Boss.h"
"src/BossAlmo1.cpp"
@ -81,6 +64,8 @@ add_executable(CSE2 WIN32
"src/CommonDefines.h"
"src/Config.cpp"
"src/Config.h"
"src/Dialog.cpp"
"src/Dialog.h"
"src/Draw.cpp"
"src/Draw.h"
"src/Ending.cpp"
@ -89,14 +74,10 @@ add_executable(CSE2 WIN32
"src/Escape.h"
"src/Fade.cpp"
"src/Fade.h"
"src/File.cpp"
"src/File.h"
"src/Flags.cpp"
"src/Flags.h"
"src/Flash.cpp"
"src/Flash.h"
"src/Font.cpp"
"src/Font.h"
"src/Frame.cpp"
"src/Frame.h"
"src/Game.cpp"
@ -154,10 +135,6 @@ add_executable(CSE2 WIN32
"src/PixTone.h"
"src/Profile.cpp"
"src/Profile.h"
"src/Random.cpp"
"src/Random.h"
"src/Resource.cpp"
"src/Resource.h"
"src/SelStage.cpp"
"src/SelStage.h"
"src/Shoot.cpp"
@ -175,79 +152,6 @@ add_executable(CSE2 WIN32
"src/ValueView.cpp"
"src/ValueView.h"
"src/WindowsWrapper.h"
"src/Backends/Audio.h"
"src/Backends/Controller.h"
"src/Backends/Misc.h"
"src/Backends/Rendering.h"
)
set(RESOURCES
"BITMAP/Credit01.bmp"
"BITMAP/Credit02.bmp"
"BITMAP/Credit03.bmp"
"BITMAP/Credit04.bmp"
"BITMAP/Credit05.bmp"
"BITMAP/Credit06.bmp"
"BITMAP/Credit07.bmp"
"BITMAP/Credit08.bmp"
"BITMAP/Credit09.bmp"
"BITMAP/Credit10.bmp"
"BITMAP/Credit11.bmp"
"BITMAP/Credit12.bmp"
"BITMAP/Credit14.bmp"
"BITMAP/Credit15.bmp"
"BITMAP/Credit16.bmp"
"BITMAP/Credit17.bmp"
"BITMAP/Credit18.bmp"
"CURSOR/CURSOR_IKA.png"
"CURSOR/CURSOR_NORMAL.png"
"ORG/Access.org"
"ORG/Anzen.org"
"ORG/Balcony.org"
"ORG/Ballos.org"
"ORG/BreakDown.org"
"ORG/Cemetery.org"
"ORG/Curly.org"
"ORG/Dr.org"
"ORG/Ending.org"
"ORG/Escape.org"
"ORG/Fanfale1.org"
"ORG/Fanfale2.org"
"ORG/Fanfale3.org"
"ORG/FireEye.org"
"ORG/Gameover.org"
"ORG/Ginsuke.org"
"ORG/Grand.org"
"ORG/Gravity.org"
"ORG/Hell.org"
"ORG/ironH.org"
"ORG/Jenka.org"
"ORG/Jenka2.org"
"ORG/Kodou.org"
"ORG/LastBtl3.org"
"ORG/LastBtl.org"
"ORG/LastCave.org"
"ORG/Marine.org"
"ORG/Maze.org"
"ORG/MDown2.org"
"ORG/Mura.org"
"ORG/Oside.org"
"ORG/Plant.org"
"ORG/quiet.org"
"ORG/Requiem.org"
"ORG/Toroko.org"
"ORG/Vivi.org"
"ORG/Wanpak2.org"
"ORG/Wanpaku.org"
"ORG/Weed.org"
"ORG/White.org"
"ORG/XXXX.org"
"ORG/Zonbie.org"
"WAVE/Wave.dat"
)
list(APPEND CMAKE_MODULE_PATH
"${CMAKE_SOURCE_DIR}/cmake"
)
@ -257,11 +161,9 @@ list(APPEND CMAKE_MODULE_PATH
if(JAPANESE)
set(BUILD_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/game_japanese")
list(APPEND RESOURCES "BITMAP/pixel_jp.bmp")
target_compile_definitions(CSE2 PRIVATE JAPANESE)
else()
set(BUILD_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/game_english")
list(APPEND RESOURCES "BITMAP/pixel.bmp")
endif()
if(FIX_BUGS)
@ -276,18 +178,6 @@ if(DEBUG_SAVE)
target_compile_definitions(CSE2 PRIVATE DEBUG_SAVE)
endif()
if(LANCZOS_RESAMPLER)
target_compile_definitions(CSE2 PRIVATE LANCZOS_RESAMPLER)
endif()
if(FREETYPE_FONTS)
target_compile_definitions(CSE2 PRIVATE FREETYPE_FONTS)
endif()
if(PKG_CONFIG_STATIC_LIBS)
target_link_options(CSE2 PRIVATE "-static")
endif()
if(LTO)
include(CheckIPOSupported)
@ -309,161 +199,6 @@ if(MSVC AND MSVC_LINK_STATIC_RUNTIME)
endforeach()
endif()
if(BACKEND_RENDERER MATCHES "OpenGL3")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/OpenGL3.cpp")
elseif(BACKEND_RENDERER MATCHES "OpenGLES2")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/OpenGLES2.cpp")
elseif(BACKEND_RENDERER MATCHES "SDLTexture")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/SDLTexture.cpp")
elseif(BACKEND_RENDERER MATCHES "SDLSurface")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/SDLSurface.cpp")
elseif(BACKEND_RENDERER MATCHES "WiiU")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/WiiU.cpp")
elseif(BACKEND_RENDERER MATCHES "3DS")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/3DS.cpp")
target_link_libraries(CSE2 PRIVATE "${CTRU_ROOT}/lib/libcitro2d.a" "${CTRU_ROOT}/lib/libcitro3d.a")
elseif(BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Software.cpp")
else()
message(FATAL_ERROR "Invalid BACKEND_RENDERER selected")
endif()
if(BACKEND_AUDIO MATCHES "SDL2")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/SoftwareMixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.h"
"src/Backends/Audio/SoftwareMixer/Backend.h"
"src/Backends/Audio/SoftwareMixer/SDL2.cpp"
)
elseif(BACKEND_AUDIO MATCHES "SDL1")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/SoftwareMixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.h"
"src/Backends/Audio/SoftwareMixer/Backend.h"
"src/Backends/Audio/SoftwareMixer/SDL1.cpp"
)
elseif(BACKEND_AUDIO MATCHES "miniaudio")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/SoftwareMixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.h"
"src/Backends/Audio/SoftwareMixer/Backend.h"
"src/Backends/Audio/SoftwareMixer/miniaudio.cpp"
)
# Link libdl, libm, and libpthread
include(CheckLibraryExists)
check_library_exists(m pow "" LIBM)
if(LIBM)
target_link_libraries(CSE2 PRIVATE m)
endif()
check_library_exists(pthread pthread_create "" LIBPTHREAD)
if(LIBPTHREAD)
target_link_libraries(CSE2 PRIVATE pthread)
endif()
target_link_libraries(CSE2 PRIVATE ${CMAKE_DL_LIBS})
elseif(BACKEND_AUDIO MATCHES "WiiU-Hardware")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/WiiU.cpp"
)
elseif(BACKEND_AUDIO MATCHES "WiiU-Software")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/SoftwareMixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.h"
"src/Backends/Audio/SoftwareMixer/Backend.h"
"src/Backends/Audio/SoftwareMixer/WiiU.cpp"
)
elseif(BACKEND_AUDIO MATCHES "3DS-Hardware")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/3DS.cpp"
)
elseif(BACKEND_AUDIO MATCHES "3DS-Software")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/SoftwareMixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.cpp"
"src/Backends/Audio/SoftwareMixer/Mixer.h"
"src/Backends/Audio/SoftwareMixer/Backend.h"
"src/Backends/Audio/SoftwareMixer/3DS.cpp"
)
elseif(BACKEND_AUDIO MATCHES "Null")
target_sources(CSE2 PRIVATE
"src/Backends/Audio/Null.cpp"
)
else()
message(FATAL_ERROR "Invalid BACKEND_AUDIO selected")
endif()
if(BACKEND_PLATFORM MATCHES "SDL2")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/SDL.cpp"
"src/Backends/Platform/SDL2.cpp"
"src/Backends/Shared/SDL.h"
)
elseif(BACKEND_PLATFORM MATCHES "SDL1")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/SDL.cpp"
"src/Backends/Platform/SDL1.cpp"
"src/Backends/Shared/SDL.h"
)
elseif(BACKEND_PLATFORM MATCHES "GLFW3")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/GLFW3.cpp"
"src/Backends/Platform/GLFW3.cpp"
"src/Backends/Shared/GLFW3.h"
)
elseif(BACKEND_PLATFORM MATCHES "WiiU")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/Null.cpp"
"src/Backends/Platform/WiiU.cpp"
)
elseif(BACKEND_PLATFORM MATCHES "3DS")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/Null.cpp"
"src/Backends/Platform/3DS.cpp"
)
elseif(BACKEND_PLATFORM MATCHES "Null")
target_sources(CSE2 PRIVATE
"src/Backends/Controller/Null.cpp"
"src/Backends/Platform/Null.cpp"
)
endif()
if(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "OpenGL3")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGL3/SDL2.cpp")
elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "OpenGLES2")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGLES2/SDL2.cpp")
elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLTexture")
elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLSurface")
elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL2.cpp")
elseif(BACKEND_PLATFORM MATCHES "SDL1" AND BACKEND_RENDERER MATCHES "OpenGL3")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGL3/SDL1.cpp")
elseif(BACKEND_PLATFORM MATCHES "SDL1" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL1.cpp")
elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "OpenGL3")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGL3/GLFW3.cpp")
elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "OpenGLES2")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGLES2/GLFW3.cpp")
elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/GLFW3.cpp")
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "WiiU")
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/WiiU.cpp")
elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "3DS")
elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/3DS.cpp")
elseif(BACKEND_PLATFORM MATCHES "Null" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/Null.cpp")
else()
message(FATAL_ERROR "Invalid BACKEND_PLATFORM/BACKEND_RENDERER combination")
endif()
##########
# Tweaks #
@ -476,14 +211,6 @@ if(MSVC)
# Make it so source files are recognized as UTF-8 by MSVC
target_compile_options(CSE2 PRIVATE "/utf-8")
# Use `main` instead of `WinMain`
set_target_properties(CSE2 PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup")
endif()
# On Windows, we use native icons instead
if(NOT WIN32)
list(APPEND RESOURCES "ICON/ICON_MINI.png")
endif()
@ -498,14 +225,12 @@ set_target_properties(CSE2 PROPERTIES
C_EXTENSIONS OFF
)
if(NOT BACKEND_PLATFORM MATCHES "WiiU" AND NOT BACKEND_PLATFORM MATCHES "3DS")
# Force strict C++98
set_target_properties(CSE2 PROPERTIES
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
endif()
# Force strict C++98
set_target_properties(CSE2 PROPERTIES
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
# Name debug builds "CSE2_debug", to distinguish them
set_target_properties(CSE2 PROPERTIES DEBUG_OUTPUT_NAME "CSE2_debug")
@ -524,258 +249,12 @@ set_target_properties(CSE2 PROPERTIES
# Dependencies #
################
if(NOT FORCE_LOCAL_LIBS)
find_package(PkgConfig QUIET)
endif()
if(BACKEND_PLATFORM MATCHES "GLFW3")
if(NOT FORCE_LOCAL_LIBS)
find_package(glfw3)
if (PKG_CONFIG_FOUND)
pkg_check_modules(glfw3 QUIET IMPORTED_TARGET glfw3)
endif()
endif()
if(TARGET PkgConfig::glfw3)
# pkg-config
if (PKG_CONFIG_STATIC_LIBS)
message(STATUS "Using system GLFW3 (pkg-config, static)")
target_compile_options(CSE2 PRIVATE ${glfw3_STATIC_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${glfw3_STATIC_LDFLAGS})
else()
message(STATUS "Using system GLFW3 (pkg-config, dynamic)")
target_compile_options(CSE2 PRIVATE ${glfw3_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${glfw3_LDFLAGS})
endif()
elseif(TARGET glfw)
# CMake
message(STATUS "Using system GLFW3 (CMake)")
target_link_libraries(CSE2 PRIVATE glfw)
else()
# Compile it ourselves
message(STATUS "Using local GLFW3")
set(GLFW_BUILD_EXAMPLES OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "" FORCE)
set(GLFW_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory("external/glfw" EXCLUDE_FROM_ALL)
target_link_libraries(CSE2 PRIVATE glfw)
endif()
endif()
if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2")
if(NOT FORCE_LOCAL_LIBS)
find_package(SDL2)
if (PKG_CONFIG_FOUND)
pkg_check_modules(sdl2 QUIET IMPORTED_TARGET sdl2)
endif()
endif()
if(TARGET PkgConfig::sdl2)
# pkg-config
if (PKG_CONFIG_STATIC_LIBS)
message(STATUS "Using system SDL2 (pkg-config, static)")
# Do not link libSDL2main.a, otherwise we get weird linker errors about SDL_main not being found.
# We don't need SDL2's WinMain->main shim anyway, so we can just ignore it.
list(REMOVE_ITEM sdl2_STATIC_CFLAGS "-Dmain=SDL_main")
list(REMOVE_ITEM sdl2_STATIC_LDFLAGS "-lSDL2main")
target_compile_options(CSE2 PRIVATE ${sdl2_STATIC_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${sdl2_STATIC_LDFLAGS})
else()
message(STATUS "Using system SDL2 (pkg-config, dynamic)")
# Do not link libSDL2main.a, otherwise we get weird linker errors about SDL_main not being found.
# We don't need SDL2's WinMain->main shim anyway, so we can just ignore it.
list(REMOVE_ITEM sdl2_CFLAGS "-Dmain=SDL_main")
list(REMOVE_ITEM sdl2_LDFLAGS "-lSDL2main")
target_compile_options(CSE2 PRIVATE ${sdl2_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${sdl2_LDFLAGS})
endif()
elseif(TARGET SDL2::SDL2)
# CMake-generated config (Arch, vcpkg, Raspbian)
message(STATUS "Using system SDL2 (CMake, dynamic)")
target_link_libraries(CSE2 PRIVATE SDL2::SDL2)
elseif(TARGET SDL2::SDL2-static)
# CMake-generated config (Arch, vcpkg, Raspbian)
message(STATUS "Using system SDL2 (CMake, static)")
target_link_libraries(CSE2 PRIVATE SDL2::SDL2-static)
elseif(SDL2_FOUND)
# Autotools-generated config (MSYS2)
message(STATUS "Using system SDL2 (Autotools)")
target_include_directories(CSE2 PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(CSE2 PRIVATE ${SDL2_LIBRARIES})
else()
# Compile it ourselves
message(STATUS "Using local SDL2")
set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
if(MSVC)
set(LIBC ON CACHE INTERNAL "" FORCE) # Needed to prevent possible 'symbol already defined' errors
endif()
add_subdirectory("external/SDL2" EXCLUDE_FROM_ALL)
target_link_libraries(CSE2 PRIVATE SDL2-static)
endif()
endif()
if(BACKEND_PLATFORM MATCHES "SDL1" OR BACKEND_AUDIO MATCHES "SDL1")
if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2")
message(FATAL_ERROR "SDL1 and SDL2 cannot be used simultaneously!")
endif()
find_package(SDL 1.2.15)
if (PKG_CONFIG_FOUND)
pkg_check_modules(sdl QUIET IMPORTED_TARGET sdl)
endif()
if(TARGET PkgConfig::sdl)
# pkg-config
if (PKG_CONFIG_STATIC_LIBS)
message(STATUS "Using system SDL1 (pkg-config, static)")
# Do not link libSDLmain.a, otherwise we get weird linker errors about SDL_main not being found.
# We don't need SDL's WinMain->main shim anyway, so we can just ignore it.
list(REMOVE_ITEM sdl_STATIC_CFLAGS "-Dmain=SDL_main")
list(REMOVE_ITEM sdl_STATIC_LDFLAGS "-lSDLmain")
target_compile_options(CSE2 PRIVATE ${sdl_STATIC_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${sdl_STATIC_LDFLAGS})
else()
message(STATUS "Using system SDL1 (pkg-config, dynamic)")
# Do not link libSDLmain.a, otherwise we get weird linker errors about SDL_main not being found.
# We don't need SDL's WinMain->main shim anyway, so we can just ignore it.
list(REMOVE_ITEM sdl_CFLAGS "-Dmain=SDL_main")
list(REMOVE_ITEM sdl_LDFLAGS "-lSDLmain")
target_compile_options(CSE2 PRIVATE ${sdl_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${sdl_LDFLAGS})
endif()
elseif(SDL_FOUND)
message(STATUS "Using system SDL1 (CMake)")
target_include_directories(CSE2 PRIVATE ${SDL_INCLUDE_DIR})
target_link_libraries(CSE2 PRIVATE ${SDL_LIBRARY})
else()
message(FATAL_ERROR "SDL1 not installed!")
endif()
endif()
if(FREETYPE_FONTS)
if(NOT FORCE_LOCAL_LIBS)
find_package(Freetype)
if (PKG_CONFIG_FOUND)
pkg_check_modules(freetype2 QUIET IMPORTED_TARGET freetype2)
endif()
endif()
if(TARGET PkgConfig::freetype2)
# pkg-config
if (PKG_CONFIG_STATIC_LIBS)
message(STATUS "Using system FreeType (pkg-config, static)")
target_compile_options(CSE2 PRIVATE ${freetype2_STATIC_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${freetype2_STATIC_LDFLAGS})
else()
message(STATUS "Using system FreeType (pkg-config, dynamic)")
target_compile_options(CSE2 PRIVATE ${freetype2_CFLAGS})
target_link_libraries(CSE2 PRIVATE ${freetype2_LDFLAGS})
endif()
elseif(FREETYPE_FOUND)
message(STATUS "Using system FreeType (CMake)")
target_include_directories(CSE2 PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(CSE2 PRIVATE ${FREETYPE_LIBRARIES})
else()
# Compile it ourselves
message(STATUS "Using local FreeType")
if(FORCE_LOCAL_LIBS)
set(CMAKE_DISABLE_FIND_PACKAGE_HarfBuzz ON CACHE INTERNAL "" FORCE)
set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB ON CACHE INTERNAL "" FORCE)
set(CMAKE_DISABLE_FIND_PACKAGE_PNG ON CACHE INTERNAL "" FORCE)
set(CMAKE_DISABLE_FIND_PACKAGE_BZip2 ON CACHE INTERNAL "" FORCE)
set(CMAKE_DISABLE_FIND_PACKAGE_BrotliDec ON CACHE INTERNAL "" FORCE)
endif()
add_subdirectory("external/freetype" EXCLUDE_FROM_ALL)
target_link_libraries(CSE2 PRIVATE freetype)
endif()
endif()
if(BACKEND_RENDERER MATCHES "OpenGL3")
add_subdirectory("external/glad" EXCLUDE_FROM_ALL)
target_link_libraries(CSE2 PRIVATE glad)
endif()
if(BACKEND_RENDERER MATCHES "OpenGLES2")
find_package(OpenGLES2 REQUIRED)
target_include_directories(CSE2 PRIVATE ${OPENGLES2_INCLUDE_DIR})
target_link_libraries(CSE2 PRIVATE ${OPENGLES2_LIBRARIES})
endif()
if(BACKEND_RENDERER MATCHES "OpenGL3" OR (BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "Software"))
if (CMAKE_VERSION GREATER_EQUAL 3.11)
cmake_policy(SET CMP0072 NEW)
endif()
find_package(OpenGL REQUIRED)
target_link_libraries(CSE2 PRIVATE OpenGL::GL)
endif()
#######################
# Resource conversion #
#######################
# Build bin2h externally, so it isn't cross-compiled when CSE2 is (Emscripten, cross-GCC, MinGW on Linux, etc.)
include(ExternalProject)
ExternalProject_Add(bin2h
SOURCE_DIR "${CMAKE_SOURCE_DIR}/bin2h"
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""
BUILD_BYPRODUCTS "<INSTALL_DIR>/bin/bin2h"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_BUILD_TYPE=Release
INSTALL_COMMAND
${CMAKE_COMMAND} --build . --config Release --target install
)
ExternalProject_Get_Property(bin2h INSTALL_DIR)
add_executable(bin2h_tool IMPORTED)
add_dependencies(bin2h_tool bin2h)
set_target_properties(bin2h_tool PROPERTIES IMPORTED_LOCATION "${INSTALL_DIR}/bin/bin2h")
# Convert resources to header files
foreach(FILENAME IN LISTS RESOURCES)
set(IN_DIR "${ASSETS_DIRECTORY}/resources")
set(OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/Resource")
get_filename_component(DIRECTORY "${FILENAME}" DIRECTORY)
add_custom_command(
OUTPUT "${OUT_DIR}/${FILENAME}.h"
COMMAND ${CMAKE_COMMAND} -E make_directory "${OUT_DIR}/${DIRECTORY}"
COMMAND bin2h_tool "${IN_DIR}/${FILENAME}" "${OUT_DIR}/${FILENAME}.h"
DEPENDS bin2h_tool "${IN_DIR}/${FILENAME}"
)
target_sources(CSE2 PRIVATE "${OUT_DIR}/${FILENAME}.h")
endforeach()
############
# DoConfig #
############
if(DOCONFIG)
add_subdirectory("DoConfig")
# Name debug builds "DoConfig_debug", to distinguish them
set_target_properties(DoConfig PROPERTIES DEBUG_OUTPUT_NAME "DoConfig_debug")
# Send executable to the build_en/build_jp directory
set_target_properties(DoConfig PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BUILD_DIRECTORY}
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BUILD_DIRECTORY}
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${BUILD_DIRECTORY}
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${BUILD_DIRECTORY}
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BUILD_DIRECTORY}
)
endif()
if(RISCOS)
include(RISCOSApp)
# Link libraries
target_link_libraries(CSE2 PRIVATE ddraw dsound version shlwapi imm32 winmm dxguid gdi32)
# Newer MSVC is missing `dinput.lib`
if(MSVC AND NOT (MSVC_VERSION LESS 1500))
target_link_libraries(CSE2 PRIVATE dinput8)
else()
target_link_libraries(CSE2 PRIVATE dinput)
endif()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

View File

@ -1,134 +0,0 @@
cmake_minimum_required(VERSION 3.8)
option(DOCONFIG_LEGACY_OPENGL "Use OpenGL 2.1 instead of 3.2" OFF)
option(PKG_CONFIG_STATIC_LIBS "On platforms with pkg-config, static-link the dependencies (good for Windows builds, so you don't need to bundle DLL files)" OFF)
option(MSVC_LINK_STATIC_RUNTIME "Link the static MSVC runtime library (Visual Studio only)" OFF)
option(FORCE_LOCAL_LIBS "Compile the built-in version of GLFW3 instead of using the system-provided one" OFF)
project(DoConfig LANGUAGES C CXX)
add_executable(DoConfig WIN32
"icon.rc"
"DoConfig.cpp"
"imgui/imconfig.h"
"imgui/imgui.cpp"
"imgui/imgui.h"
"imgui/imgui_demo.cpp"
"imgui/imgui_draw.cpp"
"imgui/imgui_impl_glfw.cpp"
"imgui/imgui_impl_glfw.h"
"imgui/imgui_internal.h"
"imgui/imgui_widgets.cpp"
"imgui/imstb_rectpack.h"
"imgui/imstb_textedit.h"
"imgui/imstb_truetype.h"
)
set_target_properties(DoConfig PROPERTIES
C_STANDARD 90
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
target_link_libraries(DoConfig PRIVATE ${CMAKE_DL_LIBS})
target_include_directories(DoConfig PRIVATE "../external/glad/include")
target_compile_definitions(DoConfig PRIVATE IMGUI_IMPL_OPENGL_LOADER_GLAD)
if(DOCONFIG_LEGACY_OPENGL)
target_compile_definitions(DoConfig PRIVATE LEGACY_OPENGL)
target_sources(DoConfig PRIVATE
"imgui/imgui_impl_opengl2.cpp"
"imgui/imgui_impl_opengl2.h"
)
else()
target_sources(DoConfig PRIVATE
"imgui/imgui_impl_opengl3.cpp"
"imgui/imgui_impl_opengl3.h"
)
endif()
if(PKG_CONFIG_STATIC_LIBS)
target_link_options(DoConfig PRIVATE "-static")
endif()
if(MSVC)
# Disable warnings that normally fire up on MSVC when using "unsafe" functions instead of using MSVC's "safe" _s functions
target_compile_definitions(DoConfig PRIVATE _CRT_SECURE_NO_WARNINGS)
# Use `main` instead of `WinMain`
set_target_properties(DoConfig PROPERTIES LINK_FLAGS "/ENTRY:mainCRTStartup")
# This is messy as hell, and has been replaced by CMAKE_MSVC_RUNTIME_LIBRARY,
# but that's a very recent CMake addition, so we're still doing it this way for now
if(MSVC_LINK_STATIC_RUNTIME)
# Statically-link the CRT (vcpkg static libs do this)
foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach()
endif()
endif()
################
# Dependencies #
################
# glad
add_subdirectory("../external/glad" "glad" EXCLUDE_FROM_ALL)
target_link_libraries(DoConfig PRIVATE glad)
if (CMAKE_VERSION GREATER_EQUAL 3.11)
cmake_policy(SET CMP0072 NEW)
endif()
find_package(OpenGL REQUIRED)
target_link_libraries(DoConfig PRIVATE OpenGL::GL)
# GLFW3
if(NOT FORCE_LOCAL_LIBS)
find_package(PkgConfig QUIET)
endif()
if(NOT FORCE_LOCAL_LIBS)
find_package(glfw3)
if (PKG_CONFIG_FOUND)
pkg_check_modules(glfw3 QUIET IMPORTED_TARGET glfw3)
endif()
endif()
if(TARGET PkgConfig::glfw3)
# pkg-config
if (PKG_CONFIG_STATIC_LIBS)
message(STATUS "Using system GLFW3 (pkg-config, static)")
target_compile_options(DoConfig PRIVATE ${glfw3_STATIC_CFLAGS})
target_link_libraries(DoConfig PRIVATE ${glfw3_STATIC_LDFLAGS})
else()
message(STATUS "Using system GLFW3 (pkg-config, dynamic)")
target_compile_options(DoConfig PRIVATE ${glfw3_CFLAGS})
target_link_libraries(DoConfig PRIVATE ${glfw3_LDFLAGS})
endif()
elseif(TARGET glfw)
# CMake
message(STATUS "Using system GLFW3 (CMake)")
target_link_libraries(DoConfig PRIVATE glfw)
else()
# Compile it ourselves
message(STATUS "Using local GLFW3")
set(GLFW_BUILD_EXAMPLES OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "" FORCE)
set(GLFW_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory("../external/glfw" "glfw" EXCLUDE_FROM_ALL)
target_link_libraries(DoConfig PRIVATE glfw)
endif()

View File

@ -1,329 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glad/glad.h"
#include <GLFW/glfw3.h>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_glfw.h"
#ifdef LEGACY_OPENGL
#include "imgui/imgui_impl_opengl2.h"
#else
#include "imgui/imgui_impl_opengl3.h"
#endif
#define WINDOW_WIDTH 360
#define WINDOW_HEIGHT 290
struct Config
{
char proof[0x20];
char font_name[0x40];
int move_button_mode;
int attack_button_mode;
int ok_button_mode;
int display_mode;
bool bJoystick;
int joystick_button[8];
};
static const char *proof = "DOUKUTSU20041206";
int main(int argc, char *argv[])
{
(void)argc;
char *config_path;
for (size_t i = strlen(argv[0]);; --i)
{
if (i == 0 || argv[0][i - 1] == '\\' || argv[0][i - 1] == '/')
{
const char config_string[] = "Config.dat";
config_path = (char*)malloc(i + sizeof(config_string));
if (config_path == NULL)
return 1;
memcpy(config_path, argv[0], i);
memcpy(config_path + i, config_string, sizeof(config_string)); // Will copy null-character
break;
}
}
/////////////////////
// Initialise GLFW //
/////////////////////
if (glfwInit())
{
#ifdef LEGACY_OPENGL
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#else
const char *glsl_version = "#version 150 core";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endif
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
GLFWwindow *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "DoConfig - Doukutsu Monogatari Settings", NULL, NULL);
if (window != NULL)
{
glfwMakeContextCurrent(window);
glfwSwapInterval(2);
if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
// Check if the platform supports the version of OpenGL we want
#ifdef LEGACY_OPENGL
if (GLAD_GL_VERSION_2_1)
#else
if (GLAD_GL_VERSION_3_2)
#endif
{
///////////////////////////
// Initialise Dear ImGui //
///////////////////////////
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
io.IniFilename = NULL; // Disable `imgui.ini`
ImGui_ImplGlfw_InitForOpenGL(window, true);
#ifdef LEGACY_OPENGL
ImGui_ImplOpenGL2_Init();
#else
ImGui_ImplOpenGL3_Init(glsl_version);
#endif
/////////////////////
// Load Config.dat //
/////////////////////
Config configuration;
FILE *file = fopen(config_path, "rb");
if (file != NULL)
{
// Read from file
fread(configuration.proof, 1, sizeof(configuration.proof), file);
fread(configuration.font_name, 1, sizeof(configuration.font_name), file);
configuration.move_button_mode = fgetc(file);
fseek(file, 3, SEEK_CUR);
configuration.attack_button_mode = fgetc(file);
fseek(file, 3, SEEK_CUR);
configuration.ok_button_mode = fgetc(file);
fseek(file, 3, SEEK_CUR);
configuration.display_mode = fgetc(file);
fseek(file, 3, SEEK_CUR);
configuration.bJoystick = fgetc(file);
for (unsigned int i = 0; i < 8; ++i)
{
const int decode_table[6] = {0, 1, 2, 4, 5, 3};
fseek(file, 3, SEEK_CUR);
configuration.joystick_button[i] = decode_table[fgetc(file) - 1];
}
fclose(file);
}
if (file == NULL || memcmp(configuration.proof, proof, strlen(proof)))
{
// Reset to defaults
memset(&configuration, 0, sizeof(configuration));
strcpy(configuration.proof, proof);
strcpy(configuration.font_name, "Courier New");
for (unsigned int i = 0; i < 8; ++i)
configuration.joystick_button[i] = i % 6;
}
//////////////
// Mainloop //
//////////////
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
#ifdef LEGACY_OPENGL
ImGui_ImplOpenGL2_NewFrame();
#else
ImGui_ImplOpenGL3_NewFrame();
#endif
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(WINDOW_WIDTH, WINDOW_HEIGHT));
ImGui::Begin("Main window", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground);
if (ImGui::BeginTable("Block1", 2, ImGuiTableFlags_Borders))
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::RadioButton("Arrows for Movement", &configuration.move_button_mode, 0);
ImGui::RadioButton("<>? for Movement", &configuration.move_button_mode, 1);
ImGui::TableSetColumnIndex(1);
ImGui::RadioButton("Jump=Okay", &configuration.ok_button_mode, 0);
ImGui::RadioButton("Attack=Okay", &configuration.ok_button_mode, 1);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::RadioButton("Z=Jump; X=Attack", &configuration.attack_button_mode, 0);
ImGui::RadioButton("X=Jump; Z=Attack", &configuration.attack_button_mode, 1);
ImGui::TableSetColumnIndex(1);
ImGui::SetNextItemWidth(-1.0f);
const char *items[] = {"Fullscreen 16-bit", "Windowed 320x240", "Windowed 640x480", "Fullscreen 24-bit", "Fullscreen 32-bit"};
ImGui::Combo("", &configuration.display_mode, items, IM_ARRAYSIZE(items));
ImGui::Checkbox("Use Joypad", &configuration.bJoystick);
ImGui::EndTable();
}
// Joypad binding
if (ImGui::BeginTable("Joypad binding", 9))
{
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 60.0f);
for (int y = 0; y < 7; ++y)
{
ImGui::TableNextRow();
if (y == 0)
{
for (int x = 1; x < 9; ++x)
{
ImGui::TableSetColumnIndex(x);
ImGui::Text(" %d", x);
}
}
else
{
for (int x = 0; x < 9; ++x)
{
ImGui::TableSetColumnIndex(x);
if (x == 0)
{
const char *inputs[6] = {"Jump:", "Attack:", "Weapon+:", "Weapon-:", "Items:", "Map:"};
ImGui::Text("%s", inputs[y - 1]);
}
else
{
static char name_buffer[5] = {'#', '#', '0', '0', '\0'};
name_buffer[2] = '0' + x;
name_buffer[3] = '0' + y;
ImGui::RadioButton(name_buffer, &configuration.joystick_button[x - 1], y - 1);
}
}
}
}
ImGui::EndTable();
if (ImGui::Button("Okay", ImVec2(ImGui::GetContentRegionAvail().x / 2, 0.0f)))
{
glfwSetWindowShouldClose(window, 1);
// Save to file
FILE *file = fopen(config_path, "wb");
if (file != NULL)
{
fwrite(configuration.proof, 1, sizeof(configuration.proof), file);
fwrite(configuration.font_name, 1, sizeof(configuration.font_name), file);
fputc(configuration.move_button_mode, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
fputc(configuration.attack_button_mode, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
fputc(configuration.ok_button_mode, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
fputc(configuration.display_mode, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
fputc(configuration.bJoystick, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
for (unsigned int i = 0; i < 8; ++i)
{
const int encode_table[6] = {0, 1, 2, 5, 3, 4};
fputc(encode_table[configuration.joystick_button[i]] + 1, file);
fputc(0, file);
fputc(0, file);
fputc(0, file);
}
fclose(file);
}
}
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(ImGui::GetContentRegionAvail().x, 0.0f)))
glfwSetWindowShouldClose(window, 1);
}
ImGui::End();
ImGui::Render();
glClear(GL_COLOR_BUFFER_BIT);
#ifdef LEGACY_OPENGL
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
#else
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
#endif
glfwSwapBuffers(window);
}
}
}
}
#ifdef LEGACY_OPENGL
ImGui_ImplOpenGL2_Shutdown();
#else
ImGui_ImplOpenGL3_Shutdown();
#endif
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
}
free(config_path);
return 0;
}

View File

@ -1 +0,0 @@
GLFW_ICON ICON "1.ico"

View File

@ -1,108 +0,0 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h)
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include
// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points.
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of imgui cpp files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library.
// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
// This adds a small runtime cost which is why it is not enabled by default.
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
}
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,369 +0,0 @@
// dear imgui: Platform Binding for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_glfw.h"
// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
#undef APIENTRY
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
#endif
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
#else
#define GLFW_HAS_NEW_CURSORS (0)
#endif
// Data
enum GlfwClientApi
{
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
};
static GLFWwindow* g_Window = NULL; // Main window
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_InstalledCallbacks = false;
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
}
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
{
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
if (g_PrevUserCallbackMousebutton != NULL)
g_PrevUserCallbackMousebutton(window, button, action, mods);
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
if (g_PrevUserCallbackScroll != NULL)
g_PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (g_PrevUserCallbackKey != NULL)
g_PrevUserCallbackKey(window, key, scancode, action, mods);
ImGuiIO& io = ImGui::GetIO();
if (action == GLFW_PRESS)
io.KeysDown[key] = true;
if (action == GLFW_RELEASE)
io.KeysDown[key] = false;
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
#ifdef _WIN32
io.KeySuper = false;
#else
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
#endif
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
if (g_PrevUserCallbackChar != NULL)
g_PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter(c);
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
g_Window = window;
g_Time = 0.0;
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_glfw";
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = g_Window;
#if defined(_WIN32)
io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
#endif
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
#if GLFW_HAS_NEW_CURSORS
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
#else
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
#endif
glfwSetErrorCallback(prev_error_callback);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL;
g_PrevUserCallbackKey = NULL;
g_PrevUserCallbackChar = NULL;
if (install_callbacks)
{
g_InstalledCallbacks = true;
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
}
g_ClientApi = client_api;
return true;
}
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
}
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
}
void ImGui_ImplGlfw_Shutdown()
{
if (g_InstalledCallbacks)
{
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
g_InstalledCallbacks = false;
}
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
{
glfwDestroyCursor(g_MouseCursors[cursor_n]);
g_MouseCursors[cursor_n] = NULL;
}
g_ClientApi = GlfwClientApi_Unknown;
}
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
// Update buttons
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
g_MouseJustPressed[i] = false;
}
// Update mouse position
const ImVec2 mouse_pos_backup = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
#ifdef __EMSCRIPTEN__
const bool focused = true; // Emscripten
#else
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
#endif
if (focused)
{
if (io.WantSetMousePos)
{
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
}
else
{
double mouse_x, mouse_y;
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
}
}
}
static void ImGui_ImplGlfw_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
else
{
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(g_Window, &w, &h);
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step
double current_time = glfwGetTime();
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
}

View File

@ -1,35 +0,0 @@
// dear imgui: Platform Binding for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// About GLSL version:
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct GLFWwindow;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);

View File

@ -1,248 +0,0 @@
// dear imgui: Renderer for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-01-23: OpenGL: Explicitly backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself.
// 2017-09-01: OpenGL: Save and restore current polygon mode.
// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
#include "imgui.h"
#include "imgui_impl_opengl2.h"
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling
#if defined(_WIN32) && !defined(APIENTRY)
#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
#endif
#if defined(_WIN32) && !defined(WINGDIAPI)
#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this
#endif
#if defined(__APPLE__)
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
// OpenGL Data
static GLuint g_FontTexture = 0;
// Functions
bool ImGui_ImplOpenGL2_Init()
{
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl2";
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
ImGui_ImplOpenGL2_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL2_NewFrame()
{
if (!g_FontTexture)
ImGui_ImplOpenGL2_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
// you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function:
// GLint last_program;
// glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
// glUseProgram(0);
// ImGui_ImplOpenGL2_RenderDrawData(...);
// glUseProgram(last_program)
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}
// OpenGL2 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width == 0 || fb_height == 0)
return;
// Backup GL state
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
// Setup desired GL state
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
}
idx_buffer += pcmd->ElemCount;
}
}
// Restore modified GL state
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode);
}
bool ImGui_ImplOpenGL2_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL2_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
{
return ImGui_ImplOpenGL2_CreateFontsTexture();
}
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
{
ImGui_ImplOpenGL2_DestroyFontsTexture();
}

View File

@ -1,31 +0,0 @@
// dear imgui: Renderer for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();

View File

@ -1,677 +0,0 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
//----------------------------------------
// OpenGL GLSL GLSL
// version version string
//----------------------------------------
// 2.0 110 "#version 110"
// 2.1 120 "#version 120"
// 3.0 130 "#version 130"
// 3.1 140 "#version 140"
// 3.2 150 "#version 150"
// 3.3 330 "#version 330 core"
// 4.0 400 "#version 400 core"
// 4.1 410 "#version 410 core"
// 4.2 420 "#version 410 core"
// 4.3 430 "#version 430 core"
// ES 2.0 100 "#version 100" = WebGL 1.0
// ES 3.0 300 "#version 300 es" = WebGL 2.0
//----------------------------------------
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// GL includes
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
#elif defined(IMGUI_IMPL_OPENGL_ES3)
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
#else
#include <GLES3/gl3.h> // Use GL ES 3
#endif
#else
// About Desktop OpenGL function loaders:
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
#include <glbinding/gl/gl.h>
using namespace gl;
#else
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif
#endif
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0
#else
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
#endif
// OpenGL Data
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
static GLuint g_FontTexture = 0;
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
// Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
g_GlVersion = (GLuint)(major * 100 + minor * 10);
#else
g_GlVersion = 200; // GLES 2
#endif
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3";
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
#if defined(IMGUI_IMPL_OPENGL_ES2)
if (glsl_version == NULL)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
if (glsl_version == NULL)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
if (glsl_version == NULL)
glsl_version = "#version 150";
#else
if (glsl_version == NULL)
glsl_version = "#version 130";
#endif
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
// Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected.
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash below.
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
const char* gl_loader = "Unknown";
IM_UNUSED(gl_loader);
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
gl_loader = "GL3W";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
gl_loader = "GLEW";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
gl_loader = "GLAD";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
gl_loader = "glbinding2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
gl_loader = "glbinding3";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
gl_loader = "custom";
#else
gl_loader = "none";
#endif
// Make a dummy GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGui_ImplOpenGL3_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
bool clip_origin_lower_left = true;
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false;
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
const float ortho_projection[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef GL_SAMPLER_BINDING
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif
(void)vertex_array_object;
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(vertex_array_object);
#endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
// OpenGL3 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
return;
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
#ifdef GL_SAMPLER_BINDING
GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler);
#endif
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
#endif
#ifdef GL_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
#ifndef IMGUI_IMPL_OPENGL_ES2
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
}
// Destroy the temporary VAO
#ifndef IMGUI_IMPL_OPENGL_ES2
glDeleteVertexArrays(1, &vertex_array_object);
#endif
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef GL_SAMPLER_BINDING
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
static bool CheckShader(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLint last_vertex_array;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#endif
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
"attribute vec2 Position;\n"
"attribute vec2 UV;\n"
"attribute vec4 Color;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* fragment_shader_glsl_120 =
"#ifdef GL_ES\n"
" precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_300_es =
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"uniform sampler2D Texture;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
const GLchar* fragment_shader = NULL;
if (glsl_version < 130)
{
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
g_ShaderHandle = glCreateProgram();
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
CheckProgram(g_ShaderHandle, "shader program");
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array);
#endif
return true;
}
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
}

View File

@ -1,84 +0,0 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// About Desktop OpenGL function loaders:
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
// About GLSL version:
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
// Backend API
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
// (Optional) Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Specific OpenGL ES versions
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
// Attempt to auto-detect the default Desktop GL loader based on available header files.
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
&& !defined(IMGUI_IMPL_OPENGL_ES3) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
// Try to detect GLES on matching platforms
#if defined(__APPLE__)
#include "TargetConditionals.h"
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
#elif defined(__EMSCRIPTEN__)
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
// Otherwise try to detect supported Desktop OpenGL loaders..
#elif defined(__has_include)
#if __has_include(<GL/glew.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#elif __has_include(<glad/glad.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#elif __has_include(<GL/gl3w.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
#elif __has_include(<glbinding/glbinding.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
#elif __has_include(<glbinding/Binding.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
#else
#error "Cannot detect OpenGL loader!"
#endif
#else
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,639 +0,0 @@
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.00.
// Those changes would need to be pushed into nothings/stb:
// - Added STBRP__CDECL
// Grep for [DEAR IMGUI] to find the changes.
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
#ifdef STBRP_LARGE_RECTS
typedef int stbrp_coord;
#else
typedef unsigned short stbrp_coord;
#endif
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
// [DEAR IMGUI] Added STBRP__CDECL
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
#endif
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
#ifdef STBRP_LARGE_RECTS
context->extra[1].y = (1<<30);
#else
context->extra[1].y = 65535;
#endif
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
STBRP_ASSERT(y <= best_y);
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
#ifdef STBRP_LARGE_RECTS
#define STBRP__MAXVAL 0xffffffff
#else
#define STBRP__MAXVAL 0xffff
#endif
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ MIT License
Copyright (c) 2019 Regan "cuckydev" Green
Copyright (c) 2019-2020 Clownacy
Copyright (c) 2019-2020 Gabriel Ravier
Copyright (c) 2020 Cameron Cawley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

213
Makefile Normal file
View File

@ -0,0 +1,213 @@
WINDRES ?= windres
ASSETS_DIRECTORY = assets
ALL_CXXFLAGS = $(CXXFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
ALL_LIBS = $(LIBS)
ifeq ($(RELEASE), 1)
ALL_CXXFLAGS += -O3 -DNDEBUG
ALL_LDFLAGS += -s
FILENAME_DEF = CSE2.exe
else
ALL_CXXFLAGS += -Og -ggdb3
FILENAME_DEF = CSE2_debug.exe
endif
ifeq ($(JAPANESE), 1)
BUILD_DIRECTORY = game_japanese
ALL_CXXFLAGS += -DJAPANESE
else
BUILD_DIRECTORY = game_english
endif
FILENAME ?= $(FILENAME_DEF)
ifeq ($(FIX_BUGS), 1)
ALL_CXXFLAGS += -DFIX_BUGS -DFIX_MAJOR_BUGS
else
ifeq ($(FIX_MAJOR_BUGS), 1)
ALL_CXXFLAGS += -DFIX_MAJOR_BUGS
endif
endif
ifeq ($(DEBUG_SAVE), 1)
ALL_CXXFLAGS += -DDEBUG_SAVE
endif
ALL_CXXFLAGS += -std=c++98 -MMD -MP -MF $@.d
ALL_LIBS += -lkernel32 -lgdi32 -lddraw -ldinput -ldsound -lversion -lshlwapi -limm32 -lwinmm -ldxguid
ALL_LDFLAGS += -mwindows
ifeq ($(STATIC), 1)
ALL_LDFLAGS += -static
endif
SOURCES = \
src/ArmsItem.cpp \
src/Back.cpp \
src/Boss.cpp \
src/BossAlmo1.cpp \
src/BossAlmo2.cpp \
src/BossBallos.cpp \
src/BossFrog.cpp \
src/BossIronH.cpp \
src/BossLife.cpp \
src/BossOhm.cpp \
src/BossPress.cpp \
src/BossTwinD.cpp \
src/BossX.cpp \
src/BulHit.cpp \
src/Bullet.cpp \
src/Caret.cpp \
src/Config.cpp \
src/Dialog.cpp \
src/Draw.cpp \
src/Ending.cpp \
src/Escape.cpp \
src/Fade.cpp \
src/Flags.cpp \
src/Flash.cpp \
src/Frame.cpp \
src/Game.cpp \
src/Generic.cpp \
src/GenericLoad.cpp \
src/Input.cpp \
src/KeyControl.cpp \
src/Main.cpp \
src/Map.cpp \
src/MapName.cpp \
src/MiniMap.cpp \
src/MyChar.cpp \
src/MycHit.cpp \
src/MycParam.cpp \
src/NpcAct000.cpp \
src/NpcAct020.cpp \
src/NpcAct040.cpp \
src/NpcAct060.cpp \
src/NpcAct080.cpp \
src/NpcAct100.cpp \
src/NpcAct120.cpp \
src/NpcAct140.cpp \
src/NpcAct160.cpp \
src/NpcAct180.cpp \
src/NpcAct200.cpp \
src/NpcAct220.cpp \
src/NpcAct240.cpp \
src/NpcAct260.cpp \
src/NpcAct280.cpp \
src/NpcAct300.cpp \
src/NpcAct320.cpp \
src/NpcAct340.cpp \
src/NpChar.cpp \
src/NpcHit.cpp \
src/NpcTbl.cpp \
src/Organya.cpp \
src/PixTone.cpp \
src/Profile.cpp \
src/SelStage.cpp \
src/Shoot.cpp \
src/Sound.cpp \
src/Stage.cpp \
src/Star.cpp \
src/TextScr.cpp \
src/Triangle.cpp \
src/ValueView.cpp
RESOURCES = \
BITMAP/Credit01.bmp \
BITMAP/Credit02.bmp \
BITMAP/Credit03.bmp \
BITMAP/Credit04.bmp \
BITMAP/Credit05.bmp \
BITMAP/Credit06.bmp \
BITMAP/Credit07.bmp \
BITMAP/Credit08.bmp \
BITMAP/Credit09.bmp \
BITMAP/Credit10.bmp \
BITMAP/Credit11.bmp \
BITMAP/Credit12.bmp \
BITMAP/Credit14.bmp \
BITMAP/Credit15.bmp \
BITMAP/Credit16.bmp \
BITMAP/Credit17.bmp \
BITMAP/Credit18.bmp \
BITMAP/pixel.bmp \
CURSOR/CURSOR_IKA.cur \
CURSOR/CURSOR_NORMAL.cur \
ICON/0.ico \
ICON/ICON_MINI.ico \
ORG/Access.org \
ORG/Anzen.org \
ORG/Balcony.org \
ORG/Ballos.org \
ORG/BreakDown.org \
ORG/Cemetery.org \
ORG/Curly.org \
ORG/Dr.org \
ORG/Ending.org \
ORG/Escape.org \
ORG/Fanfale1.org \
ORG/Fanfale2.org \
ORG/Fanfale3.org \
ORG/FireEye.org \
ORG/Gameover.org \
ORG/Ginsuke.org \
ORG/Grand.org \
ORG/Gravity.org \
ORG/Hell.org \
ORG/ironH.org \
ORG/Jenka.org \
ORG/Jenka2.org \
ORG/Kodou.org \
ORG/LastBtl3.org \
ORG/LastBtl.org \
ORG/LastCave.org \
ORG/Marine.org \
ORG/Maze.org \
ORG/MDown2.org \
ORG/Mura.org \
ORG/Oside.org \
ORG/Plant.org \
ORG/quiet.org \
ORG/Requiem.org \
ORG/Toroko.org \
ORG/Vivi.org \
ORG/Wanpak2.org \
ORG/Wanpaku.org \
ORG/Weed.org \
ORG/White.org \
ORG/XXXX.org \
ORG/Zonbie.org \
WAVE/Wave.dat
OBJECTS = $(addprefix obj/$(FILENAME)/, $(addsuffix .o, $(SOURCES)))
DEPENDENCIES = $(addprefix obj/$(FILENAME)/, $(addsuffix .o.d, $(SOURCES)))
OBJECTS += obj/$(FILENAME)/windows_resources.o
all: $(BUILD_DIRECTORY)/$(FILENAME)
$(info Finished)
$(BUILD_DIRECTORY)/$(FILENAME): $(OBJECTS)
@mkdir -p $(@D)
$(info Linking $@)
@$(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) $^ -o $@ $(ALL_LIBS)
obj/$(FILENAME)/%.cpp.o: %.cpp
@mkdir -p $(@D)
$(info Compiling $<)
@$(CXX) $(ALL_CXXFLAGS) $< -o $@ -c
include $(wildcard $(DEPENDENCIES))
obj/$(FILENAME)/windows_resources.o: $(ASSETS_DIRECTORY)/resources/CSE2.rc $(ASSETS_DIRECTORY)/resources/resource1.h $(ASSETS_DIRECTORY)/resources/afxres.h $(addprefix $(ASSETS_DIRECTORY)/resources/, $(RESOURCES))
@mkdir -p $(@D)
$(info Compiling Windows resource file $<)
@$(WINDRES) $< $@
# TODO
clean:
@rm -rf obj

159
README.md
View File

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.com/Clownacy/CSE2.svg?branch=portable)](https://travis-ci.com/Clownacy/CSE2)
[![Build Status](https://travis-ci.com/Clownacy/CSE2.svg?branch=accurate)](https://travis-ci.com/Clownacy/CSE2)
## Table of Contents
@ -9,22 +9,11 @@ Branch | Description
[accurate](https://www.github.com/Clownacy/CSE2/tree/accurate) | The main decompilation branch. The code is intended to be as close to the original as possible, down to all the bugs and platform-dependencies.
[portable](https://www.github.com/Clownacy/CSE2/tree/portable) | This branch ports the engine away from WinAPI and DirectX, and addresses numerous portability issues, allowing it to run on other platforms.
# CSE2 (Portable)
# CSE2
CSE2 is a decompilation of Cave Story.
This branch migrates the engine away from WinAPI and DirectX, and addresses
numerous portability issues, allowing it to run on other platforms.
Supported platforms include...
* Windows
* Linux
* macOS
* Wii U
* 3DS
* RISC OS
![Screenshot](images/screenshot.png)
![Screenshot](screenshot.png)
## Background
@ -62,24 +51,20 @@ Story's codebase.
And... that's it! It's not often that a game this decompilable comes along, so
I'm glad that Cave Story was one of them. [Patching a dusty old executable from 2005 sucks](https://github.com/Clownacy/Cave-Story-Mod-Loader/blob/master/src/mods/graphics_enhancement/widescreen/patch_camera.c).
## Dependencies
* SDL2 (if `BACKEND_AUDIO` or `BACKEND_PLATFORM` are set to `SDL2`)
* SDL (if `BACKEND_AUDIO` or `BACKEND_PLATFORM` are set to `SDL1`)
* GLFW3 (if `BACKEND_PLATFORM` is set to `GLFW3`)
* FreeType (if `FREETYPE_FONTS` is enabled)
If these are not found, they will be built locally (with the exception of SDL).
In addition, `pkg-config` is required for builds that require static-linkage.
A list of dependencies for specific platforms can be found [on the wiki](https://github.com/Clownacy/CSE2/wiki/Dependency-lists).
## Building
This project uses CMake, allowing it to be built with a range of compilers.
### Visual Studio .NET 2003
(A beginner-friendly guide can be found in [VISUAL_STUDIO_2019_GUIDE.md](VISUAL_STUDIO_2019_GUIDE.md))
Project files for Visual Studio .NET 2003 are available, and can be found in the
'vs2003' folder.
As proven by the original `Doukutsu.exe`'s [Rich Header](http://bytepointer.com/articles/the_microsoft_rich_header.htm),
Pixel used Visual Studio .NET 2003 to compile Cave Story. This means these
project files allow us to check the accuracy of the decompilation by comparing
the generated assembly code to that of the original executable. The tool for
this can be found in the 'devilution' folder.
### CMake (Visual Studio & MinGW-w64)
Switch to the terminal (Visual Studio users should open the [Developer Command Prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs))
and `cd` into this folder. After that, generate the files for your build system
@ -89,8 +74,7 @@ with:
cmake -B build -DCMAKE_BUILD_TYPE=Release
```
MSYS2 users should append `-G"MSYS Makefiles" -DPKG_CONFIG_STATIC_LIBS=ON` to
this command, also.
MSYS2 users should append `-G"MSYS Makefiles"` to this command, also.
You can also add the following flags:
@ -98,34 +82,10 @@ Name | Function
--------|--------
`-DJAPANESE=ON` | Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation)
`-DFIX_BUGS=ON` | Fix various bugs in the game
`-DDEBUG_SAVE=ON` | Re-enable the ability to drag-and-drop save files onto the window
`-DDOCONFIG=OFF` | Disable compiling the DoConfig tool (it is not useful for console ports)
`-DDOCONFIG_LEGACY_OPENGL=ON` | Make DoConfig use OpenGL 2.1 instead of OpenGL 3.2 (useful for older/limited platforms)
`-DLANCZOS_RESAMPLER=ON` | Use Lanczos filtering for audio resampling instead of linear-interpolation (Lanczos is more performance-intensive, but higher quality)
`-DFREETYPE_FONTS=ON` | Use FreeType2 to render the DejaVu Mono (English) or Migu1M (Japanese) fonts, instead of using pre-rendered copies of Courier New (English) and MS Gothic (Japanese)
`-DBACKEND_RENDERER=OpenGL3` | Render with OpenGL 3.2 (hardware-accelerated)
`-DBACKEND_RENDERER=OpenGLES2` | Render with OpenGL ES 2.0 (hardware-accelerated)
`-DBACKEND_RENDERER=SDLTexture` | (Default) Render with SDL2's Texture API (hardware-accelerated) (note: requires `-DBACKEND_PLATFORM=SDL2`)
`-DBACKEND_RENDERER=SDLSurface` | Render with SDL2's Surface API (software-rendered) (note: requires `-DBACKEND_PLATFORM=SDL2`)
`-DBACKEND_RENDERER=WiiU` | Render with the Wii U's GX2 API (hardware-accelerated)
`-DBACKEND_RENDERER=3DS` | Render with the 3DS's Citro2D/Citro3D API (hardware-accelerated)
`-DBACKEND_RENDERER=Software` | Render with a handwritten software-renderer
`-DBACKEND_AUDIO=SDL2` | (Default) Deliver audio with SDL2 (software-mixer)
`-DBACKEND_AUDIO=miniaudio` | Deliver audio with miniaudio (software-mixer)
`-DBACKEND_AUDIO=WiiU-Hardware` | Deliver audio with Wii U's AXVoice API (hardware-accelerated) (WARNING - currently broken: voices randomly disappear for unknown reasons)
`-DBACKEND_AUDIO=WiiU-Software` | Deliver audio with Wii U's AXVoice API (software-mixer)
`-DBACKEND_AUDIO=3DS-Hardware` | Deliver audio with 3DS's NDSP API (hardware-accelerated)
`-DBACKEND_AUDIO=3DS-Software` | Deliver audio with 3DS's NDSP API (software-mixer)
`-DBACKEND_AUDIO=Null` | Don't deliver audio at all (WARNING - game will have no audio)
`-DBACKEND_PLATFORM=SDL2` | (Default) Use SDL2 for miscellaneous platform-dependant operations
`-DBACKEND_PLATFORM=GLFW3` | Use GLFW3 for miscellaneous platform-dependant operations
`-DBACKEND_PLATFORM=WiiU` | Use the Wii U's native APIs for miscellaneous platform-dependant operations
`-DBACKEND_PLATFORM=3DS` | Use the 3DS's native APIs for miscellaneous platform-dependant operations
`-DBACKEND_PLATFORM=Null` | Don't do platform-dependant operations at all (WARNING - game will have no video or input)
`-DFIX_MAJOR_BUGS=ON` | Fix bugs that invoke undefined behaviour or cause memory leaks
`-DDEBUG_SAVE=ON` | Re-enable [the dummied-out 'Debug Save' option](https://tcrf.net/Cave_Story#Debug_Save), and the ability to drag-and-drop save files onto the window
`-DLTO=ON` | Enable link-time optimisation
`-DPKG_CONFIG_STATIC_LIBS=ON` | On platforms with pkg-config, static-link the dependencies (good for Windows builds, so you don't need to bundle DLL files)
`-DMSVC_LINK_STATIC_RUNTIME=ON` | Link the static MSVC runtime library, to reduce the number of required DLL files (Visual Studio only)
`-DFORCE_LOCAL_LIBS=ON` | Compile the built-in versions of SDL2, GLFW3, and FreeType instead of using the system-provided ones
You can pass your own compiler flags with `-DCMAKE_C_FLAGS` and `-DCMAKE_CXX_FLAGS`.
@ -138,83 +98,26 @@ cmake --build build --config Release
If you're a Visual Studio user, you can open the generated `CSE2.sln` file
instead, which can be found in the `build` folder.
Once built, the executables can be found in the `game_english`/`game_japanese`
Once built, the executable can be found in the `game_english`/`game_japanese`
folder, depending on the selected language.
### Building for the Wii U
### Makefile (MinGW-w64) \[deprecated - use CMake instead\]
To target the Wii U, you'll need devkitPro, devkitPPC, and WUT.
Run 'make' in this folder, preferably with some of the following settings:
First, add the devkitPPC tools directory to your PATH (because WUT's CMake
support is broken, as of writing):
Name | Function
--------|--------
`JAPANESE=1` | Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation)
`FIX_BUGS=1` | Fix various bugs in the game
`FIX_MAJOR_BUGS=1` | Fix bugs that invoke undefined behaviour or cause memory leaks
`DEBUG_SAVE=1` | Re-enable [the dummied-out 'Debug Save' option](https://tcrf.net/Cave_Story#Debug_Save), and the ability to drag-and-drop save files onto the window
`RELEASE=1` | Compile a release build (optimised, stripped, etc.)
`STATIC=1` | Produce a statically-linked executable (so you don't need to bundle DLL files)
```
PATH=$PATH:$DEVKITPPC/bin
```
You can pass your own compiler flags by defining `CXXFLAGS`.
Then, generate the build files with this command:
```
cmake -B buildwiiu -DCMAKE_BUILD_TYPE=Release -DFORCE_LOCAL_LIBS=ON -DBACKEND_PLATFORM=WiiU -DBACKEND_RENDERER=WiiU -DBACKEND_AUDIO=WiiU-Software -DDOCONFIG=OFF -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/wut/share/wut.toolchain.cmake
```
Finally, build the game with this command:
```
cmake --build buildwiiu
```
This will build a binary, but you still need to convert it to an `.rpx` file
that can be ran on your Wii U.
First, we need to strip the binary:
```
powerpc-eabi-strip -g game_english/CSE2
```
Then, we convert it to an `.rpx`:
```
elf2rpl game_english/CSE2 game_english/CSE2.rpx
```
`game_english/CSE2.rpx` is now ready to be ran on your Wii U. This port expects
the data folder to be in a folder called `CSE2-portable-en`/`CSE2-portable-jp`
on the root of your SD card.
### Building for the 3DS
To target the 3DS, you'll need devkitPro, devkitARM, Citro2D, Citro3D, libctru,
and bannertool, along with the `3dstools` and `devkitpro-pkgbuild-helpers`
packages.
Open a terminal, and `cd` into the CSE2 directory. Then execute this command:
```
cmake -B build3ds -DCMAKE_BUILD_TYPE=Release -DFORCE_LOCAL_LIBS=ON -DBACKEND_PLATFORM=3DS -DBACKEND_RENDERER=3DS -DBACKEND_AUDIO=3DS-Hardware -DDOCONFIG=OFF -DFREETYPE_FONTS=ON -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake
```
(Note that `FREETYPE_FONTS` is enabled. If you're creating a Japanese build,
it's best to disable this, as the FreeType font is unreadable at 320x240).
This will create the build files. To build CSE2, run:
```
cmake --build build3ds
```
This will create an elf file. Before we can create a `.3dsx` file from it, we
need to make an `.smdh` file:
```
bannertool makesmdh -i $DEVKITPRO/libctru/default_icon.png -s "CSE2" -l "Port of Cave Story" -p "Clownacy" -o build3ds/smdh.smdh
```
We can finally generate a `.3dsx` file:
```
3dsxtool game_english/CSE2 game_english/CSE2.3dsx --romfs=game_english/data --smdh=build3ds/smdh.smdh
```
Once built, the executable can be found in the `game_english`/`game_japanese`
folder, depending on the selected language.
## Licensing

View File

@ -1,62 +0,0 @@
So you want to compile CSE2?
Well, to start, you'll need Visual Studio. I know a lot of people
recommend MSYS2 instead, and while it is a lot more lightweight, it's
also way more complex, and outright broken in some places, which will
make compiling an absolute nightmare (I'm looking at you, Brotli).
So, we'll be using Visual Studio Community 2019. Don't worry - it's
free. You can download it here:
https://visualstudio.microsoft.com/
Once it's downloaded, run `vs_Community.exe`. Follow the installer until
you reach this menu:
![Screenshot](images/vs2019guide1.png)
Here, you'll want to select the 'Desktop development with C++' workload,
and then click 'Install'. Once it's done installing, you'll be prompted
to restart your computer.
Next, download a copy of CSE2's source code if you haven't already and
extract it somewhere. You can find a copy of CSE2 Portable's code here:
https://github.com/Clownacy/CSE2/archive/portable.zip
You are now ready to compile CSE2. To begin, open Visual Studio 2019. If
it prompts you to open a project, select 'Continue without code' to skip
past it and enter the main IDE. It should look something like this:
![Screenshot](images/vs2019guide2.png)
From here, select `File/Open/CMake`, and then navigate to where you
extracted the CSE2 source code, and open the `CMakeLists.txt` file.
After this, Visual Studio will spend a few minutes configuring itself.
You can see all of this in the little text console at the bottom of the
window. Eventually, it will conclude, and hopefully not report any
errors. The window should now look something like this:
![Screenshot](images/vs2019guide3.png)
You are now able to produce 64-bit Debug builds of CSE2. To do so,
simply select `Build/Build All`. Like before, Visual Studio will spend
the next few minutes performing tasks, and reporting back in the text
console. It should eventually generate `CSE2_debug.exe` and
`DoConfig_debug.exe`, which you can find in CSE2's `game_english`
folder.
However, you probably want to be compiling Release builds, not Debug
builds. To do so, select the 'Open the CMake Settings Editor' option. It
will take you to this menu:
![Screenshot](images/vs2019guide4.png)
From here, change the 'Configuration type' option to 'Release'. You can
now rebuild CSE2, and the files `CSE2.exe` and `DoConfig.exe` will be
generated in the `game_english` folder.
And... that's it. If you want, you can edit CSE2's code by expanding the
`src` folder on the right, and selecting one of the various `.cpp`
files.

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@ -59,6 +59,93 @@ BEGIN
END
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
CREDIT01 BITMAP "BITMAP/Credit01.bmp"
CREDIT02 BITMAP "BITMAP/Credit02.bmp"
CREDIT03 BITMAP "BITMAP/Credit03.bmp"
CREDIT04 BITMAP "BITMAP/Credit04.bmp"
CREDIT05 BITMAP "BITMAP/Credit05.bmp"
CREDIT06 BITMAP "BITMAP/Credit06.bmp"
CREDIT07 BITMAP "BITMAP/Credit07.bmp"
CREDIT08 BITMAP "BITMAP/Credit08.bmp"
CREDIT09 BITMAP "BITMAP/Credit09.bmp"
CREDIT10 BITMAP "BITMAP/Credit10.bmp"
CREDIT11 BITMAP "BITMAP/Credit11.bmp"
CREDIT12 BITMAP "BITMAP/Credit12.bmp"
CREDIT14 BITMAP "BITMAP/Credit14.bmp"
CREDIT15 BITMAP "BITMAP/Credit15.bmp"
CREDIT16 BITMAP "BITMAP/Credit16.bmp"
CREDIT17 BITMAP "BITMAP/Credit17.bmp"
CREDIT18 BITMAP "BITMAP/Credit18.bmp"
PIXEL BITMAP "BITMAP/pixel.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// ORG
//
ACCESS ORG "ORG/Access.org"
ANZEN ORG "ORG/Anzen.org"
BALCONY ORG "ORG/Balcony.org"
BALLOS ORG "ORG/Ballos.org"
BDOWN ORG "ORG/BreakDown.org"
CEMETERY ORG "ORG/Cemetery.org"
CURLY ORG "ORG/Curly.org"
DR ORG "ORG/Dr.org"
ENDING ORG "ORG/Ending.org"
ESCAPE ORG "ORG/Escape.org"
FANFALE1 ORG "ORG/Fanfale1.org"
FANFALE2 ORG "ORG/Fanfale2.org"
FANFALE3 ORG "ORG/Fanfale3.org"
FIREEYE ORG "ORG/FireEye.org"
GAMEOVER ORG "ORG/Gameover.org"
GINSUKE ORG "ORG/Ginsuke.org"
GRAND ORG "ORG/Grand.org"
GRAVITY ORG "ORG/Gravity.org"
HELL ORG "ORG/Hell.org"
IRONH ORG "ORG/ironH.org"
JENKA ORG "ORG/Jenka.org"
JENKA2 ORG "ORG/Jenka2.org"
KODOU ORG "ORG/Kodou.org"
LASTBTL ORG "ORG/LastBtl.org"
LASTBT3 ORG "ORG/LastBtl3.org"
LASTCAVE ORG "ORG/LastCave.org"
MARINE ORG "ORG/Marine.org"
MAZE ORG "ORG/Maze.org"
MDOWN2 ORG "ORG/MDown2.org"
OSIDE ORG "ORG/Oside.org"
MURA ORG "ORG/Mura.org"
PLANT ORG "ORG/Plant.org"
QUIET ORG "ORG/quiet.org"
REQUIEM ORG "ORG/Requiem.org"
TOROKO ORG "ORG/Toroko.org"
VIVI ORG "ORG/Vivi.org"
WANPAK2 ORG "ORG/Wanpak2.org"
WANPAKU ORG "ORG/Wanpaku.org"
WEED ORG "ORG/Weed.org"
WHITE ORG "ORG/White.org"
XXXX ORG "ORG/XXXX.org"
ZONBIE ORG "ORG/Zonbie.org"
/////////////////////////////////////////////////////////////////////////////
//
// WAVE
//
WAVE100 WAVE "WAVE/Wave.dat"
/////////////////////////////////////////////////////////////////////////////
//
// Cursor
//
CURSOR_IKA CURSOR "CURSOR/CURSOR_IKA.cur"
CURSOR_NORMAL CURSOR "CURSOR/CURSOR_NORMAL.cur"
/////////////////////////////////////////////////////////////////////////////
//
// Icon
@ -66,11 +153,124 @@ END
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
GLFW_ICON ICON "ICON/GLFW_ICON.ico"
0 ICON "ICON/0.ico"
ICON_MINI ICON "ICON/ICON_MINI.ico"
#endif // Japanese resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource1.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
MENU_MAIN MENU
BEGIN
MENUITEM "Quit", 40001
MENUITEM "Volume", 40004
MENUITEM "Version", 40002
MENUITEM "Debug Save", 40005
MENUITEM "Mute", 40007
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
DLG_ABOUT DIALOGEX 0, 0, 123, 75
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 9, "Arial", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",1,37,54,50,14,BS_FLAT
CTEXT "---",1011,7,14,109,35
END
DLG_MUTE DIALOGEX 0, 0, 118, 111
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Mute"
FONT 9, "Arial", 400, 0, 0x80
BEGIN
DEFPUSHBUTTON "OK",1,7,90,50,14
PUSHBUTTON "Cancel",2,61,90,50,14
CONTROL "0",1010,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,7,7,20,10
CONTROL "1",1018,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,17,15,20,10
CONTROL "2",1019,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,26,24,20,10
CONTROL "3",1020,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,35,33,20,10
CONTROL "4",1021,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,45,41,20,10
CONTROL "5",1022,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,54,50,20,10
CONTROL "6",1023,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,63,58,20,10
CONTROL "7",1024,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT |
WS_TABSTOP,73,67,20,10
END
DLG_SAVE DIALOGEX 0, 0, 118, 47
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Save"
FONT 9, "Arial", 0, 0, 0x1
BEGIN
EDITTEXT 1008,36,8,72,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",1,8,28,48,12
PUSHBUTTON "Cancel",2,60,28,48,12
LTEXT "Name",-1,8,8,20,12,SS_CENTERIMAGE
END
DLG_YESNO DIALOGEX 0, 0, 119, 49
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION
FONT 9, "Arial", 400, 0, 0x80
BEGIN
PUSHBUTTON "Yes",1,7,28,50,14,BS_FLAT
PUSHBUTTON "No",2,62,28,50,14,BS_FLAT
CTEXT "---",1009,7,8,105,15,SS_CENTERIMAGE
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

BIN
assets/resources/ICON/0.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

View File

@ -1,2 +0,0 @@
Set CSE2$Dir <Obey$Dir>
IconSprites <CSE2$Dir>.!Sprites

View File

@ -1,2 +0,0 @@
Set CSE2$Dir <Obey$Dir>
Run <CSE2$Dir>.CSE2 ><CSE2$Dir>.Log 2>&1

Binary file not shown.

View File

@ -1,34 +0,0 @@
cmake_minimum_required(VERSION 3.8)
option(LTO "Enable link-time optimisation" OFF)
project(bin2h LANGUAGES C)
add_executable(bin2h "bin2h.c")
set_target_properties(bin2h PROPERTIES
C_STANDARD 90
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
)
# Make some tweaks if we're using MSVC
if(MSVC)
# Disable warnings that normally fire up on MSVC when using "unsafe" functions instead of using MSVC's "safe" _s functions
target_compile_definitions(bin2h PRIVATE _CRT_SECURE_NO_WARNINGS)
# Make it so source files are recognized as UTF-8 by MSVC
target_compile_options(bin2h PRIVATE "/utf-8")
endif()
if(LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT result)
if(result)
set_target_properties(bin2h PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
endif()
install(TARGETS bin2h RUNTIME DESTINATION bin)

View File

@ -1,59 +0,0 @@
/* bin2h - converts binary files to C header files */
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int result = 1;
if (argc > 2)
{
FILE *in_file = fopen(argv[1], "rb");
FILE *out_file = fopen(argv[2], "w");
if (in_file == NULL)
{
printf("Couldn't open '%s'\n", argv[1]);
}
else if (out_file == NULL)
{
printf("Couldn't open '%s'\n", argv[2]);
}
else
{
long in_file_size;
unsigned char *in_file_buffer;
unsigned char *in_file_pointer;
long i;
fseek(in_file, 0, SEEK_END);
in_file_size = ftell(in_file);
rewind(in_file);
in_file_buffer = malloc(in_file_size);
fread(in_file_buffer, 1, in_file_size, in_file);
fclose(in_file);
in_file_pointer = in_file_buffer;
setvbuf(out_file, NULL, _IOFBF, 0x10000);
for (i = 0; i < in_file_size - 1; ++i)
{
if (i % 64 == 64-1)
fprintf(out_file, "%d,\n", *in_file_pointer++);
else
fprintf(out_file, "%d,", *in_file_pointer++);
}
fprintf(out_file, "%d\n", *in_file_pointer++);
fclose(out_file);
free(in_file_buffer);
result = 0;
}
}
return result;
}

View File

@ -1,170 +0,0 @@
#-------------------------------------------------------------------
# This file is stolen from part of the CMake build system for OGRE (Object-oriented Graphics Rendering Engine) http://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# - Try to find OpenGLES and EGL
# Once done this will define
#
# OPENGLES2_FOUND - system has OpenGLES
# OPENGLES2_INCLUDE_DIR - the GL include directory
# OPENGLES2_LIBRARIES - Link these to use OpenGLES
#
# EGL_FOUND - system has EGL
# EGL_INCLUDE_DIR - the EGL include directory
# EGL_LIBRARIES - Link these to use EGL
# Win32, Apple, and Android are not tested!
# Linux tested and works
# Slightly customised framework finder
macro(findpkg_framework fwk)
if(APPLE)
set(${fwk}_FRAMEWORK_PATH
${${fwk}_FRAMEWORK_SEARCH_PATH}
${CMAKE_FRAMEWORK_PATH}
~/Library/Frameworks
/Library/Frameworks
/System/Library/Frameworks
/Network/Library/Frameworks
${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Release
${CMAKE_CURRENT_SOURCE_DIR}/lib/macosx/Debug
)
# These could be arrays of paths, add each individually to the search paths
foreach(i ${OGRE_PREFIX_PATH})
set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug)
endforeach(i)
foreach(i ${OGRE_PREFIX_BUILD})
set(${fwk}_FRAMEWORK_PATH ${${fwk}_FRAMEWORK_PATH} ${i}/lib/macosx/Release ${i}/lib/macosx/Debug)
endforeach(i)
foreach(dir ${${fwk}_FRAMEWORK_PATH})
set(fwkpath ${dir}/${fwk}.framework)
if(EXISTS ${fwkpath})
set(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES}
${fwkpath}/Headers ${fwkpath}/PrivateHeaders)
set(${fwk}_FRAMEWORK_PATH ${dir})
if (NOT ${fwk}_LIBRARY_FWK)
set(${fwk}_LIBRARY_FWK "-framework ${fwk}")
endif ()
endif(EXISTS ${fwkpath})
endforeach(dir)
endif(APPLE)
endmacro(findpkg_framework)
macro(create_search_paths PREFIX)
foreach(dir ${${PREFIX}_PREFIX_PATH})
set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH}
${dir}/include ${dir}/Include ${dir}/include/${PREFIX} ${dir}/Headers)
set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH}
${dir}/lib ${dir}/Lib ${dir}/lib/${PREFIX} ${dir}/Libs)
set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH}
${dir}/bin)
endforeach(dir)
if(ANDROID)
set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} ${OGRE_DEPENDENCIES_DIR}/lib/${ANDROID_ABI})
endif()
set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH})
endmacro(create_search_paths)
if(WIN32)
if(CYGWIN)
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h)
find_library(OPENGLES2_LIBRARY libGLESv2)
else()
if(BORLAND)
set(OPENGLES2_LIBRARY import32 CACHE STRING "OpenGL ES 2.x library for Win32")
else()
# TODO
# set(OPENGLES_LIBRARY ${SOURCE_DIR}/Dependencies/lib/release/libGLESv2.lib CACHE STRING "OpenGL ES 2.x library for win32"
endif()
endif()
elseif(APPLE)
create_search_paths(/Developer/Platforms)
findpkg_framework(OpenGLES2)
set(OPENGLES2_LIBRARY "-framework OpenGLES")
else()
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
PATHS /usr/openwin/share/include
/opt/graphics/OpenGL/include
/opt/vc/include
/usr/X11R6/include
/usr/include
)
find_library(OPENGLES2_LIBRARY
NAMES GLESv2
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib /usr/X11R6/lib
/opt/vc/lib
/usr/lib/aarch64-linux-gnu
/usr/lib/arm-linux-gnueabihf
/usr/lib
)
if(NOT BUILD_ANDROID)
find_path(EGL_INCLUDE_DIR EGL/egl.h
PATHS /usr/openwin/share/include
/opt/graphics/OpenGL/include
/opt/vc/include
/usr/X11R6/include
/usr/include
)
find_library(EGL_LIBRARY
NAMES EGL
PATHS /opt/graphics/OpenGL/lib
/usr/openwin/lib
/usr/shlib
/usr/X11R6/lib
/opt/vc/lib
/usr/lib/aarch64-linux-gnu
/usr/lib/arm-linux-gnueabihf
/usr/lib
)
# On Unix OpenGL usually requires X11.
# It doesn't require X11 on OSX.
if(OPENGLES2_LIBRARY)
if(NOT X11_FOUND)
include(FindX11)
endif()
if(X11_FOUND)
set(OPENGLES2_LIBRARIES ${X11_LIBRARIES})
endif()
endif()
endif()
endif()
set(OPENGLES2_LIBRARIES ${OPENGLES2_LIBRARIES} ${OPENGLES2_LIBRARY})
if(BUILD_ANDROID)
if(OPENGLES2_LIBRARY)
set(EGL_LIBRARIES)
set(OPENGLES2_FOUND TRUE)
endif()
else()
if(OPENGLES2_LIBRARY AND EGL_LIBRARY)
set(EGL_LIBRARIES ${EGL_LIBRARY} ${EGL_LIBRARIES})
set(OPENGLES2_FOUND TRUE)
endif()
endif()
mark_as_advanced(
OPENGLES2_INCLUDE_DIR
OPENGLES2_LIBRARY
EGL_INCLUDE_DIR
EGL_LIBRARY
)
if(OPENGLES2_FOUND)
message(STATUS "Found system OpenGL ES 2 library: ${OPENGLES2_LIBRARIES}")
else()
set(OPENGLES2_LIBRARIES "")
endif()

View File

@ -1,22 +0,0 @@
# Use the following commands to build for RISC OS:
# cmake -B build-riscos -DCMAKE_BUILD_TYPE=Release -DBACKEND_PLATFORM=SDL1 -DBACKEND_RENDERER=Software -DBACKEND_AUDIO=SDL1 -DDOCONFIG=OFF -DCMAKE_TOOLCHAIN_FILE=$GCCSDK_INSTALL_ENV/toolchain-riscos.cmake -DRISCOS=ON -DPKG_CONFIG_STATIC_LIBS=ON
# cmake --build build-riscos
# (cd game_english && $GCCSDK_INSTALL_ENV/bin/zip -,9r cse2-riscos.zip \!CSE2)
function(elf_to_aif)
cmake_parse_arguments(ELFTOAIF "" "TARGET;OUTPUT" "" ${ARGN})
get_filename_component(ELFTOAIF_OUTPUT_DIR "${ELFTOAIF_OUTPUT}" DIRECTORY)
add_custom_command(OUTPUT "${ELFTOAIF_OUTPUT}"
COMMAND ${CMAKE_COMMAND} -E make_directory ${ELFTOAIF_OUTPUT_DIR}
COMMAND elf2aif $<TARGET_FILE:${ELFTOAIF_TARGET}> ${ELFTOAIF_OUTPUT}
DEPENDS ${ELFTOAIF_TARGET})
add_custom_target(${ELFTOAIF_TARGET}-aif ALL DEPENDS ${ELFTOAIF_OUTPUT})
endfunction(elf_to_aif)
elf_to_aif(TARGET CSE2 OUTPUT ${BUILD_DIRECTORY}/!CSE2/CSE2,ff8)
configure_file(${ASSETS_DIRECTORY}/riscos/!Boot,feb ${BUILD_DIRECTORY}/!CSE2/!Boot,feb COPYONLY)
configure_file(${ASSETS_DIRECTORY}/riscos/!Run,feb ${BUILD_DIRECTORY}/!CSE2/!Run,feb COPYONLY)
configure_file(${ASSETS_DIRECTORY}/riscos/!Sprites,ff9 ${BUILD_DIRECTORY}/!CSE2/!Sprites,ff9 COPYONLY)
configure_file(${BUILD_DIRECTORY}/licence.txt ${BUILD_DIRECTORY}/!CSE2/Licence COPYONLY)
file(COPY ${BUILD_DIRECTORY}/data DESTINATION ${BUILD_DIRECTORY}/!CSE2)

BIN
devilution/Doukutsu.exe Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
This code is licensed under the MIT License (MIT).
Copyright (c) 2014-2020 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

BIN
devilution/cvdump.exe Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,187 +0,0 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
TeX Gyre DJV Math
-----------------
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski
(on behalf of TeX users groups) are in public domain.
Letters imported from Euler Fraktur from AMSfonts are (c) American
Mathematical Society (see below).
Bitstream Vera Fonts Copyright
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera
is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license (“Fonts”) and associated
documentation
files (the “Font Software”), to reproduce and distribute the Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute,
and/or sell copies of the Font Software, and to permit persons to whom
the Font Software is furnished to do so, subject to the following
conditions:
The above copyright and trademark notices and this permission notice
shall be
included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional
glyphs or characters may be added to the Fonts, only if the fonts are
renamed
to names not containing either the words “Bitstream” or the word “Vera”.
This License becomes null and void to the extent applicable to Fonts or
Font Software
that has been modified and is distributed under the “Bitstream Vera”
names.
The Font Software may be sold as part of a larger software package but
no copy
of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN
ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
INABILITY TO USE
THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of GNOME, the GNOME
Foundation,
and Bitstream Inc., shall not be used in advertising or otherwise to promote
the sale, use or other dealings in this Font Software without prior written
authorization from the GNOME Foundation or Bitstream Inc., respectively.
For further information, contact: fonts at gnome dot org.
AMSFonts (v. 2.2) copyright
The PostScript Type 1 implementation of the AMSFonts produced by and
previously distributed by Blue Sky Research and Y&Y, Inc. are now freely
available for general use. This has been accomplished through the
cooperation
of a consortium of scientific publishers with Blue Sky Research and Y&Y.
Members of this consortium include:
Elsevier Science IBM Corporation Society for Industrial and Applied
Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)
In order to assure the authenticity of these fonts, copyright will be
held by
the American Mathematical Society. This is not meant to restrict in any way
the legitimate use of the fonts, such as (but not limited to) electronic
distribution of documents containing these fonts, inclusion of these fonts
into other public domain or commercial font collections or computer
applications, use of the outline data to create derivative fonts and/or
faces, etc. However, the AMS does require that the AMS copyright notice be
removed from any derivative versions of the fonts which have been altered in
any way. In addition, to ensure the fidelity of TeX documents using Computer
Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces,
has requested that any alterations which yield different font metrics be
given a different name.
$Id$

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -1,117 +0,0 @@
--------------------------------------------------
IPA Font License Agreement v1.0 <Japanese/English>
--------------------------------------------------
IPAフォントライセンスv1.0
許諾者は、この使用許諾以下「本契約」といいます。に定める条件の下で、許諾プログラム1条に定義するところによります。を提供します。受領者1条に定義するところによります。が、許諾プログラムを使用し、複製し、または頒布する行為、その他、本契約に定める権利の利用を行った場合、受領者は本契約に同意したものと見なします。
第1条 用語の定義
本契約において、次の各号に掲げる用語は、当該各号に定めるところによります。
1.「デジタル・フォント・プログラム」とは、フォントを含み、レンダリングしまたは表示するために用いられるコンピュータ・プログラムをいいます。
2.「許諾プログラム」とは、許諾者が本契約の下で許諾するデジタル・フォント・プログラムをいいます。
3.「派生プログラム」とは、許諾プログラムの一部または全部を、改変し、加除修正等し、入れ替え、その他翻案したデジタル・フォント・プログラムをいい、許諾プログラムの一部もしくは全部から文字情報を取り出し、またはデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出し、取り出された文字情報をそのまま、または改変をなして新たなデジタル・フォント・プログラムとして製作されたものを含みます。
4.「デジタル・コンテンツ」とは、デジタル・データ形式によってエンド・ユーザに提供される制作物のことをいい、動画・静止画等の映像コンテンツおよびテレビ番組等の放送コンテンツ、ならびに文字テキスト、画像、図形等を含んで構成された制作物を含みます。
5.「デジタル・ドキュメント・ファイル」とは、PDFファイルその他、各種ソフトウェア・プログラムによって製作されたデジタル・コンテンツであって、その中にフォントを表示するために許諾プログラムの全部または一部が埋め込まれたエンベッドされたものをいいます。フォントが「エンベッドされた」とは、当該フォントが埋め込まれた特定の「デジタル・ドキュメント・ファイル」においてのみ表示されるために使用されている状態を指し、その特定の「デジタル・ドキュメント・ファイル」以外でフォントを表示するために使用できるデジタル・フォント・プログラムに含まれている場合と区別されます。
6.「コンピュータ」とは、本契約においては、サーバを含みます。
7.「複製その他の利用」とは、複製、譲渡、頒布、貸与、公衆送信、上映、展示、翻案その他の利用をいいます。
8.「受領者」とは、許諾プログラムを本契約の下で受領した人をいい、受領者から許諾プログラムを受領した人を含みます。
第2条 使用許諾の付与
許諾者は受領者に対し、本契約の条項に従い、すべての国で、許諾プログラムを使用することを許諾します。ただし、許諾プログラムに存在する一切の権利はすべて許諾者が保有しています。本契約は、本契約で明示的に定められている場合を除き、いかなる意味においても、許諾者が保有する許諾プログラムに関する一切の権利および、いかなる商標、商号、もしくはサービス・マークに関する権利をも受領者に移転するものではありません。
1.受領者は本契約に定める条件に従い、許諾プログラムを任意の数のコンピュータにインストールし、当該コンピュータで使用することができます。
2.受領者はコンピュータにインストールされた許諾プログラムをそのまま、または改変を行ったうえで、印刷物およびデジタル・コンテンツにおいて、文字テキスト表現等として使用することができます。
3.受領者は前項の定めに従い作成した印刷物およびデジタル・コンテンツにつき、その商用・非商用の別、および放送、通信、各種記録メディアなどの媒体の形式を問わず、複製その他の利用をすることができます。
4.受領者がデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出して派生プログラムを作成した場合には、かかる派生プログラムは本契約に定める条件に従う必要があります。
5.許諾プログラムのエンベッドされたフォントがデジタル・ドキュメント・ファイル内のデジタル・コンテンツをレンダリングするためにのみ使用される場合において、受領者が当該デジタル・ドキュメント・ファイルを複製その他の利用をする場合には、受領者はかかる行為に関しては本契約の下ではいかなる義務をも負いません。
6.受領者は、3条2項の定めに従い、商用・非商用を問わず、許諾プログラムをそのままの状態で改変することなく複製して第三者への譲渡し、公衆送信し、その他の方法で再配布することができます(以下、「再配布」といいます。)。
7.受領者は、上記の許諾プログラムについて定められた条件と同様の条件に従って、派生プログラムを作成し、使用し、複製し、再配布することができます。ただし、受領者が派生プログラムを再配布する場合には、3条1項の定めに従うものとします。
第3条 制限
前条により付与された使用許諾は、以下の制限に服します。
1.派生プログラムが前条4項及び7項に基づき再配布される場合には、以下の全ての条件を満たさなければなりません。
 (1)派生プログラムを再配布する際には、下記もまた、当該派生プログラムと一緒に再配布され、オンラインで提供され、または、郵送費・媒体及び取扱手数料の合計を超えない実費と引き換えに媒体を郵送する方法により提供されなければなりません。
  (a)派生プログラムの写し; および
  (b)派生プログラムを作成する過程でフォント開発プログラムによって作成された追加のファイルであって派生プログラムをさらに加工するにあたって利用できるファイルが存在すれば、当該ファイル
 (2)派生プログラムの受領者が、派生プログラムを、このライセンスの下で最初にリリースされた許諾プログラム(以下、「オリジナル・プログラム」といいます。)に置き換えることができる方法を再配布するものとします。かかる方法は、オリジナル・ファイルからの差分ファイルの提供、または、派生プログラムをオリジナル・プログラムに置き換える方法を示す指示の提供などが考えられます。
 (3)派生プログラムを、本契約書に定められた条件の下でライセンスしなければなりません。
 (4)派生プログラムのプログラム名、フォント名またはファイル名として、許諾プログラムが用いているのと同一の名称、またはこれを含む名称を使用してはなりません。
 (5)本項の要件を満たすためにオンラインで提供し、または媒体を郵送する方法で提供されるものは、その提供を希望するいかなる者によっても提供が可能です。
2.受領者が前条6項に基づき許諾プログラムを再配布する場合には、以下の全ての条件を満たさなければなりません。
 (1)許諾プログラムの名称を変更してはなりません。
 (2)許諾プログラムに加工その他の改変を加えてはなりません。
 (3)本契約の写しを許諾プログラムに添付しなければなりません。
3.許諾プログラムは、現状有姿で提供されており、許諾プログラムまたは派生プログラムについて、許諾者は一切の明示または黙示の保証(権利の所在、非侵害、商品性、特定目的への適合性を含むがこれに限られません)を行いません。いかなる場合にも、その原因を問わず、契約上の責任か厳格責任か過失その他の不法行為責任かにかかわらず、また事前に通知されたか否かにかかわらず、許諾者は、許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用または本契約上の権利の行使によって生じた一切の損害(直接・間接・付随的・特別・拡大・懲罰的または結果的損害)(商品またはサービスの代替品の調達、システム障害から生じた損害、現存するデータまたはプログラムの紛失または破損、逸失利益を含むがこれに限られません)について責任を負いません。
4.許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用に関して、許諾者は技術的な質問や問い合わせ等に対する対応その他、いかなるユーザ・サポートをも行う義務を負いません。
第4条 契約の終了
1.本契約の有効期間は、受領者が許諾プログラムを受領した時に開始し、受領者が許諾プログラムを何らかの方法で保持する限り続くものとします。
2.前項の定めにかかわらず、受領者が本契約に定める各条項に違反したときは、本契約は、何らの催告を要することなく、自動的に終了し、当該受領者はそれ以後、許諾プログラムおよび派生プログラムを一切使用しまたは複製その他の利用をすることができないものとします。ただし、かかる契約の終了は、当該違反した受領者から許諾プログラムまたは派生プログラムの配布を受けた受領者の権利に影響を及ぼすものではありません。
第5条 準拠法
1.IPAは、本契約の変更バージョンまたは新しいバージョンを公表することができます。その場合には、受領者は、許諾プログラムまたは派生プログラムの使用、複製その他の利用または再配布にあたり、本契約または変更後の契約のいずれかを選択することができます。その他、上記に記載されていない条項に関しては日本の著作権法および関連法規に従うものとします。
2.本契約は、日本法に基づき解釈されます。
----------
IPA Font License Agreement v1.0
The Licensor provides the Licensed Program (as defined in Article 1 below) under the terms of this license agreement (“Agreement”). Any use, reproduction or distribution of the Licensed Program, or any exercise of rights under this Agreement by a Recipient (as defined in Article 1 below) constitutes the Recipient's acceptance of this Agreement.
Article 1 (Definitions)
1.“Digital Font Program” shall mean a computer program containing, or used to render or display fonts.
2.“Licensed Program” shall mean a Digital Font Program licensed by the Licensor under this Agreement.
3.“Derived Program” shall mean a Digital Font Program created as a result of a modification, addition, deletion, replacement or any other adaptation to or of a part or all of the Licensed Program, and includes a case where a Digital Font Program newly created by retrieving font information from a part or all of the Licensed Program or Embedded Fonts from a Digital Document File with or without modification of the retrieved font information.
4.“Digital Content” shall mean products provided to end users in the form of digital data, including video content, motion and/or still pictures, TV programs or other broadcasting content and products consisting of character text, pictures, photographic images, graphic symbols and/or the like.
5.“Digital Document File” shall mean a PDF file or other Digital Content created by various software programs in which a part or all of the Licensed Program becomes embedded or contained in the file for the display of the font (“Embedded Fonts”). Embedded Fonts are used only in the display of characters in the particular Digital Document File within which they are embedded, and shall be distinguished from those in any Digital Font Program, which may be used for display of characters outside that particular Digital Document File.
6.“Computer” shall include a server in this Agreement.
7.“Reproduction and Other Exploitation” shall mean reproduction, transfer, distribution, lease, public transmission, presentation, exhibition, adaptation and any other exploitation.
8.“Recipient” shall mean anyone who receives the Licensed Program under this Agreement, including one that receives the Licensed Program from a Recipient.
Article 2 (Grant of License)
The Licensor grants to the Recipient a license to use the Licensed Program in any and all countries in accordance with each of the provisions set forth in this Agreement. However, any and all rights underlying in the Licensed Program shall be held by the Licensor. In no sense is this Agreement intended to transfer any right relating to the Licensed Program held by the Licensor except as specifically set forth herein or any right relating to any trademark, trade name, or service mark to the Recipient.
1.The Recipient may install the Licensed Program on any number of Computers and use the same in accordance with the provisions set forth in this Agreement.
2.The Recipient may use the Licensed Program, with or without modification in printed materials or in Digital Content as an expression of character texts or the like.
3.The Recipient may conduct Reproduction and Other Exploitation of the printed materials and Digital Content created in accordance with the preceding Paragraph, for commercial or non-commercial purposes and in any form of media including but not limited to broadcasting, communication and various recording media.
4.If any Recipient extracts Embedded Fonts from a Digital Document File to create a Derived Program, such Derived Program shall be subject to the terms of this agreement.
5.If any Recipient performs Reproduction or Other Exploitation of a Digital Document File in which Embedded Fonts of the Licensed Program are used only for rendering the Digital Content within such Digital Document File then such Recipient shall have no further obligations under this Agreement in relation to such actions.
6.The Recipient may reproduce the Licensed Program as is without modification and transfer such copies, publicly transmit or otherwise redistribute the Licensed Program to a third party for commercial or non-commercial purposes (“Redistribute”), in accordance with the provisions set forth in Article 3 Paragraph 2.
7.The Recipient may create, use, reproduce and/or Redistribute a Derived Program under the terms stated above for the Licensed Program: provided, that the Recipient shall follow the provisions set forth in Article 3 Paragraph 1 when Redistributing the Derived Program.
Article 3 (Restriction)
The license granted in the preceding Article shall be subject to the following restrictions:
1.If a Derived Program is Redistributed pursuant to Paragraph 4 and 7 of the preceding Article, the following conditions must be met :
 (1)The following must be also Redistributed together with the Derived Program, or be made available online or by means of mailing mechanisms in exchange for a cost which does not exceed the total costs of postage, storage medium and handling fees:
  (a)a copy of the Derived Program; and
  (b)any additional file created by the font developing program in the course of creating the Derived Program that can be used for further modification of the Derived Program, if any.
 (2)It is required to also Redistribute means to enable recipients of the Derived Program to replace the Derived Program with the Licensed Program first released under this License (the “Original Program”). Such means may be to provide a difference file from the Original Program, or instructions setting out a method to replace the Derived Program with the Original Program.
 (3)The Recipient must license the Derived Program under the terms and conditions of this Agreement.
 (4)No one may use or include the name of the Licensed Program as a program name, font name or file name of the Derived Program.
 (5)Any material to be made available online or by means of mailing a medium to satisfy the requirements of this paragraph may be provided, verbatim, by any party wishing to do so.
2.If the Recipient Redistributes the Licensed Program pursuant to Paragraph 6 of the preceding Article, the Recipient shall meet all of the following conditions:
 (1)The Recipient may not change the name of the Licensed Program.
 (2)The Recipient may not alter or otherwise modify the Licensed Program.
 (3)The Recipient must attach a copy of this Agreement to the Licensed Program.
3.THIS LICENSED PROGRAM IS PROVIDED BY THE LICENSOR “AS IS” AND ANY EXPRESSED OR IMPLIED WARRANTY AS TO THE LICENSED PROGRAM OR ANY DERIVED PROGRAM, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXTENDED, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO; PROCUREMENT OF SUBSTITUTED GOODS OR SERVICE; DAMAGES ARISING FROM SYSTEM FAILURE; LOSS OR CORRUPTION OF EXISTING DATA OR PROGRAM; LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE INSTALLATION, USE, THE REPRODUCTION OR OTHER EXPLOITATION OF THE LICENSED PROGRAM OR ANY DERIVED PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
4.The Licensor is under no obligation to respond to any technical questions or inquiries, or provide any other user support in connection with the installation, use or the Reproduction and Other Exploitation of the Licensed Program or Derived Programs thereof.
Article 4 (Termination of Agreement)
1.The term of this Agreement shall begin from the time of receipt of the Licensed Program by the Recipient and shall continue as long as the Recipient retains any such Licensed Program in any way.
2.Notwithstanding the provision set forth in the preceding Paragraph, in the event of the breach of any of the provisions set forth in this Agreement by the Recipient, this Agreement shall automatically terminate without any notice. In the case of such termination, the Recipient may not use or conduct Reproduction and Other Exploitation of the Licensed Program or a Derived Program: provided that such termination shall not affect any rights of any other Recipient receiving the Licensed Program or the Derived Program from such Recipient who breached this Agreement.
Article 5 (Governing Law)
1.IPA may publish revised and/or new versions of this License. In such an event, the Recipient may select either this Agreement or any subsequent version of the Agreement in using, conducting the Reproduction and Other Exploitation of, or Redistributing the Licensed Program or a Derived Program. Other matters not specified above shall be subject to the Copyright Law of Japan and other related laws and regulations of Japan.
2.This Agreement shall be construed under the laws of Japan.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

View File

@ -1,68 +0,0 @@
==============
= Cave Story =
==============
None of us are lawyers, but to my understanding...
Being a decompilation, much of CSE2's code belongs to Daisuke "Pixel" Amaya.
There was no licence supplied with the original freeware release, so presumably
this code defaults to 'All Rights Reserved'.
...I dunno - how many of *you* are fluent in international copyright law?
========
= CSE2 =
========
MIT License
Copyright (c) 2019 Regan "cuckydev" Green
Copyright (c) 2019-2020 Clownacy
Copyright (c) 2019-2020 Gabriel Ravier
Copyright (c) 2020 Cameron Cawley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==============
= Dear Imgui =
==============
The MIT License (MIT)
Copyright (c) 2014-2020 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -8,7 +8,6 @@
#include "ArmsItem.h"
#include <string.h>
#include <string>
#include "WindowsWrapper.h"
@ -422,12 +421,12 @@ void PutCampObject(void)
int CampLoop(void)
{
std::string old_script_path;
char old_script_path[MAX_PATH];
RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
// Save the current script path (to restore it when we get out of the inventory)
old_script_path = GetTextScriptPath();
GetTextScriptPath(old_script_path);
// Load the inventory script
LoadTextScript2("ArmsItem.tsc");
@ -455,7 +454,7 @@ int CampLoop(void)
// Handle ESC
if (gKeyTrg & KEY_ESCAPE)
{
switch (Call_Escape())
switch (Call_Escape(ghWnd))
{
case enum_ESCRETURN_exit:
return enum_ESCRETURN_exit; // Quit game
@ -501,12 +500,12 @@ int CampLoop(void)
}
}
if (!Flip_SystemTask())
if (!Flip_SystemTask(ghWnd))
return enum_ESCRETURN_exit; // Quit game
}
// Resume original script
LoadTextScript_Stage(old_script_path.c_str());
LoadTextScript_Stage(old_script_path);
gArmsEnergyX = 32; // Displays weapon rotation animation in case the weapon was changed
return enum_ESCRETURN_continue; // Go to game
}

View File

@ -1,27 +0,0 @@
#pragma once
/// Include file for portable usage of __attribute__
#ifdef __MINGW32__
#define ATTRIBUTE_FORMAT_PRINTF(stringIndex, firstToCheck) __attribute__((format(__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck)))
#elif defined(__GNUC__)
#define ATTRIBUTE_FORMAT_PRINTF(stringIndex, firstToCheck) __attribute__((format(printf, stringIndex, firstToCheck)))
#else
#define ATTRIBUTE_FORMAT_PRINTF(stringIndex, firstToCheck)
#endif
#ifdef __GNUC__
#define ATTRIBUTE_HOT __attribute__((hot))
#define LIKELY(condition) __builtin_expect((condition), 1)
#define UNLIKELY(condition) __builtin_expect((condition), 0)
#define PREFETCH(address, isWrite, locality) __builtin_prefetch((address), (isWrite), (locality))
#else
#define ATTRIBUTE_HOT
#define LIKELY(condition) condition
#define UNLIKELY(condition) condition
#define PREFETCH(address, isWrite, locality)
#endif

View File

@ -9,13 +9,11 @@
#include <stddef.h>
#include <stdio.h>
#include <string>
#include "WindowsWrapper.h"
#include "CommonDefines.h"
#include "Draw.h"
#include "File.h"
#include "Main.h"
BACK gBack;
@ -25,19 +23,24 @@ static unsigned long color_black;
// TODO - Another function that has an incorrect stack frame
BOOL InitBack(const char *fName, int type)
{
std::string path;
char path[MAX_PATH];
FILE *fp;
BITMAPFILEHEADER file_header; // The original names for these two variables are unknown. This ruins the stack frame layout.
BITMAPINFOHEADER info_header;
color_black = GetCortBoxColor(RGB(0, 0, 0x10)); // Unused. This may have once been used by background type 4 (the solid black background)
// We're not actually loading the bitmap here - we're just reading its width/height and making sure it's really a BMP file
path = gDataPath + '/' + fName + ".pbm";
sprintf(path, "%s\\%s.pbm", gDataPath, fName);
fp = fopen(path.c_str(), "rb");
fp = fopen(path, "rb");
if (fp == NULL)
return FALSE;
if (fgetc(fp) != 'B' || fgetc(fp) != 'M')
fread(&file_header, sizeof(file_header), 1, fp);
// Check if this is a valid bitmap file
if (file_header.bfType != 0x4D42) // 'MB' (we use hex here to prevent a compiler warning)
{
#ifdef FIX_MAJOR_BUGS
// The original game forgets to close fp
@ -46,12 +49,12 @@ BOOL InitBack(const char *fName, int type)
return FALSE;
}
fseek(fp, 18, SEEK_SET);
fread(&info_header, sizeof(info_header), 1, fp);
fclose(fp);
// Get bitmap width and height
gBack.partsW = File_ReadLE32(fp);
gBack.partsH = File_ReadLE32(fp);
fclose(fp);
gBack.partsW = info_header.biWidth;
gBack.partsH = info_header.biHeight;
gBack.flag = TRUE; // This variable is otherwise unused

View File

@ -1,25 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
#include <stddef.h>
typedef struct AudioBackend_Sound AudioBackend_Sound;
bool AudioBackend_Init(void);
void AudioBackend_Deinit(void);
AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length);
void AudioBackend_DestroySound(AudioBackend_Sound *sound);
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping);
void AudioBackend_StopSound(AudioBackend_Sound *sound);
void AudioBackend_RewindSound(AudioBackend_Sound *sound);
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency);
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume);
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan);
void AudioBackend_SetOrganyaCallback(void (*callback)(void));
void AudioBackend_SetOrganyaTimer(unsigned int milliseconds);

View File

@ -1,297 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Audio.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <3ds.h>
#include "../Misc.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(a, min, max) MIN(MAX((a), (min)), (max))
typedef struct AudioBackend_Sound
{
signed char *samples;
ndspWaveBuf wave_buffer;
unsigned int frequency;
float volume;
float pan_l;
float pan_r;
bool looping;
int channel;
unsigned int identifier;
} AudioBackend_Sound;
static struct
{
unsigned int sound_identifier;
AudioBackend_Sound *sound;
} channels[24];
static void (*organya_callback)(void);
static unsigned int organya_callback_timer;
static LightLock organya_mutex;
static Thread organya_thread;
static bool organya_thread_die;
static void OrganyaThread(void *user_data)
{
(void)user_data;
while (!organya_thread_die)
{
LightLock_Lock(&organya_mutex);
unsigned int sleep_milliseconds = 10;
if (organya_callback_timer != 0)
{
organya_callback();
sleep_milliseconds = organya_callback_timer;
}
LightLock_Unlock(&organya_mutex);
svcSleepThread(sleep_milliseconds * 1000000);
}
}
static float MillibelToScale(long volume)
{
// Volume is in hundredths of a decibel, from 0 to -10000
volume = CLAMP(volume, -10000, 0);
return pow(10.0f, volume / 2000.0f);
}
static int AllocateChannel(AudioBackend_Sound *sound)
{
// Search for a channel which either doesn't have an assigned sound,
// or whose assigned sound has since stopped playing.
for (int i = 0; i < 24; ++i)
{
if (channels[i].sound_identifier == 0
|| channels[i].sound->wave_buffer.status == NDSP_WBUF_FREE
|| channels[i].sound->wave_buffer.status == NDSP_WBUF_DONE)
{
channels[i].sound_identifier = sound->identifier;
channels[i].sound = sound;
return i;
}
}
Backend_PrintInfo("Ran out of sound channels - hey you, whatever you're doing, stop it!");
return -1;
}
bool AudioBackend_Init(void)
{
Result rc = ndspInit();
if (R_SUCCEEDED(rc))
{
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
LightLock_Init(&organya_mutex);
s32 priority = 0x30;
svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
organya_thread_die = false;
organya_thread = threadCreate(OrganyaThread, NULL, 32 * 1024, CLAMP(priority - 1, 0x18, 0x3F), -1, false);
return true;
}
else
{
if (R_SUMMARY(rc) == RS_NOTFOUND && R_MODULE(rc) == RM_DSP)
Backend_PrintError("Could not load DSP firmware.\nThe game will not have any audio!\nTo fix this, you need to dump your\n3DS's DSP firmware.\nGoogle it if you're not sure what to do.");
else
Backend_PrintError("ndspInit failed in AudioBackend_Init");
}
return false;
}
void AudioBackend_Deinit(void)
{
organya_thread_die = true;
threadJoin(organya_thread, UINT64_MAX);
threadFree(organya_thread);
ndspExit();
}
AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
{
static unsigned int identifier_allocator;
AudioBackend_Sound *sound = (AudioBackend_Sound*)malloc(sizeof(AudioBackend_Sound));
if (sound != NULL)
{
sound->samples = (signed char*)linearAlloc(length);
if (sound->samples != NULL)
{
for (size_t i = 0; i < length; ++i)
sound->samples[i] = samples[i] - 0x80;
DSP_FlushDataCache(sound->samples, length);
memset(&sound->wave_buffer, 0, sizeof(sound->wave_buffer));
sound->wave_buffer.data_vaddr = sound->samples;
sound->wave_buffer.nsamples = length;
sound->frequency = frequency;
sound->volume = 1.0f;
sound->pan_l = 1.0f;
sound->pan_r = 1.0f;
sound->looping = false;
sound->channel = -1;
do
{
sound->identifier = ++identifier_allocator;
} while (sound->identifier == 0); // 0 is reserved
return sound;
}
else
{
Backend_PrintError("linearAlloc failed in AudioBackend_CreateSound");
}
free(sound);
}
else
{
Backend_PrintError("malloc failed in AudioBackend_CreateSound");
}
return NULL;
}
void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{
if (sound->channel != -1 && channels[sound->channel].sound_identifier == sound->identifier)
{
ndspChnWaveBufClear(sound->channel);
channels[sound->channel].sound_identifier = 0;
channels[sound->channel].sound = NULL;
}
linearFree(sound->samples);
free(sound);
}
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{
if (sound->channel == -1 || channels[sound->channel].sound_identifier != sound->identifier)
sound->channel = AllocateChannel(sound);
bool previous_looping = sound->looping;
sound->looping = looping;
if (sound->channel != -1)
{
if (sound->wave_buffer.status == NDSP_WBUF_FREE
|| sound->wave_buffer.status == NDSP_WBUF_DONE
|| previous_looping != looping)
{
ndspChnWaveBufClear(sound->channel);
ndspChnSetInterp(sound->channel, NDSP_INTERP_LINEAR);
ndspChnSetRate(sound->channel, sound->frequency);
ndspChnSetFormat(sound->channel, NDSP_FORMAT_MONO_PCM8);
sound->wave_buffer.looping = looping;
float mix[12];
memset(mix, 0, sizeof(mix));
mix[0] = sound->pan_l * sound->volume;
mix[1] = sound->pan_r * sound->volume;
ndspChnSetMix(sound->channel, mix);
ndspChnWaveBufAdd(sound->channel, &sound->wave_buffer);
}
}
}
void AudioBackend_StopSound(AudioBackend_Sound *sound)
{
if (sound->channel != -1 && channels[sound->channel].sound_identifier == sound->identifier)
ndspChnWaveBufClear(sound->channel);
}
void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{
(void)sound;
}
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{
sound->frequency = frequency;
if (sound->channel != -1 && channels[sound->channel].sound_identifier == sound->identifier)
ndspChnSetRate(sound->channel, frequency);
}
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{
sound->volume = MillibelToScale(volume);
if (sound->channel != -1 && channels[sound->channel].sound_identifier == sound->identifier)
{
float mix[12];
memset(mix, 0, sizeof(mix));
mix[0] = sound->pan_l * sound->volume;
mix[1] = sound->pan_r * sound->volume;
ndspChnSetMix(sound->channel, mix);
}
}
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
{
sound->pan_l = MillibelToScale(-pan);
sound->pan_r = MillibelToScale(pan);
if (sound->channel != -1 && channels[sound->channel].sound_identifier == sound->identifier)
{
float mix[12];
memset(mix, 0, sizeof(mix));
mix[0] = sound->pan_l * sound->volume;
mix[1] = sound->pan_r * sound->volume;
ndspChnSetMix(sound->channel, mix);
}
}
void AudioBackend_SetOrganyaCallback(void (*callback)(void))
{
LightLock_Lock(&organya_mutex);
organya_callback = callback;
LightLock_Unlock(&organya_mutex);
}
void AudioBackend_SetOrganyaTimer(unsigned int milliseconds)
{
LightLock_Lock(&organya_mutex);
organya_callback_timer = milliseconds;
LightLock_Unlock(&organya_mutex);
}

View File

@ -1,74 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Audio.h"
#include <stddef.h>
bool AudioBackend_Init(void)
{
return true;
}
void AudioBackend_Deinit(void)
{
}
AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
{
(void)frequency;
(void)samples;
(void)length;
return NULL;
}
void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{
(void)sound;
}
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{
(void)sound;
(void)looping;
}
void AudioBackend_StopSound(AudioBackend_Sound *sound)
{
(void)sound;
}
void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{
(void)sound;
}
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{
(void)sound;
(void)frequency;
}
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{
(void)sound;
(void)volume;
}
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
{
(void)sound;
(void)pan;
}
void AudioBackend_SetOrganyaCallback(void (*callback)(void))
{
(void)callback;
}
void AudioBackend_SetOrganyaTimer(unsigned int milliseconds)
{
(void)milliseconds;
}

View File

@ -1,194 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Audio.h"
#include <stddef.h>
#include "SoftwareMixer/Backend.h"
#include "SoftwareMixer/Mixer.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static unsigned long output_frequency;
static void (*organya_callback)(void);
static unsigned int organya_callback_timer_master;
static void MixSoundsAndUpdateOrganya(long *stream, size_t frames_total)
{
SoftwareMixerBackend_LockOrganyaMutex();
if (organya_callback_timer_master == 0)
{
SoftwareMixerBackend_LockMixerMutex();
Mixer_MixSounds(stream, frames_total);
SoftwareMixerBackend_UnlockMixerMutex();
}
else
{
// Synchronise audio generation with Organya.
// In the original game, Organya ran asynchronously in a separate thread,
// firing off commands to DirectSound in realtime. To match that, we'd
// need a very low-latency buffer, otherwise we'd get mistimed instruments.
// Instead, we can just do this.
unsigned int frames_done = 0;
while (frames_done != frames_total)
{
static unsigned long organya_callback_timer;
if (organya_callback_timer == 0)
{
organya_callback_timer = organya_callback_timer_master;
organya_callback();
}
const unsigned int frames_to_do = MIN(organya_callback_timer, frames_total - frames_done);
SoftwareMixerBackend_LockMixerMutex();
Mixer_MixSounds(stream + frames_done * 2, frames_to_do);
SoftwareMixerBackend_UnlockMixerMutex();
frames_done += frames_to_do;
organya_callback_timer -= frames_to_do;
}
}
SoftwareMixerBackend_UnlockOrganyaMutex();
}
bool AudioBackend_Init(void)
{
output_frequency = SoftwareMixerBackend_Init(MixSoundsAndUpdateOrganya);
if (output_frequency != 0)
{
Mixer_Init(output_frequency);
if (SoftwareMixerBackend_Start())
return true;
SoftwareMixerBackend_Deinit();
}
return false;
}
void AudioBackend_Deinit(void)
{
return SoftwareMixerBackend_Deinit();
}
AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
{
SoftwareMixerBackend_LockMixerMutex();
Mixer_Sound *sound = Mixer_CreateSound(frequency, samples, length);
SoftwareMixerBackend_UnlockMixerMutex();
return (AudioBackend_Sound*)sound;
}
void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_DestroySound((Mixer_Sound*)sound);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_PlaySound((Mixer_Sound*)sound, looping);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_StopSound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_StopSound((Mixer_Sound*)sound);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_RewindSound((Mixer_Sound*)sound);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_SetSoundFrequency((Mixer_Sound*)sound, frequency);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_SetSoundVolume((Mixer_Sound*)sound, volume);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
{
if (sound == NULL)
return;
SoftwareMixerBackend_LockMixerMutex();
Mixer_SetSoundPan((Mixer_Sound*)sound, pan);
SoftwareMixerBackend_UnlockMixerMutex();
}
void AudioBackend_SetOrganyaCallback(void (*callback)(void))
{
SoftwareMixerBackend_LockOrganyaMutex();
organya_callback = callback;
SoftwareMixerBackend_UnlockOrganyaMutex();
}
void AudioBackend_SetOrganyaTimer(unsigned int milliseconds)
{
SoftwareMixerBackend_LockOrganyaMutex();
organya_callback_timer_master = (milliseconds * output_frequency) / 1000; // convert milliseconds to audio frames
SoftwareMixerBackend_UnlockOrganyaMutex();
}

View File

@ -1,210 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Backend.h"
#include <stddef.h>
#include <string.h>
#include <3ds.h>
#include "../../Misc.h"
#define SAMPLE_RATE 32000 // The native sample rate is 32728.4980469
#define FRAMES_PER_BUFFER (SAMPLE_RATE / 30) // 33.333 milliseconds
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(a, min, max) MIN(MAX((a), (min)), (max))
static void (*parent_callback)(long *stream, size_t frames_total);
static short *stream_buffer;
static ndspWaveBuf dsp_buffers[2];
static bool current_dsp_buffer;
static LightLock mixer_mutex;
static LightLock organya_mutex;
static LightEvent audio_thread_event;
static Thread audio_thread;
static bool audio_thread_die;
static void FillBuffer(short *stream, size_t frames_total)
{
size_t frames_done = 0;
while (frames_done != frames_total)
{
long mix_buffer[FRAMES_PER_BUFFER * 2]; // 2 because stereo
size_t subframes = MIN(FRAMES_PER_BUFFER, frames_total - frames_done);
memset(mix_buffer, 0, subframes * sizeof(long) * 2);
parent_callback(mix_buffer, subframes);
for (size_t i = 0; i < subframes * 2; ++i)
{
if (mix_buffer[i] > 0x7FFF)
*stream++ = 0x7FFF;
else if (mix_buffer[i] < -0x7FFF)
*stream++ = -0x7FFF;
else
*stream++ = mix_buffer[i];
}
frames_done += subframes;
}
DSP_FlushDataCache(stream, frames_total * sizeof(short) * 2);
}
static void Callback(void *user_data)
{
(void)user_data;
LightEvent_Signal(&audio_thread_event);
}
static void AudioThread(void *user_data)
{
(void)user_data;
while (!audio_thread_die)
{
if (dsp_buffers[current_dsp_buffer].status == NDSP_WBUF_DONE)
{
FillBuffer(dsp_buffers[current_dsp_buffer].data_pcm16, dsp_buffers[current_dsp_buffer].nsamples);
ndspChnWaveBufAdd(0, &dsp_buffers[current_dsp_buffer]);
current_dsp_buffer = !current_dsp_buffer;
}
LightEvent_Wait(&audio_thread_event);
}
}
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total))
{
parent_callback = callback;
current_dsp_buffer = false;
stream_buffer = (short*)linearAlloc(FRAMES_PER_BUFFER * sizeof(short) * 2 * 2);
if (stream_buffer != NULL)
{
Result rc = ndspInit();
if (R_SUCCEEDED(rc))
{
ndspSetCallback(Callback, NULL);
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
ndspChnSetRate(0, SAMPLE_RATE);
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
float mix[12];
mix[0] = 1.0f;
mix[1] = 1.0f;
mix[2] = 0.0f;
mix[3] = 0.0f;
mix[4] = 0.0f;
mix[5] = 0.0f;
mix[6] = 0.0f;
mix[7] = 0.0f;
mix[8] = 0.0f;
mix[9] = 0.0f;
mix[10] = 0.0f;
mix[11] = 0.0f;
ndspChnSetMix(0, mix);
memset(dsp_buffers, 0, sizeof(dsp_buffers));
dsp_buffers[0].data_vaddr = &stream_buffer[FRAMES_PER_BUFFER * 2 * 0];
dsp_buffers[0].nsamples = FRAMES_PER_BUFFER;
dsp_buffers[1].data_vaddr = &stream_buffer[FRAMES_PER_BUFFER * 2 * 1];
dsp_buffers[1].nsamples = FRAMES_PER_BUFFER;
LightLock_Init(&mixer_mutex);
LightLock_Init(&organya_mutex);
LightEvent_Init(&audio_thread_event, RESET_ONESHOT);
s32 priority = 0x30;
svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
audio_thread_die = false;
audio_thread = threadCreate(AudioThread, NULL, 32 * 1024, CLAMP(priority - 1, 0x18, 0x3F), -1, false);
return SAMPLE_RATE;
}
else
{
if (R_SUMMARY(rc) == RS_NOTFOUND && R_MODULE(rc) == RM_DSP)
Backend_PrintError("Could not load DSP firmware.\nThe game will not have any audio!\nTo fix this, you need to dump your\n3DS's DSP firmware.\nGoogle it if you're not sure what to do.");
else
Backend_PrintError("ndspInit failed in SoftwareMixerBackend_Init");
}
linearFree(stream_buffer);
}
else
{
Backend_PrintError("linearAlloc failed");
}
return 0;
}
void SoftwareMixerBackend_Deinit(void)
{
ndspSetCallback(NULL, NULL);
// Kill audio thread
audio_thread_die = true;
LightEvent_Signal(&audio_thread_event);
threadJoin(audio_thread, UINT64_MAX);
threadFree(audio_thread);
ndspChnReset(0);
ndspExit();
linearFree(stream_buffer);
}
bool SoftwareMixerBackend_Start(void)
{
FillBuffer(stream_buffer, FRAMES_PER_BUFFER * 2);
ndspChnWaveBufAdd(0, &dsp_buffers[0]);
ndspChnWaveBufAdd(0, &dsp_buffers[1]);
return true;
}
void SoftwareMixerBackend_LockMixerMutex(void)
{
LightLock_Lock(&mixer_mutex);
}
void SoftwareMixerBackend_UnlockMixerMutex(void)
{
LightLock_Unlock(&mixer_mutex);
}
void SoftwareMixerBackend_LockOrganyaMutex(void)
{
LightLock_Lock(&organya_mutex);
}
void SoftwareMixerBackend_UnlockOrganyaMutex(void)
{
LightLock_Unlock(&organya_mutex);
}

View File

@ -1,17 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
#include <stddef.h>
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total));
void SoftwareMixerBackend_Deinit(void);
bool SoftwareMixerBackend_Start(void);
void SoftwareMixerBackend_LockMixerMutex(void);
void SoftwareMixerBackend_UnlockMixerMutex(void);
void SoftwareMixerBackend_LockOrganyaMutex(void);
void SoftwareMixerBackend_UnlockOrganyaMutex(void);

View File

@ -1,245 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Mixer.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include "../../../Attributes.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(x, y, z) MIN(MAX((x), (y)), (z))
#define LANCZOS_KERNEL_RADIUS 2
struct Mixer_Sound
{
signed char *samples;
size_t frames;
size_t position;
unsigned short position_subsample;
unsigned long advance_delta; // 16.16 fixed-point
bool playing;
bool looping;
short volume; // 8.8 fixed-point
short pan_l; // 8.8 fixed-point
short pan_r; // 8.8 fixed-point
short volume_l; // 8.8 fixed-point
short volume_r; // 8.8 fixed-point
struct Mixer_Sound *next;
};
static Mixer_Sound *sound_list_head;
static unsigned long output_frequency;
static unsigned short MillibelToScale(long volume)
{
// Volume is in hundredths of a decibel, from 0 to -10000
volume = CLAMP(volume, -10000, 0);
return (unsigned short)(pow(10.0, volume / 2000.0) * 256.0);
}
void Mixer_Init(unsigned long frequency)
{
output_frequency = frequency;
}
Mixer_Sound* Mixer_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
{
Mixer_Sound *sound = (Mixer_Sound*)malloc(sizeof(Mixer_Sound));
if (sound == NULL)
return NULL;
// Both interpolators will read outside the array's bounds, so allocate some extra room
#ifdef LANCZOS_RESAMPLER
sound->samples = (signed char*)malloc(LANCZOS_KERNEL_RADIUS - 1 + length + LANCZOS_KERNEL_RADIUS);
#else
sound->samples = (signed char*)malloc(length + 1);
#endif
if (sound->samples == NULL)
{
free(sound);
return NULL;
}
#ifdef LANCZOS_RESAMPLER
sound->samples += LANCZOS_KERNEL_RADIUS - 1;
#endif
for (size_t i = 0; i < length; ++i)
sound->samples[i] = samples[i] - 0x80; // Convert from unsigned 8-bit PCM to signed
sound->frames = length;
sound->playing = false;
sound->position = 0;
sound->position_subsample = 0;
Mixer_SetSoundFrequency(sound, frequency);
Mixer_SetSoundVolume(sound, 0);
Mixer_SetSoundPan(sound, 0);
sound->next = sound_list_head;
sound_list_head = sound;
return sound;
}
void Mixer_DestroySound(Mixer_Sound *sound)
{
for (Mixer_Sound **sound_pointer = &sound_list_head; *sound_pointer != NULL; sound_pointer = &(*sound_pointer)->next)
{
if (*sound_pointer == sound)
{
*sound_pointer = sound->next;
#ifdef LANCZOS_RESAMPLER
sound->samples -= LANCZOS_KERNEL_RADIUS - 1;
#endif
free(sound->samples);
free(sound);
break;
}
}
}
void Mixer_PlaySound(Mixer_Sound *sound, bool looping)
{
sound->playing = true;
sound->looping = looping;
// Fill the out-of-bounds part of the buffer with
// either blank samples or repeated samples
#ifdef LANCZOS_RESAMPLER
if (looping)
{
for (int i = -LANCZOS_KERNEL_RADIUS + 1; i < 0; ++i)
sound->samples[i] = sound->samples[sound->frames + i];
for (int i = 0; i < LANCZOS_KERNEL_RADIUS; ++i)
sound->samples[sound->frames + i] = sound->samples[i];
}
else
{
for (int i = -LANCZOS_KERNEL_RADIUS + 1; i < 0; ++i)
sound->samples[i] = 0;
for (int i = 0; i < LANCZOS_KERNEL_RADIUS; ++i)
sound->samples[sound->frames + i] = 0;
}
#else
sound->samples[sound->frames] = looping ? sound->samples[0] : 0;
#endif
}
void Mixer_StopSound(Mixer_Sound *sound)
{
sound->playing = false;
}
void Mixer_RewindSound(Mixer_Sound *sound)
{
sound->position = 0;
sound->position_subsample = 0;
}
void Mixer_SetSoundFrequency(Mixer_Sound *sound, unsigned int frequency)
{
sound->advance_delta = (frequency << 16) / output_frequency;
}
void Mixer_SetSoundVolume(Mixer_Sound *sound, long volume)
{
sound->volume = MillibelToScale(volume);
sound->volume_l = (sound->pan_l * sound->volume) >> 8;
sound->volume_r = (sound->pan_r * sound->volume) >> 8;
}
void Mixer_SetSoundPan(Mixer_Sound *sound, long pan)
{
sound->pan_l = MillibelToScale(-pan);
sound->pan_r = MillibelToScale(pan);
sound->volume_l = (sound->pan_l * sound->volume) >> 8;
sound->volume_r = (sound->pan_r * sound->volume) >> 8;
}
// Most CPU-intensive function in the game (2/3rd CPU time consumption in my experience), so marked with ATTRIBUTE_HOT so the compiler considers it a hot spot (as it is) when optimizing
ATTRIBUTE_HOT void Mixer_MixSounds(long *stream, size_t frames_total)
{
for (Mixer_Sound *sound = sound_list_head; sound != NULL; sound = sound->next)
{
if (sound->playing)
{
long *stream_pointer = stream;
for (size_t frames_done = 0; frames_done < frames_total; ++frames_done)
{
#ifdef LANCZOS_RESAMPLER
// Perform Lanczos resampling
float output_sample = 0;
for (int i = -LANCZOS_KERNEL_RADIUS + 1; i <= LANCZOS_KERNEL_RADIUS; ++i)
{
const signed char input_sample = sound->samples[sound->position + i];
const float kernel_input = ((float)sound->position_subsample / 0x10000) - i;
if (kernel_input == 0.0f)
{
output_sample += input_sample;
}
else
{
const float nx = 3.14159265358979323846f * kernel_input;
const float nxa = nx / LANCZOS_KERNEL_RADIUS;
output_sample += input_sample * (sin(nx) * sin(nxa) / (nx * nxa));
}
}
// Mix, and apply volume
*stream_pointer++ += (short)(output_sample * sound->volume_l);
*stream_pointer++ += (short)(output_sample * sound->volume_r);
#else
// Perform linear interpolation
const unsigned char interpolation_scale = sound->position_subsample >> 8;
const signed char output_sample = (sound->samples[sound->position] * (0x100 - interpolation_scale)
+ sound->samples[sound->position + 1] * interpolation_scale) >> 8;
// Mix, and apply volume
*stream_pointer++ += output_sample * sound->volume_l;
*stream_pointer++ += output_sample * sound->volume_r;
#endif
// Increment sample
const unsigned long next_position_subsample = sound->position_subsample + sound->advance_delta;
sound->position += next_position_subsample >> 16;
sound->position_subsample = next_position_subsample & 0xFFFF;
// Stop or loop sample once it's reached its end
if (sound->position >= sound->frames)
{
if (sound->looping)
{
sound->position %= sound->frames;
}
else
{
sound->playing = false;
sound->position = 0;
sound->position_subsample = 0;
break;
}
}
}
}
}
}

View File

@ -1,19 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
#include <stddef.h>
typedef struct Mixer_Sound Mixer_Sound;
void Mixer_Init(unsigned long frequency);
Mixer_Sound* Mixer_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length);
void Mixer_DestroySound(Mixer_Sound *sound);
void Mixer_PlaySound(Mixer_Sound *sound, bool looping);
void Mixer_StopSound(Mixer_Sound *sound);
void Mixer_RewindSound(Mixer_Sound *sound);
void Mixer_SetSoundFrequency(Mixer_Sound *sound, unsigned int frequency);
void Mixer_SetSoundVolume(Mixer_Sound *sound, long volume);
void Mixer_SetSoundPan(Mixer_Sound *sound, long pan);
void Mixer_MixSounds(long *stream, size_t frames_total);

View File

@ -1,116 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Backend.h"
#include <stddef.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../../Misc.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static void (*parent_callback)(long *stream, size_t frames_total);
static void Callback(void *user_data, Uint8 *stream_uint8, int len)
{
(void)user_data;
short *stream = (short*)stream_uint8;
const size_t frames_total = len / sizeof(short) / 2;
size_t frames_done = 0;
while (frames_done != frames_total)
{
long mix_buffer[0x800 * 2]; // 2 because stereo
size_t subframes = MIN(0x800, frames_total - frames_done);
memset(mix_buffer, 0, subframes * sizeof(long) * 2);
parent_callback(mix_buffer, subframes);
for (size_t i = 0; i < subframes * 2; ++i)
{
if (mix_buffer[i] > 0x7FFF)
*stream++ = 0x7FFF;
else if (mix_buffer[i] < -0x7FFF)
*stream++ = -0x7FFF;
else
*stream++ = mix_buffer[i];
}
frames_done += subframes;
}
}
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total))
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str());
return false;
}
SDL_AudioSpec specification;
specification.freq = 48000;
specification.format = AUDIO_S16;
specification.channels = 2;
specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz
specification.callback = Callback;
specification.userdata = NULL;
SDL_AudioSpec obtained_specification;
if (SDL_OpenAudio(&specification, &obtained_specification) != 0)
{
std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str());
return false;
}
char driver[20];
Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20));
parent_callback = callback;
return obtained_specification.freq;
}
void SoftwareMixerBackend_Deinit(void)
{
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
bool SoftwareMixerBackend_Start(void)
{
SDL_PauseAudio(0);
return true;
}
void SoftwareMixerBackend_LockMixerMutex(void)
{
SDL_LockAudio();
}
void SoftwareMixerBackend_UnlockMixerMutex(void)
{
SDL_UnlockAudio();
}
void SoftwareMixerBackend_LockOrganyaMutex(void)
{
SDL_LockAudio();
}
void SoftwareMixerBackend_UnlockOrganyaMutex(void)
{
SDL_UnlockAudio();
}

View File

@ -1,123 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Backend.h"
#include <stddef.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../../Misc.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static void (*parent_callback)(long *stream, size_t frames_total);
static SDL_AudioDeviceID device_id;
static void Callback(void *user_data, Uint8 *stream_uint8, int len)
{
(void)user_data;
short *stream = (short*)stream_uint8;
const size_t frames_total = len / sizeof(short) / 2;
size_t frames_done = 0;
while (frames_done != frames_total)
{
long mix_buffer[0x800 * 2]; // 2 because stereo
size_t subframes = MIN(0x800, frames_total - frames_done);
memset(mix_buffer, 0, subframes * sizeof(long) * 2);
parent_callback(mix_buffer, subframes);
for (size_t i = 0; i < subframes * 2; ++i)
{
if (mix_buffer[i] > 0x7FFF)
*stream++ = 0x7FFF;
else if (mix_buffer[i] < -0x7FFF)
*stream++ = -0x7FFF;
else
*stream++ = mix_buffer[i];
}
frames_done += subframes;
}
}
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total))
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDL2 audio backend)", errorMessage.c_str());
return 0;
}
Backend_PrintInfo("Available SDL audio drivers:");
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i)
Backend_PrintInfo("%s", SDL_GetAudioDriver(i));
SDL_AudioSpec specification;
specification.freq = 48000;
specification.format = AUDIO_S16;
specification.channels = 2;
specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz
specification.callback = Callback;
specification.userdata = NULL;
SDL_AudioSpec obtained_specification;
device_id = SDL_OpenAudioDevice(NULL, 0, &specification, &obtained_specification, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (device_id == 0)
{
std::string error_message = std::string("'SDL_OpenAudioDevice' failed: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDL2 audio backend)", error_message.c_str());
return 0;
}
Backend_PrintInfo("Selected SDL audio driver: %s", SDL_GetCurrentAudioDriver());
parent_callback = callback;
return obtained_specification.freq;
}
void SoftwareMixerBackend_Deinit(void)
{
SDL_CloseAudioDevice(device_id);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
bool SoftwareMixerBackend_Start(void)
{
SDL_PauseAudioDevice(device_id, 0);
return true;
}
void SoftwareMixerBackend_LockMixerMutex(void)
{
SDL_LockAudioDevice(device_id);
}
void SoftwareMixerBackend_UnlockMixerMutex(void)
{
SDL_UnlockAudioDevice(device_id);
}
void SoftwareMixerBackend_LockOrganyaMutex(void)
{
SDL_LockAudioDevice(device_id);
}
void SoftwareMixerBackend_UnlockOrganyaMutex(void)
{
SDL_UnlockAudioDevice(device_id);
}

View File

@ -1,237 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Backend.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <coreinit/cache.h>
#include <coreinit/mutex.h>
#include <coreinit/thread.h>
#include <sndcore2/core.h>
#include <sndcore2/voice.h>
#include <sndcore2/drcvs.h>
#define AUDIO_BUFFERS 2 // Double-buffer
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(x, y, z) MIN(MAX((x), (y)), (z))
static void (*parent_callback)(long *stream, size_t frames_total);
static OSMutex sound_list_mutex;
static OSMutex organya_mutex;
static AXVoice *voices[2];
static short *stream_buffers[2];
static long *stream_buffer_long;
static size_t buffer_length;
static void FrameCallback(void)
{
// We use a double-buffer: while the Wii U is busy playing one half of the buffer, we update the other.
// The buffer is 10ms long in total, and this function runs every 3ms.
// Just assume both voices are in-sync, and only check the first one
AXVoiceOffsets offsets;
AXGetVoiceOffsets(voices[0], &offsets);
unsigned int current_buffer = offsets.currentOffset / buffer_length;
static unsigned int last_buffer = 1;
if (current_buffer != last_buffer)
{
// Clear the mixer buffer
memset(stream_buffer_long, 0, buffer_length * sizeof(long) * 2);
// Fill mixer buffer
parent_callback(stream_buffer_long, buffer_length);
// Deinterlate samples, convert them to S16, and write them to the double-buffers
short *left_output_buffer = &stream_buffers[0][buffer_length * last_buffer];
short *right_output_buffer = &stream_buffers[1][buffer_length * last_buffer];
long *mixer_buffer_pointer = stream_buffer_long;
short *left_output_buffer_pointer = left_output_buffer;
short *right_output_buffer_pointer = right_output_buffer;
for (unsigned int i = 0; i < buffer_length; ++i)
{
const long left_sample = *mixer_buffer_pointer++;
const long right_sample = *mixer_buffer_pointer++;
// Clamp samples to sane limits, convert to S16, and store in double-buffers
if (left_sample > 0x7FFF)
*left_output_buffer_pointer++ = 0x7FFF;
else if (left_sample < -0x7FFF)
*left_output_buffer_pointer++ = -0x7FFF;
else
*left_output_buffer_pointer++ = (short)left_sample;
if (right_sample > 0x7FFF)
*right_output_buffer_pointer++ = 0x7FFF;
else if (right_sample < -0x7FFF)
*right_output_buffer_pointer++ = -0x7FFF;
else
*right_output_buffer_pointer++ = (short)right_sample;
}
// Make sure the sound hardware can see our data
DCStoreRange(left_output_buffer, buffer_length * sizeof(short));
DCStoreRange(right_output_buffer, buffer_length * sizeof(short));
last_buffer = current_buffer;
}
}
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total))
{
if (!AXIsInit())
{
AXInitParams initparams = {
.renderer = AX_INIT_RENDERER_48KHZ,
.pipeline = AX_INIT_PIPELINE_SINGLE,
};
AXInitWithParams(&initparams);
}
OSInitMutex(&sound_list_mutex);
OSInitMutex(&organya_mutex);
unsigned long output_frequency = AXGetInputSamplesPerSec();
buffer_length = output_frequency / 100; // 10ms buffer
// Create and initialise two 'voices': each one will stream its own
// audio - one for the left speaker, and one for the right.
// The software-mixer outputs interlaced samples into a buffer of `long`s,
// so create a buffer for it here.
stream_buffer_long = (long*)malloc(buffer_length * sizeof(long) * 2); // `* 2` because it's an interlaced stereo buffer
if (stream_buffer_long != NULL)
{
stream_buffers[0] = (short*)malloc(buffer_length * sizeof(short) * AUDIO_BUFFERS);
if (stream_buffers[0] != NULL)
{
stream_buffers[1] = (short*)malloc(buffer_length * sizeof(short) * AUDIO_BUFFERS);
if (stream_buffers[1] != NULL)
{
voices[0] = AXAcquireVoice(31, NULL, NULL);
if (voices[0] != NULL)
{
voices[1] = AXAcquireVoice(31, NULL, NULL);
if (voices[1] != NULL)
{
for (unsigned int i = 0; i < 2; ++i)
{
AXVoiceBegin(voices[i]);
AXSetVoiceType(voices[i], 0);
AXVoiceVeData vol = {.volume = 0x8000};
AXSetVoiceVe(voices[i], &vol);
AXVoiceDeviceMixData mix_data[6];
memset(mix_data, 0, sizeof(mix_data));
mix_data[i].bus[0].volume = 0x8000; // Voice 1 goes on the left speaker - voice 2 goes on the right speaker
AXSetVoiceDeviceMix(voices[i], AX_DEVICE_TYPE_DRC, 0, mix_data);
AXSetVoiceDeviceMix(voices[i], AX_DEVICE_TYPE_TV, 0, mix_data);
AXSetVoiceSrcRatio(voices[i], 1.0f); // We use the native sample rate
AXSetVoiceSrcType(voices[i], AX_VOICE_SRC_TYPE_NONE);
AXVoiceOffsets offs = {
.dataType = AX_VOICE_FORMAT_LPCM16,
.loopingEnabled = AX_VOICE_LOOP_ENABLED,
.loopOffset = 0,
.endOffset = (buffer_length * AUDIO_BUFFERS) - 1, // -1 or else you'll get popping!
.currentOffset = 0,
.data = stream_buffers[i]
};
AXSetVoiceOffsets(voices[i], &offs);
AXVoiceEnd(voices[i]);
}
parent_callback = callback;
// Register the frame callback.
// Apparently, this fires every 3ms - we will use
// it to update the stream buffers when needed.
AXRegisterAppFrameCallback(FrameCallback);
return output_frequency;
}
AXFreeVoice(voices[0]);
}
free(stream_buffers[1]);
}
free(stream_buffers[0]);
}
free(stream_buffer_long);
}
AXQuit();
return 0;
}
void SoftwareMixerBackend_Deinit(void)
{
AXRegisterAppFrameCallback(NULL);
AXFreeVoice(voices[1]);
AXFreeVoice(voices[0]);
free(stream_buffers[1]);
free(stream_buffers[0]);
free(stream_buffer_long);
AXQuit();
}
bool SoftwareMixerBackend_Start(void)
{
AXSetVoiceState(voices[0], AX_VOICE_STATE_PLAYING);
AXSetVoiceState(voices[1], AX_VOICE_STATE_PLAYING);
return true;
}
void SoftwareMixerBackend_LockMixerMutex(void)
{
OSLockMutex(&sound_list_mutex);
}
void SoftwareMixerBackend_UnlockMixerMutex(void)
{
OSUnlockMutex(&sound_list_mutex);
}
void SoftwareMixerBackend_LockOrganyaMutex(void)
{
OSLockMutex(&organya_mutex);
}
void SoftwareMixerBackend_UnlockOrganyaMutex(void)
{
OSUnlockMutex(&organya_mutex);
}

View File

@ -1,170 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "Backend.h"
#include <stddef.h>
#include <string.h>
#define MINIAUDIO_IMPLEMENTATION
#define MA_NO_DECODING
#define MA_NO_ENCODING
#define MA_NO_WAV
#define MA_NO_FLAC
#define MA_NO_MP3
#define MA_API static
#include "../../../../external/miniaudio.h"
#include "../../Misc.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static void (*parent_callback)(long *stream, size_t frames_total);
static ma_context context;
static ma_device device;
static ma_mutex mutex;
static ma_mutex organya_mutex;
static void Callback(ma_device *device, void *output_stream, const void *input_stream, ma_uint32 frames_total)
{
(void)device;
(void)input_stream;
short *stream = (short*)output_stream;
size_t frames_done = 0;
while (frames_done != frames_total)
{
long mix_buffer[0x800 * 2]; // 2 because stereo
size_t subframes = MIN(0x800, frames_total - frames_done);
memset(mix_buffer, 0, subframes * sizeof(long) * 2);
parent_callback(mix_buffer, subframes);
for (size_t i = 0; i < subframes * 2; ++i)
{
if (mix_buffer[i] > 0x7FFF)
*stream++ = 0x7FFF;
else if (mix_buffer[i] < -0x7FFF)
*stream++ = -0x7FFF;
else
*stream++ = mix_buffer[i];
}
frames_done += subframes;
}
}
unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total))
{
ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = NULL;
config.playback.format = ma_format_s16;
config.playback.channels = 2;
config.sampleRate = 0; // Let miniaudio decide what sample rate to use
config.dataCallback = Callback;
config.pUserData = NULL;
ma_result return_value;
return_value = ma_context_init(NULL, 0, NULL, &context);
if (return_value == MA_SUCCESS)
{
return_value = ma_device_init(&context, &config, &device);
if (return_value == MA_SUCCESS)
{
return_value = ma_mutex_init(&mutex);
if (return_value == MA_SUCCESS)
{
return_value = ma_mutex_init(&organya_mutex);
if (return_value == MA_SUCCESS)
{
parent_callback = callback;
return device.sampleRate;
}
else
{
Backend_PrintError("Failed to create organya mutex: %s", ma_result_description(return_value));
}
ma_mutex_uninit(&mutex);
}
else
{
Backend_PrintError("Failed to create mutex: %s", ma_result_description(return_value));
}
ma_device_uninit(&device);
}
else
{
Backend_PrintError("Failed to initialize playback device: %s", ma_result_description(return_value));
}
ma_context_uninit(&context);
}
else
{
Backend_PrintError("Failed to initialize context: %s", ma_result_description(return_value));
}
return 0;
}
void SoftwareMixerBackend_Deinit(void)
{
ma_result return_value = ma_device_stop(&device);
if (return_value != MA_SUCCESS)
Backend_PrintError("Failed to stop playback device: %s", ma_result_description(return_value));
ma_mutex_uninit(&organya_mutex);
ma_mutex_uninit(&mutex);
ma_device_uninit(&device);
ma_context_uninit(&context);
}
bool SoftwareMixerBackend_Start(void)
{
ma_result return_value = ma_device_start(&device);
if (return_value != MA_SUCCESS)
{
Backend_PrintError("Failed to start playback device: %s", ma_result_description(return_value));
return false;
}
return true;
}
void SoftwareMixerBackend_LockMixerMutex(void)
{
ma_mutex_lock(&mutex);
}
void SoftwareMixerBackend_UnlockMixerMutex(void)
{
ma_mutex_unlock(&mutex);
}
void SoftwareMixerBackend_LockOrganyaMutex(void)
{
ma_mutex_lock(&organya_mutex);
}
void SoftwareMixerBackend_UnlockOrganyaMutex(void)
{
ma_mutex_unlock(&organya_mutex);
}

View File

@ -1,425 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
// This darned thing doesn't work - sounds just randomly refuse to play,
// particularly the ones used by Organya.
// If anyone could figure out what causes this, that would be great.
#include "../Audio.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <coreinit/cache.h>
#include <coreinit/mutex.h>
#include <coreinit/thread.h>
#include <sndcore2/core.h>
#include <sndcore2/voice.h>
#include <sndcore2/drcvs.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(x, y, z) MIN(MAX((x), (y)), (z))
struct AudioBackend_Sound
{
signed char *samples;
size_t length;
AXVoice *voice;
unsigned int frequency;
unsigned short volume;
unsigned short pan_l;
unsigned short pan_r;
struct AudioBackend_Sound *next;
};
static void (*organya_callback)(void);
static unsigned int organya_milliseconds;
static unsigned long ticks_per_second;
static OSMutex sound_list_mutex;
static OSMutex organya_mutex;
static AudioBackend_Sound *sound_list_head;
static void CullVoices(void)
{
// Free any voices that aren't playing anymore
OSLockMutex(&sound_list_mutex);
for (AudioBackend_Sound *sound = sound_list_head; sound != NULL; sound = sound->next)
{
if (sound->voice != NULL)
{
if (!AXIsVoiceRunning(sound->voice))
{
AXVoiceBegin(sound->voice);
AXFreeVoice(sound->voice);
AXVoiceEnd(sound->voice);
sound->voice = NULL;
}
}
}
OSUnlockMutex(&sound_list_mutex);
}
static double MillibelToScale(long volume)
{
// Volume is in hundredths of a decibel, from 0 to -10000
volume = CLAMP(volume, -10000, 0);
return pow(10.0, volume / 2000.0);
}
static unsigned long GetTicksMilliseconds(void)
{
static uint64_t accumulator;
static unsigned long last_tick;
unsigned long current_tick = OSGetTick();
accumulator += current_tick - last_tick;
last_tick = current_tick;
return (accumulator * 1000) / ticks_per_second;
}
static int ThreadFunction(int argc, const char *argv[])
{
for (;;)
{
OSTestThreadCancel();
OSLockMutex(&organya_mutex);
if (organya_milliseconds == 0)
{
OSUnlockMutex(&organya_mutex);
// Do nothing
OSSleepTicks(ticks_per_second / 1000);
}
else
{
OSUnlockMutex(&organya_mutex);
// Update Organya
static unsigned long next_ticks;
for (;;)
{
unsigned long ticks = GetTicksMilliseconds();
if (ticks >= next_ticks)
break;
OSSleepTicks(ticks_per_second / 1000);
}
OSLockMutex(&organya_mutex);
next_ticks += organya_milliseconds;
OSUnlockMutex(&organya_mutex);
OSLockMutex(&sound_list_mutex);
organya_callback();
OSUnlockMutex(&sound_list_mutex);
}
}
return 0;
}
bool AudioBackend_Init(void)
{
if (!AXIsInit())
{
AXInitParams initparams = {
.renderer = AX_INIT_RENDERER_48KHZ,
.pipeline = AX_INIT_PIPELINE_SINGLE,
};
AXInitWithParams(&initparams);
}
ticks_per_second = OSGetSystemInfo()->busClockSpeed / 4;
OSInitMutex(&sound_list_mutex);
OSInitMutex(&organya_mutex);
OSRunThread(OSGetDefaultThread(0), ThreadFunction, 0, NULL);
return true;
}
void AudioBackend_Deinit(void)
{
OSCancelThread(OSGetDefaultThread(0));
OSJoinThread(OSGetDefaultThread(0), NULL);
AXQuit();
}
AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
{
AudioBackend_Sound *sound = (AudioBackend_Sound*)malloc(sizeof(AudioBackend_Sound));
if (sound != NULL)
{
signed char *samples_copy = (signed char*)malloc(length);
if (samples_copy != NULL)
{
// Convert to signed
for (size_t i = 0; i < length; ++i)
samples_copy[i] = samples[i] - 0x80;
DCStoreRange(samples_copy, length);
sound->samples = samples_copy;
sound->length = length;
sound->voice = NULL;
sound->frequency = frequency;
sound->volume = 0x8000;
sound->pan_l = 0x8000;
sound->pan_r = 0x8000;
OSLockMutex(&sound_list_mutex);
sound->next = sound_list_head;
sound_list_head = sound;
OSUnlockMutex(&sound_list_mutex);
return sound;
}
free(sound);
}
return NULL;
}
void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
// Unhook sound from the linked-list
for (AudioBackend_Sound **sound_pointer = &sound_list_head; *sound_pointer != NULL; sound_pointer = &(*sound_pointer)->next)
{
if (*sound_pointer == sound)
{
*sound_pointer = sound->next;
break;
}
}
OSUnlockMutex(&sound_list_mutex);
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXFreeVoice(sound->voice);
AXVoiceEnd(sound->voice);
}
free(sound->samples);
free(sound);
}
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{
if (sound == NULL)
return;
CullVoices();
OSLockMutex(&sound_list_mutex);
if (sound->voice == NULL)
{
AXVoice *voice = AXAcquireVoice(31, NULL, NULL);
if (voice != NULL)
{
AXVoiceBegin(voice);
AXSetVoiceType(voice, 0);
AXVoiceVeData vol = {.volume = sound->volume};
AXSetVoiceVe(voice, &vol);
AXVoiceDeviceMixData mix_data[6];
memset(mix_data, 0, sizeof(mix_data));
mix_data[0].bus[0].volume = sound->pan_l;
mix_data[1].bus[0].volume = sound->pan_r;
AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_DRC, 0, mix_data);
AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_TV, 0, mix_data);
float srcratio = (float)sound->frequency / (float)AXGetInputSamplesPerSec();
AXSetVoiceSrcRatio(voice, srcratio);
AXSetVoiceSrcType(voice, AX_VOICE_SRC_TYPE_LINEAR);
AXVoiceOffsets offs;
offs.dataType = AX_VOICE_FORMAT_LPCM8;
offs.endOffset = sound->length;
offs.loopingEnabled = AX_VOICE_LOOP_DISABLED;
offs.loopOffset = 0;
offs.currentOffset = 0;
offs.data = sound->samples;
AXSetVoiceOffsets(voice, &offs);
AXVoiceEnd(voice);
sound->voice = voice;
}
}
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXSetVoiceLoop(sound->voice, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED);
AXSetVoiceState(sound->voice, AX_VOICE_STATE_PLAYING);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_StopSound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXSetVoiceState(sound->voice, AX_VOICE_STATE_STOPPED);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXSetVoiceCurrentOffset(sound->voice, 0);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
sound->frequency = frequency;
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec();
AXSetVoiceSrcRatio(sound->voice, srcratio);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
sound->volume = (unsigned short)(0x8000 * MillibelToScale(volume));
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXVoiceVeData vol = {.volume = sound->volume};
AXSetVoiceVe(sound->voice, &vol);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
{
if (sound == NULL)
return;
OSLockMutex(&sound_list_mutex);
sound->pan_l = (unsigned short)(0x8000 * MillibelToScale(-pan));
sound->pan_r = (unsigned short)(0x8000 * MillibelToScale(pan));
if (sound->voice != NULL)
{
AXVoiceBegin(sound->voice);
AXVoiceDeviceMixData mix_data[6];
memset(mix_data, 0, sizeof(mix_data));
mix_data[0].bus[0].volume = sound->pan_l;
mix_data[1].bus[0].volume = sound->pan_r;
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_DRC, 0, mix_data);
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_TV, 0, mix_data);
AXVoiceEnd(sound->voice);
}
OSUnlockMutex(&sound_list_mutex);
}
void AudioBackend_SetOrganyaCallback(void (*callback)(void))
{
// As far as thread-safety goes - this is guarded by
// `organya_milliseconds`, which is guarded by `organya_mutex`.
organya_callback = callback;
}
void AudioBackend_SetOrganyaTimer(unsigned int milliseconds)
{
OSLockMutex(&organya_mutex);
organya_milliseconds = milliseconds;
OSUnlockMutex(&organya_mutex);
}

View File

@ -1,8 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
bool ControllerBackend_Init(void);
void ControllerBackend_Deinit(void);
bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_count, short **axes, unsigned int *axis_count);

View File

@ -1,172 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Controller.h"
#include <stddef.h>
#include <stdlib.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include "../Misc.h"
#define DEADZONE (10000.0f / 32767.0f)
static bool joystick_connected;
static int connected_joystick_id;
static float *axis_neutrals;
static void JoystickCallback(int joystick_id, int event)
{
switch (event)
{
case GLFW_CONNECTED:
Backend_PrintInfo("Joystick #%d connected - %s", joystick_id, glfwGetJoystickName(joystick_id));
if (!joystick_connected)
{
int total_axes;
const float *axes = glfwGetJoystickAxes(joystick_id, &total_axes);
int total_buttons;
const unsigned char *buttons = glfwGetJoystickButtons(joystick_id, &total_buttons);
if (total_axes >= 2 && total_buttons >= 6)
{
#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
if (glfwJoystickIsGamepad(joystick_id) == GLFW_TRUE) // Avoid selecting things like laptop touchpads
#endif
{
// Set up neutral axes
axis_neutrals = (float*)malloc(sizeof(float) * total_axes);
if (axis_neutrals != NULL)
{
for (int i = 0; i < total_axes; ++i)
axis_neutrals[i] = axes[i];
Backend_PrintInfo("Joystick #%d selected\n", joystick_id);
joystick_connected = true;
connected_joystick_id = joystick_id;
}
else
{
Backend_PrintError("Couldn't allocate memory for joystick axes");
}
}
}
}
break;
case GLFW_DISCONNECTED:
if (joystick_connected && joystick_id == connected_joystick_id)
{
Backend_PrintInfo("Joystick #%d disconnected", connected_joystick_id);
joystick_connected = false;
free(axis_neutrals);
}
break;
}
}
bool ControllerBackend_Init(void)
{
// Connect joysticks that are already plugged-in
for (int i = GLFW_JOYSTICK_1; i < GLFW_JOYSTICK_LAST; ++i)
if (glfwJoystickPresent(i) == GLFW_TRUE)
JoystickCallback(i, GLFW_CONNECTED);
// Set-up the callback for future (dis)connections
glfwSetJoystickCallback(JoystickCallback);
return true;
}
void ControllerBackend_Deinit(void)
{
glfwSetJoystickCallback(NULL);
joystick_connected = false;
connected_joystick_id = 0;
free(axis_neutrals);
axis_neutrals = NULL;
}
bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_count, short **axes, unsigned int *axis_count)
{
if (!joystick_connected)
return false;
int total_glfw_buttons;
const unsigned char *glfw_buttons = glfwGetJoystickButtons(connected_joystick_id, &total_glfw_buttons);
int total_glfw_axes;
const float *glfw_axes = glfwGetJoystickAxes(connected_joystick_id, &total_glfw_axes);
int total_glfw_hats = 0;
#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
const unsigned char *glfw_hats = glfwGetJoystickHats(connected_joystick_id, &total_glfw_hats);
#endif
*button_count = total_glfw_buttons + total_glfw_axes * 2 + total_glfw_hats * 4;
*axis_count = total_glfw_axes;
static bool *button_buffer = NULL;
static short *axis_buffer = NULL;
bool *new_button_buffer = (bool*)realloc(button_buffer, *button_count * sizeof(bool));
short *new_axis_buffer = (short*)realloc(axis_buffer, *axis_count * sizeof(short));
if (new_button_buffer == NULL || new_axis_buffer == NULL)
return false;
button_buffer = new_button_buffer;
axis_buffer = new_axis_buffer;
//////////////////////////
// Handle button inputs //
//////////////////////////
unsigned int current_button = 0;
// Start with the joystick buttons
for (int i = 0; i < total_glfw_buttons; ++i)
button_buffer[current_button++] = glfw_buttons[i] == GLFW_PRESS;
// Then the joystick axes
for (int i = 0; i < total_glfw_axes; ++i)
{
button_buffer[current_button++] = glfw_axes[i] < axis_neutrals[i] - DEADZONE;
button_buffer[current_button++] = glfw_axes[i] > axis_neutrals[i] + DEADZONE;
}
#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3)
// Then the joystick hats
for (int i = 0; i < total_glfw_hats; ++i)
{
button_buffer[current_button++] = glfw_hats[i] & GLFW_HAT_UP;
button_buffer[current_button++] = glfw_hats[i] & GLFW_HAT_RIGHT;
button_buffer[current_button++] = glfw_hats[i] & GLFW_HAT_DOWN;
button_buffer[current_button++] = glfw_hats[i] & GLFW_HAT_LEFT;
}
#endif
*buttons = button_buffer;
////////////////////////
// Handle axis inputs //
////////////////////////
for (int i = 0; i < total_glfw_axes; ++i)
axis_buffer[i] = (short)(glfw_axes[i] * 0x7FFF);
*axes = axis_buffer;
return true;
}

View File

@ -1,24 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Controller.h"
bool ControllerBackend_Init(void)
{
return false;
}
void ControllerBackend_Deinit(void)
{
}
bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_count, short **axes, unsigned int *axis_count)
{
(void)buttons;
(void)button_count;
(void)axes;
(void)axis_count;
return false;
}

View File

@ -1,215 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Controller.h"
#include <stddef.h>
#include <stdlib.h>
#include "SDL.h"
#include "../Misc.h"
#include "../Shared/SDL.h"
#define DEADZONE 10000
static SDL_Joystick *joystick;
static Sint16 *axis_neutrals;
bool ControllerBackend_Init(void)
{
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
Backend_PrintError("Couldn't initialise joystick SDL subsystem: %s", SDL_GetError());
return false;
}
#if !SDL_VERSION_ATLEAST(2, 0, 0)
if (SDL_NumJoysticks() > 0)
ControllerBackend_JoystickConnect(0);
#endif
return true;
}
void ControllerBackend_Deinit(void)
{
if (joystick != NULL)
{
SDL_JoystickClose(joystick);
joystick = NULL;
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_count, short **axes, unsigned int *axis_count)
{
if (joystick == NULL)
return false;
int total_sdl_buttons = SDL_JoystickNumButtons(joystick);
if (total_sdl_buttons < 0)
{
total_sdl_buttons = 0;
Backend_PrintError("Failed to get number of buttons on joystick: %s", SDL_GetError());
}
int total_sdl_axes = SDL_JoystickNumAxes(joystick);
if (total_sdl_axes < 0)
{
total_sdl_axes = 0;
Backend_PrintError("Failed to get number of general axis controls on joystick: %s", SDL_GetError());
}
int total_sdl_hats = SDL_JoystickNumHats(joystick);
if (total_sdl_hats < 0)
{
total_sdl_hats = 0;
Backend_PrintError("Failed to get number of POV hats on joystick: %s", SDL_GetError());
}
*button_count = total_sdl_buttons + total_sdl_axes * 2 + total_sdl_hats * 4;
*axis_count = total_sdl_axes;
static bool *button_buffer = NULL;
static short *axis_buffer = NULL;
bool *new_button_buffer = (bool*)realloc(button_buffer, *button_count * sizeof(bool));
if (new_button_buffer == NULL)
return false;
button_buffer = new_button_buffer;
short *new_axis_buffer = (short*)realloc(axis_buffer, *axis_count * sizeof(short));
if (new_axis_buffer == NULL)
return false;
axis_buffer = new_axis_buffer;
//////////////////////////
// Handle button inputs //
//////////////////////////
unsigned int current_button = 0;
// Start with the joystick buttons
for (int i = 0; i < total_sdl_buttons; ++i)
button_buffer[current_button++] = SDL_JoystickGetButton(joystick, i);
// Then the joystick axes
for (int i = 0; i < total_sdl_axes; ++i)
{
Sint16 axis = SDL_JoystickGetAxis(joystick, i);
button_buffer[current_button++] = axis < axis_neutrals[i] - DEADZONE;
button_buffer[current_button++] = axis > axis_neutrals[i] + DEADZONE;
}
// Then the joystick hats
for (int i = 0; i < total_sdl_hats; ++i)
{
Uint8 hat = SDL_JoystickGetHat(joystick, i);
button_buffer[current_button++] = hat == SDL_HAT_UP || hat == SDL_HAT_LEFTUP || hat == SDL_HAT_RIGHTUP;
button_buffer[current_button++] = hat == SDL_HAT_RIGHT || hat == SDL_HAT_RIGHTUP || hat == SDL_HAT_RIGHTDOWN;
button_buffer[current_button++] = hat == SDL_HAT_DOWN || hat == SDL_HAT_LEFTDOWN || hat == SDL_HAT_RIGHTDOWN;
button_buffer[current_button++] = hat == SDL_HAT_LEFT || hat == SDL_HAT_LEFTUP || hat == SDL_HAT_LEFTDOWN;
}
*buttons = button_buffer;
////////////////////////
// Handle axis inputs //
////////////////////////
for (int i = 0; i < total_sdl_axes; ++i)
axis_buffer[i] = SDL_JoystickGetAxis(joystick, i);
*axes = axis_buffer;
return true;
}
void ControllerBackend_JoystickConnect(Sint32 joystick_id)
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
const char *joystick_name = SDL_JoystickNameForIndex(joystick_id);
#else
const char *joystick_name = SDL_JoystickName(joystick_id);
#endif
if (joystick_name != NULL)
{
Backend_PrintInfo("Joystick #%d connected - %s", joystick_id, joystick_name);
}
else
{
Backend_PrintError("Couldn't get joystick name: %s", SDL_GetError());
Backend_PrintInfo("Joystick #%d connected - Name unknown", joystick_id);
}
if (joystick == NULL)
{
joystick = SDL_JoystickOpen(joystick_id);
if (joystick != NULL)
{
int total_axes = SDL_JoystickNumAxes(joystick);
if (total_axes < 0)
Backend_PrintError("Couldn't get number of general axis control on connected joystick: %s", SDL_GetError());
int total_buttons = SDL_JoystickNumButtons(joystick);
if (total_buttons < 0)
Backend_PrintError("Couldn't get number of buttons on connected joystick: %s", SDL_GetError());
if (total_axes >= 2 && total_buttons >= 6)
{
Backend_PrintInfo("Joystick #%d selected", joystick_id);
// Set up neutral axes
axis_neutrals = (Sint16*)malloc(sizeof(Sint16) * total_axes);
if (axis_neutrals != NULL)
{
for (int i = 0; i < total_axes; ++i)
axis_neutrals[i] = SDL_JoystickGetAxis(joystick, i);
return;
}
else
{
Backend_PrintError("Couldn't allocate memory for neutral axes");
}
}
SDL_JoystickClose(joystick);
joystick = NULL;
}
else
{
Backend_PrintError("Couldn't open joystick for use: %s", SDL_GetError());
}
}
}
void ControllerBackend_JoystickDisconnect(Sint32 joystick_id)
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_JoystickID current_joystick_id = SDL_JoystickInstanceID(joystick);
if (current_joystick_id < 0)
Backend_PrintError("Couldn't get instance ID for current joystick: %s", SDL_GetError());
if (joystick_id == current_joystick_id)
{
Backend_PrintInfo("Joystick #%d disconnected", joystick_id);
SDL_JoystickClose(joystick);
joystick = NULL;
free(axis_neutrals);
}
#endif
}

View File

@ -1,106 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
#include <stddef.h>
#include <string>
#include "../Attributes.h"
enum
{
// Based on US QWERTY
BACKEND_KEYBOARD_A,
BACKEND_KEYBOARD_B,
BACKEND_KEYBOARD_C,
BACKEND_KEYBOARD_D,
BACKEND_KEYBOARD_E,
BACKEND_KEYBOARD_F,
BACKEND_KEYBOARD_G,
BACKEND_KEYBOARD_H,
BACKEND_KEYBOARD_I,
BACKEND_KEYBOARD_J,
BACKEND_KEYBOARD_K,
BACKEND_KEYBOARD_L,
BACKEND_KEYBOARD_M,
BACKEND_KEYBOARD_N,
BACKEND_KEYBOARD_O,
BACKEND_KEYBOARD_P,
BACKEND_KEYBOARD_Q,
BACKEND_KEYBOARD_R,
BACKEND_KEYBOARD_S,
BACKEND_KEYBOARD_T,
BACKEND_KEYBOARD_U,
BACKEND_KEYBOARD_V,
BACKEND_KEYBOARD_W,
BACKEND_KEYBOARD_X,
BACKEND_KEYBOARD_Y,
BACKEND_KEYBOARD_Z,
BACKEND_KEYBOARD_0,
BACKEND_KEYBOARD_1,
BACKEND_KEYBOARD_2,
BACKEND_KEYBOARD_3,
BACKEND_KEYBOARD_4,
BACKEND_KEYBOARD_5,
BACKEND_KEYBOARD_6,
BACKEND_KEYBOARD_7,
BACKEND_KEYBOARD_8,
BACKEND_KEYBOARD_9,
BACKEND_KEYBOARD_F1,
BACKEND_KEYBOARD_F2,
BACKEND_KEYBOARD_F3,
BACKEND_KEYBOARD_F4,
BACKEND_KEYBOARD_F5,
BACKEND_KEYBOARD_F6,
BACKEND_KEYBOARD_F7,
BACKEND_KEYBOARD_F8,
BACKEND_KEYBOARD_F9,
BACKEND_KEYBOARD_F10,
BACKEND_KEYBOARD_F11,
BACKEND_KEYBOARD_F12,
BACKEND_KEYBOARD_UP,
BACKEND_KEYBOARD_DOWN,
BACKEND_KEYBOARD_LEFT,
BACKEND_KEYBOARD_RIGHT,
BACKEND_KEYBOARD_ESCAPE,
BACKEND_KEYBOARD_BACK_QUOTE,
BACKEND_KEYBOARD_TAB,
BACKEND_KEYBOARD_CAPS_LOCK,
BACKEND_KEYBOARD_LEFT_SHIFT,
BACKEND_KEYBOARD_LEFT_CTRL,
BACKEND_KEYBOARD_LEFT_ALT,
BACKEND_KEYBOARD_SPACE,
BACKEND_KEYBOARD_RIGHT_ALT,
BACKEND_KEYBOARD_RIGHT_CTRL,
BACKEND_KEYBOARD_RIGHT_SHIFT,
BACKEND_KEYBOARD_ENTER,
BACKEND_KEYBOARD_BACKSPACE,
BACKEND_KEYBOARD_MINUS,
BACKEND_KEYBOARD_EQUALS,
BACKEND_KEYBOARD_LEFT_BRACKET,
BACKEND_KEYBOARD_RIGHT_BRACKET,
BACKEND_KEYBOARD_BACK_SLASH,
BACKEND_KEYBOARD_SEMICOLON,
BACKEND_KEYBOARD_APOSTROPHE,
BACKEND_KEYBOARD_COMMA,
BACKEND_KEYBOARD_PERIOD,
BACKEND_KEYBOARD_FORWARD_SLASH,
BACKEND_KEYBOARD_TOTAL
};
bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus));
void Backend_Deinit(void);
void Backend_PostWindowCreation(void);
bool Backend_GetPaths(std::string *module_path, std::string *data_path);
void Backend_HideMouse(void);
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height);
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height);
void Backend_EnableDragAndDrop(void);
bool Backend_SystemTask(bool active);
void Backend_GetKeyboardState(bool *keyboard_state);
void Backend_ShowMessageBox(const char *title, const char *message);
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...);
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...);
unsigned long Backend_GetTicks(void);
void Backend_Delay(unsigned int ticks);

View File

@ -1,152 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <3ds.h>
bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus))
{
(void)drag_and_drop_callback;
(void)window_focus_callback;
gfxInitDefault();
consoleInit(GFX_BOTTOM, NULL);
if (R_SUCCEEDED(romfsInit()))
{
// osSetSpeedupEnable(true); // Enable New3DS speedup, since this doesn't run very well on Old3DSs yet
return true;
}
else
{
Backend_PrintError("Could not initialise romfs");
}
return false;
}
void Backend_Deinit(void)
{
romfsExit();
gfxExit();
}
void Backend_PostWindowCreation(void)
{
// Nothing to do here
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
// Create the CSE2 folder if it doesn't already exist
mkdir("sdmc:/3ds", 0777);
mkdir("sdmc:/3ds/data", 0777);
mkdir("sdmc:/3ds/data/cse2", 0777);
// Configuration files and save data goes on the read-write SD card
*module_path = "sdmc:/3ds/data/cse2";
// Data goes in the read-only ROMFS
*data_path = "romfs:";
return true;
}
void Backend_HideMouse(void)
{
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
(void)rgb_pixels;
(void)width;
(void)height;
}
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height)
{
(void)rgba_pixels;
(void)width;
(void)height;
}
void Backend_EnableDragAndDrop(void)
{
}
bool Backend_SystemTask(bool active)
{
(void)active;
return true;
}
void Backend_GetKeyboardState(bool *keyboard_state)
{
memset(keyboard_state, 0, sizeof(bool) * BACKEND_KEYBOARD_TOTAL);
// Read controller
hidScanInput();
u32 buttons = hidKeysHeld();
keyboard_state[BACKEND_KEYBOARD_UP] |= buttons & KEY_UP;
keyboard_state[BACKEND_KEYBOARD_DOWN] |= buttons & KEY_DOWN;
keyboard_state[BACKEND_KEYBOARD_LEFT] |= buttons & KEY_LEFT;
keyboard_state[BACKEND_KEYBOARD_RIGHT] |= buttons & KEY_RIGHT;
keyboard_state[BACKEND_KEYBOARD_Z] |= buttons & KEY_B; // Jump
keyboard_state[BACKEND_KEYBOARD_X] |= buttons & KEY_Y; // Shoot
keyboard_state[BACKEND_KEYBOARD_Q] |= buttons & (KEY_A | KEY_START); // Inventory
keyboard_state[BACKEND_KEYBOARD_W] |= buttons & (KEY_X | KEY_SELECT); // Map
keyboard_state[BACKEND_KEYBOARD_A] |= buttons & (KEY_L | KEY_ZR | KEY_CSTICK_LEFT); // Weapon left
keyboard_state[BACKEND_KEYBOARD_S] |= buttons & (KEY_R | KEY_ZL | KEY_CSTICK_RIGHT); // Weapon right
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
Backend_PrintInfo("ShowMessageBox - %s - %s", title, message);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("ERROR: ", stderr);
vfprintf(stderr, format, argumentList);
fputc('\n', stderr);
va_end(argumentList);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("INFO: ", stdout);
vfprintf(stdout, format, argumentList);
fputc('\n', stdout);
va_end(argumentList);
}
unsigned long Backend_GetTicks(void)
{
return svcGetSystemTick() / CPU_TICKS_PER_MSEC;
}
void Backend_Delay(unsigned int ticks)
{
// svcSleepThread measures in nanoseconds
svcSleepThread(ticks * 1000000);
}

View File

@ -1,309 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#if __cplusplus >= 201103L
#include <chrono>
#include <thread>
#elif defined(_WIN32)
#include "windows.h"
#else
#include <unistd.h>
#endif
#include <GLFW/glfw3.h>
#include "../Rendering.h"
#include "../Shared/GLFW3.h"
#include "../../Attributes.h"
#define DO_KEY(GLFW_KEY, BACKEND_KEY) \
case GLFW_KEY: \
keyboard_state[BACKEND_KEY] = action == GLFW_PRESS; \
break;
static bool keyboard_state[BACKEND_KEYBOARD_TOTAL];
static GLFWcursor* cursor;
static void (*drag_and_drop_callback)(const char *path);
static void (*window_focus_callback)(bool focus);
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
(void)window;
(void)scancode;
(void)mods;
switch (action)
{
case GLFW_RELEASE:
case GLFW_PRESS:
switch (key)
{
DO_KEY(GLFW_KEY_A, BACKEND_KEYBOARD_A)
DO_KEY(GLFW_KEY_B, BACKEND_KEYBOARD_B)
DO_KEY(GLFW_KEY_C, BACKEND_KEYBOARD_C)
DO_KEY(GLFW_KEY_D, BACKEND_KEYBOARD_D)
DO_KEY(GLFW_KEY_E, BACKEND_KEYBOARD_E)
DO_KEY(GLFW_KEY_F, BACKEND_KEYBOARD_F)
DO_KEY(GLFW_KEY_G, BACKEND_KEYBOARD_G)
DO_KEY(GLFW_KEY_H, BACKEND_KEYBOARD_H)
DO_KEY(GLFW_KEY_I, BACKEND_KEYBOARD_I)
DO_KEY(GLFW_KEY_J, BACKEND_KEYBOARD_J)
DO_KEY(GLFW_KEY_K, BACKEND_KEYBOARD_K)
DO_KEY(GLFW_KEY_L, BACKEND_KEYBOARD_L)
DO_KEY(GLFW_KEY_M, BACKEND_KEYBOARD_M)
DO_KEY(GLFW_KEY_N, BACKEND_KEYBOARD_N)
DO_KEY(GLFW_KEY_O, BACKEND_KEYBOARD_O)
DO_KEY(GLFW_KEY_P, BACKEND_KEYBOARD_P)
DO_KEY(GLFW_KEY_Q, BACKEND_KEYBOARD_Q)
DO_KEY(GLFW_KEY_R, BACKEND_KEYBOARD_R)
DO_KEY(GLFW_KEY_S, BACKEND_KEYBOARD_S)
DO_KEY(GLFW_KEY_T, BACKEND_KEYBOARD_T)
DO_KEY(GLFW_KEY_U, BACKEND_KEYBOARD_U)
DO_KEY(GLFW_KEY_V, BACKEND_KEYBOARD_V)
DO_KEY(GLFW_KEY_W, BACKEND_KEYBOARD_W)
DO_KEY(GLFW_KEY_X, BACKEND_KEYBOARD_X)
DO_KEY(GLFW_KEY_Y, BACKEND_KEYBOARD_Y)
DO_KEY(GLFW_KEY_Z, BACKEND_KEYBOARD_Z)
DO_KEY(GLFW_KEY_0, BACKEND_KEYBOARD_0)
DO_KEY(GLFW_KEY_1, BACKEND_KEYBOARD_1)
DO_KEY(GLFW_KEY_2, BACKEND_KEYBOARD_2)
DO_KEY(GLFW_KEY_3, BACKEND_KEYBOARD_3)
DO_KEY(GLFW_KEY_4, BACKEND_KEYBOARD_4)
DO_KEY(GLFW_KEY_5, BACKEND_KEYBOARD_5)
DO_KEY(GLFW_KEY_6, BACKEND_KEYBOARD_6)
DO_KEY(GLFW_KEY_7, BACKEND_KEYBOARD_7)
DO_KEY(GLFW_KEY_8, BACKEND_KEYBOARD_8)
DO_KEY(GLFW_KEY_9, BACKEND_KEYBOARD_9)
DO_KEY(GLFW_KEY_F1, BACKEND_KEYBOARD_F1)
DO_KEY(GLFW_KEY_F2, BACKEND_KEYBOARD_F2)
DO_KEY(GLFW_KEY_F3, BACKEND_KEYBOARD_F3)
DO_KEY(GLFW_KEY_F4, BACKEND_KEYBOARD_F4)
DO_KEY(GLFW_KEY_F5, BACKEND_KEYBOARD_F5)
DO_KEY(GLFW_KEY_F6, BACKEND_KEYBOARD_F6)
DO_KEY(GLFW_KEY_F7, BACKEND_KEYBOARD_F7)
DO_KEY(GLFW_KEY_F8, BACKEND_KEYBOARD_F8)
DO_KEY(GLFW_KEY_F9, BACKEND_KEYBOARD_F9)
DO_KEY(GLFW_KEY_F10, BACKEND_KEYBOARD_F10)
DO_KEY(GLFW_KEY_F11, BACKEND_KEYBOARD_F11)
DO_KEY(GLFW_KEY_F12, BACKEND_KEYBOARD_F12)
DO_KEY(GLFW_KEY_UP, BACKEND_KEYBOARD_UP)
DO_KEY(GLFW_KEY_DOWN, BACKEND_KEYBOARD_DOWN)
DO_KEY(GLFW_KEY_LEFT, BACKEND_KEYBOARD_LEFT)
DO_KEY(GLFW_KEY_RIGHT, BACKEND_KEYBOARD_RIGHT)
DO_KEY(GLFW_KEY_ESCAPE, BACKEND_KEYBOARD_ESCAPE)
DO_KEY(GLFW_KEY_GRAVE_ACCENT, BACKEND_KEYBOARD_BACK_QUOTE)
DO_KEY(GLFW_KEY_TAB, BACKEND_KEYBOARD_TAB)
DO_KEY(GLFW_KEY_CAPS_LOCK, BACKEND_KEYBOARD_CAPS_LOCK)
DO_KEY(GLFW_KEY_LEFT_SHIFT, BACKEND_KEYBOARD_LEFT_SHIFT)
DO_KEY(GLFW_KEY_LEFT_CONTROL, BACKEND_KEYBOARD_LEFT_CTRL)
DO_KEY(GLFW_KEY_LEFT_ALT, BACKEND_KEYBOARD_LEFT_ALT)
DO_KEY(GLFW_KEY_SPACE, BACKEND_KEYBOARD_SPACE)
DO_KEY(GLFW_KEY_RIGHT_ALT, BACKEND_KEYBOARD_RIGHT_ALT)
DO_KEY(GLFW_KEY_RIGHT_CONTROL, BACKEND_KEYBOARD_RIGHT_CTRL)
DO_KEY(GLFW_KEY_RIGHT_SHIFT, BACKEND_KEYBOARD_RIGHT_SHIFT)
DO_KEY(GLFW_KEY_ENTER, BACKEND_KEYBOARD_ENTER)
DO_KEY(GLFW_KEY_BACKSPACE, BACKEND_KEYBOARD_BACKSPACE)
DO_KEY(GLFW_KEY_MINUS, BACKEND_KEYBOARD_MINUS)
DO_KEY(GLFW_KEY_EQUAL, BACKEND_KEYBOARD_EQUALS)
DO_KEY(GLFW_KEY_LEFT_BRACKET, BACKEND_KEYBOARD_LEFT_BRACKET)
DO_KEY(GLFW_KEY_RIGHT_BRACKET, BACKEND_KEYBOARD_RIGHT_BRACKET)
DO_KEY(GLFW_KEY_BACKSLASH, BACKEND_KEYBOARD_BACK_SLASH)
DO_KEY(GLFW_KEY_SEMICOLON, BACKEND_KEYBOARD_SEMICOLON)
DO_KEY(GLFW_KEY_APOSTROPHE, BACKEND_KEYBOARD_APOSTROPHE)
DO_KEY(GLFW_KEY_COMMA, BACKEND_KEYBOARD_COMMA)
DO_KEY(GLFW_KEY_PERIOD, BACKEND_KEYBOARD_PERIOD)
DO_KEY(GLFW_KEY_SLASH, BACKEND_KEYBOARD_FORWARD_SLASH)
default:
break;
}
break;
}
}
static void WindowFocusCallback(GLFWwindow *window, int focused)
{
(void)window;
window_focus_callback(focused);
}
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
(void)window;
RenderBackend_HandleWindowResize(width, height);
}
static void DragAndDropCallback(GLFWwindow *window, int count, const char **paths)
{
(void)window;
(void)count;
drag_and_drop_callback(paths[0]);
}
static void ErrorCallback(int code, const char *description)
{
Backend_PrintError("GLFW error received (%d): %s", code, description);
}
bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus))
{
drag_and_drop_callback = drag_and_drop_callback_param;
window_focus_callback = window_focus_callback_param;
glfwSetErrorCallback(ErrorCallback);
if (glfwInit() == GL_TRUE)
return true;
Backend_ShowMessageBox("Fatal error", "Could not initialise GLFW3");
return false;
}
void Backend_Deinit(void)
{
if (cursor != NULL)
glfwDestroyCursor(cursor);
glfwTerminate();
}
void Backend_PostWindowCreation(void)
{
// Hook callbacks
glfwSetKeyCallback(window, KeyCallback);
glfwSetWindowFocusCallback(window, WindowFocusCallback);
glfwSetWindowSizeCallback(window, WindowSizeCallback);
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
(void)module_path;
(void)data_path;
// GLFW3 doesn't seem to have a mechanism for this
return false;
}
void Backend_HideMouse(void)
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
// Convert to RGBA, since that's the only thing GLFW3 accepts
unsigned char *rgba_pixels = (unsigned char*)malloc(width * height * 4);
const unsigned char *rgb_pointer = rgb_pixels;
unsigned char *rgba_pointer = rgba_pixels;
if (rgba_pixels != NULL)
{
for (size_t y = 0; y < height; ++y)
{
for (size_t x = 0; x < width; ++x)
{
*rgba_pointer++ = *rgb_pointer++;
*rgba_pointer++ = *rgb_pointer++;
*rgba_pointer++ = *rgb_pointer++;
*rgba_pointer++ = 0xFF;
}
}
GLFWimage glfw_image = {(int)width, (int)height, rgba_pixels};
glfwSetWindowIcon(window, 1, &glfw_image);
free(rgba_pixels);
}
}
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height)
{
GLFWimage glfw_image = {(int)width, (int)height, (unsigned char*)rgba_pixels};
cursor = glfwCreateCursor(&glfw_image, 0, 0);
if (cursor != NULL)
glfwSetCursor(window, cursor);
}
void Backend_EnableDragAndDrop(void)
{
glfwSetDropCallback(window, DragAndDropCallback);
}
bool Backend_SystemTask(bool active)
{
if (glfwWindowShouldClose(window))
return false;
if (active)
glfwPollEvents();
else
glfwWaitEvents();
return true;
}
void Backend_GetKeyboardState(bool *out_keyboard_state)
{
memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state));
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
// GLFW3 doesn't have a message box
Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("ERROR: ", stderr);
vfprintf(stderr, format, argumentList);
fputc('\n', stderr);
va_end(argumentList);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("INFO: ", stdout);
vfprintf(stdout, format, argumentList);
fputc('\n', stdout);
va_end(argumentList);
}
unsigned long Backend_GetTicks(void)
{
return (unsigned long)(glfwGetTime() * 1000.0);
}
void Backend_Delay(unsigned int ticks)
{
#if __cplusplus >= 201103L
// GLFW3 doesn't have a delay function, so here's some butt-ugly C++11
std::this_thread::sleep_for(std::chrono::milliseconds(ticks));
#elif defined(_WIN32)
Sleep(ticks);
#else
usleep(ticks * 1000);
#endif
}

View File

@ -1,100 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <string>
#include "../../Attributes.h"
bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus))
{
(void)drag_and_drop_callback;
(void)window_focus_callback;
return true;
}
void Backend_Deinit(void)
{
}
void Backend_PostWindowCreation(void)
{
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
(void)module_path;
(void)data_path;
return false;
}
void Backend_HideMouse(void)
{
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
(void)rgb_pixels;
(void)width;
(void)height;
}
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height)
{
(void)rgba_pixels;
(void)width;
(void)height;
}
void Backend_EnableDragAndDrop(void)
{
}
bool Backend_SystemTask(bool active)
{
(void)active;
return true;
}
void Backend_GetKeyboardState(bool *keyboard_state)
{
(void)keyboard_state;
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
(void)title;
(void)message;
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
(void)format;
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
(void)format;
}
unsigned long Backend_GetTicks(void)
{
static unsigned long fake_ticks = 0;
fake_ticks += 1000 / 50;
return fake_ticks;
}
void Backend_Delay(unsigned int ticks)
{
(void)ticks;
}

View File

@ -1,260 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../Rendering.h"
#include "../../Attributes.h"
#define DO_KEY(SDL_KEY, BACKEND_KEY) \
case SDL_KEY: \
keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \
break;
static bool keyboard_state[BACKEND_KEYBOARD_TOTAL];
static void (*window_focus_callback)(bool focus);
bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus))
{
window_focus_callback = window_focus_callback_param;
if (SDL_Init(SDL_INIT_VIDEO) == 0)
{
char driver[20];
if (SDL_VideoDriverName(driver, 20) != NULL)
{
Backend_PrintInfo("Selected SDL video driver: %s", driver);
return true;
}
else
{
Backend_PrintError("No SDL video driver initialized!");
SDL_Quit();
}
}
else
{
std::string error_message = std::string("Could not initialise SDL: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error", error_message.c_str());
}
return false;
}
void Backend_Deinit(void)
{
SDL_Quit();
}
void Backend_PostWindowCreation(void)
{
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
(void)module_path;
(void)data_path;
return false;
}
void Backend_HideMouse(void)
{
SDL_ShowCursor(SDL_DISABLE);
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)rgb_pixels, width, height, 24, width * 3, 0x0000FF, 0x00FF00, 0xFF0000, 0);
if (surface != NULL)
{
SDL_WM_SetIcon(surface, NULL);
SDL_FreeSurface(surface);
}
else
{
Backend_PrintError("Couldn't create RGB surface for window icon: %s", SDL_GetError());
}
}
void Backend_SetCursor(const unsigned char *rgb_pixels, size_t width, size_t height)
{
(void)rgb_pixels;
(void)width;
(void)height;
// SDL1 only supports black and white cursors
}
void Backend_EnableDragAndDrop(void)
{
}
bool Backend_SystemTask(bool active)
{
if (!active)
if (!SDL_WaitEvent(NULL))
return false;
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYUP:
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
DO_KEY(SDLK_a, BACKEND_KEYBOARD_A)
DO_KEY(SDLK_b, BACKEND_KEYBOARD_B)
DO_KEY(SDLK_c, BACKEND_KEYBOARD_C)
DO_KEY(SDLK_d, BACKEND_KEYBOARD_D)
DO_KEY(SDLK_e, BACKEND_KEYBOARD_E)
DO_KEY(SDLK_f, BACKEND_KEYBOARD_F)
DO_KEY(SDLK_g, BACKEND_KEYBOARD_G)
DO_KEY(SDLK_h, BACKEND_KEYBOARD_H)
DO_KEY(SDLK_i, BACKEND_KEYBOARD_I)
DO_KEY(SDLK_j, BACKEND_KEYBOARD_J)
DO_KEY(SDLK_k, BACKEND_KEYBOARD_K)
DO_KEY(SDLK_l, BACKEND_KEYBOARD_L)
DO_KEY(SDLK_m, BACKEND_KEYBOARD_M)
DO_KEY(SDLK_n, BACKEND_KEYBOARD_N)
DO_KEY(SDLK_o, BACKEND_KEYBOARD_O)
DO_KEY(SDLK_p, BACKEND_KEYBOARD_P)
DO_KEY(SDLK_q, BACKEND_KEYBOARD_Q)
DO_KEY(SDLK_r, BACKEND_KEYBOARD_R)
DO_KEY(SDLK_s, BACKEND_KEYBOARD_S)
DO_KEY(SDLK_t, BACKEND_KEYBOARD_T)
DO_KEY(SDLK_u, BACKEND_KEYBOARD_U)
DO_KEY(SDLK_v, BACKEND_KEYBOARD_V)
DO_KEY(SDLK_w, BACKEND_KEYBOARD_W)
DO_KEY(SDLK_x, BACKEND_KEYBOARD_X)
DO_KEY(SDLK_y, BACKEND_KEYBOARD_Y)
DO_KEY(SDLK_z, BACKEND_KEYBOARD_Z)
DO_KEY(SDLK_0, BACKEND_KEYBOARD_0)
DO_KEY(SDLK_1, BACKEND_KEYBOARD_1)
DO_KEY(SDLK_2, BACKEND_KEYBOARD_2)
DO_KEY(SDLK_3, BACKEND_KEYBOARD_3)
DO_KEY(SDLK_4, BACKEND_KEYBOARD_4)
DO_KEY(SDLK_5, BACKEND_KEYBOARD_5)
DO_KEY(SDLK_6, BACKEND_KEYBOARD_6)
DO_KEY(SDLK_7, BACKEND_KEYBOARD_7)
DO_KEY(SDLK_8, BACKEND_KEYBOARD_8)
DO_KEY(SDLK_9, BACKEND_KEYBOARD_9)
DO_KEY(SDLK_F1, BACKEND_KEYBOARD_F1)
DO_KEY(SDLK_F2, BACKEND_KEYBOARD_F2)
DO_KEY(SDLK_F3, BACKEND_KEYBOARD_F3)
DO_KEY(SDLK_F4, BACKEND_KEYBOARD_F4)
DO_KEY(SDLK_F5, BACKEND_KEYBOARD_F5)
DO_KEY(SDLK_F6, BACKEND_KEYBOARD_F6)
DO_KEY(SDLK_F7, BACKEND_KEYBOARD_F7)
DO_KEY(SDLK_F8, BACKEND_KEYBOARD_F8)
DO_KEY(SDLK_F9, BACKEND_KEYBOARD_F9)
DO_KEY(SDLK_F10, BACKEND_KEYBOARD_F10)
DO_KEY(SDLK_F11, BACKEND_KEYBOARD_F11)
DO_KEY(SDLK_F12, BACKEND_KEYBOARD_F12)
DO_KEY(SDLK_UP, BACKEND_KEYBOARD_UP)
DO_KEY(SDLK_DOWN, BACKEND_KEYBOARD_DOWN)
DO_KEY(SDLK_LEFT, BACKEND_KEYBOARD_LEFT)
DO_KEY(SDLK_RIGHT, BACKEND_KEYBOARD_RIGHT)
DO_KEY(SDLK_ESCAPE, BACKEND_KEYBOARD_ESCAPE)
DO_KEY(SDLK_BACKQUOTE, BACKEND_KEYBOARD_BACK_QUOTE)
DO_KEY(SDLK_TAB, BACKEND_KEYBOARD_TAB)
DO_KEY(SDLK_CAPSLOCK, BACKEND_KEYBOARD_CAPS_LOCK)
DO_KEY(SDLK_LSHIFT, BACKEND_KEYBOARD_LEFT_SHIFT)
DO_KEY(SDLK_LCTRL, BACKEND_KEYBOARD_LEFT_CTRL)
DO_KEY(SDLK_LALT, BACKEND_KEYBOARD_LEFT_ALT)
DO_KEY(SDLK_SPACE, BACKEND_KEYBOARD_SPACE)
DO_KEY(SDLK_RALT, BACKEND_KEYBOARD_RIGHT_ALT)
DO_KEY(SDLK_RCTRL, BACKEND_KEYBOARD_RIGHT_CTRL)
DO_KEY(SDLK_RSHIFT, BACKEND_KEYBOARD_RIGHT_SHIFT)
DO_KEY(SDLK_RETURN, BACKEND_KEYBOARD_ENTER)
DO_KEY(SDLK_BACKSPACE, BACKEND_KEYBOARD_BACKSPACE)
DO_KEY(SDLK_MINUS, BACKEND_KEYBOARD_MINUS)
DO_KEY(SDLK_EQUALS, BACKEND_KEYBOARD_EQUALS)
DO_KEY(SDLK_LEFTBRACKET, BACKEND_KEYBOARD_LEFT_BRACKET)
DO_KEY(SDLK_RIGHTBRACKET, BACKEND_KEYBOARD_RIGHT_BRACKET)
DO_KEY(SDLK_BACKSLASH, BACKEND_KEYBOARD_BACK_SLASH)
DO_KEY(SDLK_SEMICOLON, BACKEND_KEYBOARD_SEMICOLON)
DO_KEY(SDLK_QUOTE, BACKEND_KEYBOARD_APOSTROPHE)
DO_KEY(SDLK_COMMA, BACKEND_KEYBOARD_COMMA)
DO_KEY(SDLK_PERIOD, BACKEND_KEYBOARD_PERIOD)
DO_KEY(SDLK_SLASH, BACKEND_KEYBOARD_FORWARD_SLASH)
default:
break;
}
break;
case SDL_ACTIVEEVENT:
if (event.active.state & SDL_APPINPUTFOCUS)
{
window_focus_callback(event.active.gain);
}
break;
case SDL_VIDEORESIZE:
RenderBackend_HandleWindowResize(event.resize.w, event.resize.h);
break;
case SDL_QUIT:
return false;
}
}
return true;
}
void Backend_GetKeyboardState(bool *out_keyboard_state)
{
memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state));
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("ERROR: ", stderr);
vfprintf(stderr, format, argumentList);
fputc('\n', stderr);
va_end(argumentList);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("INFO: ", stdout);
vfprintf(stdout, format, argumentList);
fputc('\n', stdout);
va_end(argumentList);
}
unsigned long Backend_GetTicks(void)
{
return SDL_GetTicks();
}
void Backend_Delay(unsigned int ticks)
{
SDL_Delay(ticks);
}

View File

@ -1,356 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../Rendering.h"
#include "../Shared/SDL.h"
#include "../../Attributes.h"
#define DO_KEY(SDL_KEY, BACKEND_KEY) \
case SDL_KEY: \
keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \
break;
static bool keyboard_state[BACKEND_KEYBOARD_TOTAL];
static unsigned char *cursor_surface_pixels;
static SDL_Surface *cursor_surface;
static SDL_Cursor *cursor;
static void (*drag_and_drop_callback)(const char *path);
static void (*window_focus_callback)(bool focus);
bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus))
{
drag_and_drop_callback = drag_and_drop_callback_param;
window_focus_callback = window_focus_callback_param;
if (SDL_Init(SDL_INIT_EVENTS) == 0)
{
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0)
{
Backend_PrintInfo("Available SDL video drivers:");
for (int i = 0; i < SDL_GetNumVideoDrivers(); ++i)
Backend_PrintInfo("%s", SDL_GetVideoDriver(i));
const char *driver = SDL_GetCurrentVideoDriver();
if (driver != NULL)
{
Backend_PrintInfo("Selected SDL video driver: %s", driver);
return true;
}
else
{
Backend_PrintError("No SDL video driver initialized!");
}
}
else
{
std::string error_message = std::string("Could not initialise SDL video subsystem: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error", error_message.c_str());
}
SDL_Quit();
}
else
{
std::string error_message = std::string("Could not initialise SDL: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error", error_message.c_str());
}
return false;
}
void Backend_Deinit(void)
{
if (cursor != NULL)
SDL_FreeCursor(cursor);
if (cursor_surface != NULL)
SDL_FreeSurface(cursor_surface);
free(cursor_surface_pixels);
SDL_Quit();
}
void Backend_PostWindowCreation(void)
{
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
#ifdef _WIN32
// SDL_GetBasePath returns a UTF-8 string, but Windows' fopen uses (extended?) ASCII.
// This is apparently a problem for accented characters, as they will make fopen fail.
// So, instead, we rely on argv[0], as that will put the accented characters in a
// format Windows will understand.
(void)module_path;
(void)data_path;
return false;
#else
char *base_path = SDL_GetBasePath();
if (base_path == NULL)
return false;
// Trim the trailing '/'
size_t base_path_length = strlen(base_path);
base_path[base_path_length - 1] = '\0';
*module_path = base_path;
SDL_free(base_path);
*data_path = *module_path + "/data";
return true;
#endif
}
void Backend_HideMouse(void)
{
SDL_ShowCursor(SDL_DISABLE);
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom((void*)rgb_pixels, width, height, 0, width * 3, SDL_PIXELFORMAT_RGB24);
if (surface != NULL)
{
SDL_SetWindowIcon(window, surface);
SDL_FreeSurface(surface);
}
else
{
Backend_PrintError("Couldn't create RGB surface for window icon: %s", SDL_GetError());
}
}
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height)
{
cursor_surface_pixels = (unsigned char*)malloc(width * height * 4);
if (cursor_surface_pixels != NULL)
{
memcpy(cursor_surface_pixels, rgba_pixels, width * height * 4);
cursor_surface = SDL_CreateRGBSurfaceWithFormatFrom(cursor_surface_pixels, width, height, 0, width * 4, SDL_PIXELFORMAT_RGBA32);
if (cursor_surface != NULL)
{
cursor = SDL_CreateColorCursor(cursor_surface, 0, 0);
if (cursor != NULL)
SDL_SetCursor(cursor);
}
}
else
{
Backend_PrintError("Failed to allocate memory for cursor surface");
}
}
void Backend_EnableDragAndDrop(void)
{
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
}
bool Backend_SystemTask(bool active)
{
if (!active)
if (!SDL_WaitEvent(NULL))
return false;
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYUP:
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
DO_KEY(SDLK_a, BACKEND_KEYBOARD_A)
DO_KEY(SDLK_b, BACKEND_KEYBOARD_B)
DO_KEY(SDLK_c, BACKEND_KEYBOARD_C)
DO_KEY(SDLK_d, BACKEND_KEYBOARD_D)
DO_KEY(SDLK_e, BACKEND_KEYBOARD_E)
DO_KEY(SDLK_f, BACKEND_KEYBOARD_F)
DO_KEY(SDLK_g, BACKEND_KEYBOARD_G)
DO_KEY(SDLK_h, BACKEND_KEYBOARD_H)
DO_KEY(SDLK_i, BACKEND_KEYBOARD_I)
DO_KEY(SDLK_j, BACKEND_KEYBOARD_J)
DO_KEY(SDLK_k, BACKEND_KEYBOARD_K)
DO_KEY(SDLK_l, BACKEND_KEYBOARD_L)
DO_KEY(SDLK_m, BACKEND_KEYBOARD_M)
DO_KEY(SDLK_n, BACKEND_KEYBOARD_N)
DO_KEY(SDLK_o, BACKEND_KEYBOARD_O)
DO_KEY(SDLK_p, BACKEND_KEYBOARD_P)
DO_KEY(SDLK_q, BACKEND_KEYBOARD_Q)
DO_KEY(SDLK_r, BACKEND_KEYBOARD_R)
DO_KEY(SDLK_s, BACKEND_KEYBOARD_S)
DO_KEY(SDLK_t, BACKEND_KEYBOARD_T)
DO_KEY(SDLK_u, BACKEND_KEYBOARD_U)
DO_KEY(SDLK_v, BACKEND_KEYBOARD_V)
DO_KEY(SDLK_w, BACKEND_KEYBOARD_W)
DO_KEY(SDLK_x, BACKEND_KEYBOARD_X)
DO_KEY(SDLK_y, BACKEND_KEYBOARD_Y)
DO_KEY(SDLK_z, BACKEND_KEYBOARD_Z)
DO_KEY(SDLK_0, BACKEND_KEYBOARD_0)
DO_KEY(SDLK_1, BACKEND_KEYBOARD_1)
DO_KEY(SDLK_2, BACKEND_KEYBOARD_2)
DO_KEY(SDLK_3, BACKEND_KEYBOARD_3)
DO_KEY(SDLK_4, BACKEND_KEYBOARD_4)
DO_KEY(SDLK_5, BACKEND_KEYBOARD_5)
DO_KEY(SDLK_6, BACKEND_KEYBOARD_6)
DO_KEY(SDLK_7, BACKEND_KEYBOARD_7)
DO_KEY(SDLK_8, BACKEND_KEYBOARD_8)
DO_KEY(SDLK_9, BACKEND_KEYBOARD_9)
DO_KEY(SDLK_F1, BACKEND_KEYBOARD_F1)
DO_KEY(SDLK_F2, BACKEND_KEYBOARD_F2)
DO_KEY(SDLK_F3, BACKEND_KEYBOARD_F3)
DO_KEY(SDLK_F4, BACKEND_KEYBOARD_F4)
DO_KEY(SDLK_F5, BACKEND_KEYBOARD_F5)
DO_KEY(SDLK_F6, BACKEND_KEYBOARD_F6)
DO_KEY(SDLK_F7, BACKEND_KEYBOARD_F7)
DO_KEY(SDLK_F8, BACKEND_KEYBOARD_F8)
DO_KEY(SDLK_F9, BACKEND_KEYBOARD_F9)
DO_KEY(SDLK_F10, BACKEND_KEYBOARD_F10)
DO_KEY(SDLK_F11, BACKEND_KEYBOARD_F11)
DO_KEY(SDLK_F12, BACKEND_KEYBOARD_F12)
DO_KEY(SDLK_UP, BACKEND_KEYBOARD_UP)
DO_KEY(SDLK_DOWN, BACKEND_KEYBOARD_DOWN)
DO_KEY(SDLK_LEFT, BACKEND_KEYBOARD_LEFT)
DO_KEY(SDLK_RIGHT, BACKEND_KEYBOARD_RIGHT)
DO_KEY(SDLK_ESCAPE, BACKEND_KEYBOARD_ESCAPE)
DO_KEY(SDLK_BACKQUOTE, BACKEND_KEYBOARD_BACK_QUOTE)
DO_KEY(SDLK_TAB, BACKEND_KEYBOARD_TAB)
DO_KEY(SDLK_CAPSLOCK, BACKEND_KEYBOARD_CAPS_LOCK)
DO_KEY(SDLK_LSHIFT, BACKEND_KEYBOARD_LEFT_SHIFT)
DO_KEY(SDLK_LCTRL, BACKEND_KEYBOARD_LEFT_CTRL)
DO_KEY(SDLK_LALT, BACKEND_KEYBOARD_LEFT_ALT)
DO_KEY(SDLK_SPACE, BACKEND_KEYBOARD_SPACE)
DO_KEY(SDLK_RALT, BACKEND_KEYBOARD_RIGHT_ALT)
DO_KEY(SDLK_RCTRL, BACKEND_KEYBOARD_RIGHT_CTRL)
DO_KEY(SDLK_RSHIFT, BACKEND_KEYBOARD_RIGHT_SHIFT)
DO_KEY(SDLK_RETURN, BACKEND_KEYBOARD_ENTER)
DO_KEY(SDLK_BACKSPACE, BACKEND_KEYBOARD_BACKSPACE)
DO_KEY(SDLK_MINUS, BACKEND_KEYBOARD_MINUS)
DO_KEY(SDLK_EQUALS, BACKEND_KEYBOARD_EQUALS)
DO_KEY(SDLK_LEFTBRACKET, BACKEND_KEYBOARD_LEFT_BRACKET)
DO_KEY(SDLK_RIGHTBRACKET, BACKEND_KEYBOARD_RIGHT_BRACKET)
DO_KEY(SDLK_BACKSLASH, BACKEND_KEYBOARD_BACK_SLASH)
DO_KEY(SDLK_SEMICOLON, BACKEND_KEYBOARD_SEMICOLON)
DO_KEY(SDLK_QUOTE, BACKEND_KEYBOARD_APOSTROPHE)
DO_KEY(SDLK_COMMA, BACKEND_KEYBOARD_COMMA)
DO_KEY(SDLK_PERIOD, BACKEND_KEYBOARD_PERIOD)
DO_KEY(SDLK_SLASH, BACKEND_KEYBOARD_FORWARD_SLASH)
default:
break;
}
break;
case SDL_JOYDEVICEADDED:
ControllerBackend_JoystickConnect(event.jdevice.which);
break;
case SDL_JOYDEVICEREMOVED:
ControllerBackend_JoystickDisconnect(event.jdevice.which);
break;
case SDL_DROPFILE:
drag_and_drop_callback(event.drop.file);
SDL_free(event.drop.file);
break;
case SDL_WINDOWEVENT:
switch (event.window.event)
{
case SDL_WINDOWEVENT_FOCUS_LOST:
window_focus_callback(false);
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
window_focus_callback(true);
break;
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
RenderBackend_HandleWindowResize(event.window.data1, event.window.data2);
break;
}
break;
case SDL_QUIT:
return false;
case SDL_RENDER_TARGETS_RESET:
RenderBackend_HandleRenderTargetLoss();
break;
}
}
return true;
}
void Backend_GetKeyboardState(bool *out_keyboard_state)
{
memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state));
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message);
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, window) != 0)
Backend_PrintError("Was also unable to display a message box containing the error: %s", SDL_GetError());
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("ERROR: ", stderr);
vfprintf(stderr, format, argumentList);
fputc('\n', stderr);
va_end(argumentList);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
va_list argumentList;
va_start(argumentList, format);
fputs("INFO: ", stdout);
vfprintf(stdout, format, argumentList);
fputc('\n', stdout);
va_end(argumentList);
}
unsigned long Backend_GetTicks(void)
{
return SDL_GetTicks();
}
void Backend_Delay(unsigned int ticks)
{
SDL_Delay(ticks);
}

View File

@ -1,200 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Misc.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <coreinit/thread.h>
#include <padscore/kpad.h>
#include <vpad/input.h>
#include <whb/log.h>
#include <whb/log_udp.h>
#include <whb/proc.h>
#include <whb/sdcard.h>
static unsigned long ticks_per_second;
bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus))
{
(void)drag_and_drop_callback;
(void)window_focus_callback;
WHBProcInit();
if (!WHBMountSdCard())
return FALSE;
VPADInit();
WPADInit();
KPADInit();
// Enable Wii U Pro Controllers to be connected
WPADEnableURCC(1);
WHBLogUdpInit();
ticks_per_second = OSGetSystemInfo()->busClockSpeed / 4;
return true;
}
void Backend_Deinit(void)
{
WHBLogUdpDeinit();
WPADShutdown();
VPADShutdown();
WHBUnmountSdCard();
WHBProcShutdown();
}
void Backend_PostWindowCreation(void)
{
}
bool Backend_GetPaths(std::string *module_path, std::string *data_path)
{
*module_path = WHBGetSdCardMountPath();
#ifdef JAPANESE
*module_path += "/CSE2-portable-jp";
#else
*module_path += "/CSE2-portable-en";
#endif
*data_path = *module_path + "/data";
return true;
}
void Backend_HideMouse(void)
{
}
void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height)
{
(void)rgb_pixels;
(void)width;
(void)height;
}
void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height)
{
(void)rgba_pixels;
(void)width;
(void)height;
}
void Backend_EnableDragAndDrop(void)
{
}
bool Backend_SystemTask(bool active)
{
(void)active;
return WHBProcIsRunning();
}
void Backend_GetKeyboardState(bool *keyboard_state)
{
memset(keyboard_state, 0, sizeof(bool) * BACKEND_KEYBOARD_TOTAL);
// Read gamepad
static uint32_t vpad_buttons;
VPADStatus vpad_status;
if (VPADRead(VPAD_CHAN_0, &vpad_status, 1, NULL) == 1)
vpad_buttons = vpad_status.hold;
keyboard_state[BACKEND_KEYBOARD_UP] |= vpad_buttons & (VPAD_BUTTON_UP | VPAD_STICK_L_EMULATION_UP);
keyboard_state[BACKEND_KEYBOARD_DOWN] |= vpad_buttons & (VPAD_BUTTON_DOWN | VPAD_STICK_L_EMULATION_DOWN);
keyboard_state[BACKEND_KEYBOARD_LEFT] |= vpad_buttons & (VPAD_BUTTON_LEFT | VPAD_STICK_L_EMULATION_LEFT);
keyboard_state[BACKEND_KEYBOARD_RIGHT] |= vpad_buttons & (VPAD_BUTTON_RIGHT | VPAD_STICK_L_EMULATION_RIGHT);
keyboard_state[BACKEND_KEYBOARD_Z] |= vpad_buttons & VPAD_BUTTON_B; // Jump
keyboard_state[BACKEND_KEYBOARD_X] |= vpad_buttons & VPAD_BUTTON_Y; // Shoot
keyboard_state[BACKEND_KEYBOARD_Q] |= vpad_buttons & (VPAD_BUTTON_A | VPAD_BUTTON_PLUS); // Inventory
keyboard_state[BACKEND_KEYBOARD_W] |= vpad_buttons & (VPAD_BUTTON_X | VPAD_BUTTON_MINUS); // Map
keyboard_state[BACKEND_KEYBOARD_A] |= vpad_buttons & (VPAD_BUTTON_L | VPAD_BUTTON_ZL | VPAD_STICK_R_EMULATION_LEFT); // Weapon left
keyboard_state[BACKEND_KEYBOARD_S] |= vpad_buttons & (VPAD_BUTTON_R | VPAD_BUTTON_ZR | VPAD_STICK_R_EMULATION_RIGHT); // Weapon right
// Read Wii U Pro Controller
static uint32_t kpad_buttons;
KPADStatus kpad_status;
if (KPADRead(WPAD_CHAN_0, &kpad_status, 1) == 1)
kpad_buttons = kpad_status.pro.hold;
keyboard_state[BACKEND_KEYBOARD_UP] |= kpad_buttons & (WPAD_PRO_BUTTON_UP | WPAD_PRO_STICK_L_EMULATION_UP);
keyboard_state[BACKEND_KEYBOARD_DOWN] |= kpad_buttons & (WPAD_PRO_BUTTON_DOWN | WPAD_PRO_STICK_L_EMULATION_DOWN);
keyboard_state[BACKEND_KEYBOARD_LEFT] |= kpad_buttons & (WPAD_PRO_BUTTON_LEFT | WPAD_PRO_STICK_L_EMULATION_LEFT);
keyboard_state[BACKEND_KEYBOARD_RIGHT] |= kpad_buttons & (WPAD_PRO_BUTTON_RIGHT | WPAD_PRO_STICK_L_EMULATION_RIGHT);
keyboard_state[BACKEND_KEYBOARD_Z] |= kpad_buttons & WPAD_PRO_BUTTON_B; // Jump
keyboard_state[BACKEND_KEYBOARD_X] |= kpad_buttons & WPAD_PRO_BUTTON_Y; // Shoot
keyboard_state[BACKEND_KEYBOARD_Q] |= kpad_buttons & (WPAD_PRO_BUTTON_A | WPAD_PRO_BUTTON_PLUS); // Inventory
keyboard_state[BACKEND_KEYBOARD_W] |= kpad_buttons & (WPAD_PRO_BUTTON_X | WPAD_PRO_BUTTON_MINUS); // Map
keyboard_state[BACKEND_KEYBOARD_A] |= kpad_buttons & (WPAD_PRO_TRIGGER_L | WPAD_PRO_TRIGGER_ZL | WPAD_PRO_STICK_R_EMULATION_LEFT); // Weapon left
keyboard_state[BACKEND_KEYBOARD_S] |= kpad_buttons & (WPAD_PRO_TRIGGER_R | WPAD_PRO_TRIGGER_ZR | WPAD_PRO_STICK_R_EMULATION_RIGHT); // Weapon right
}
void Backend_ShowMessageBox(const char *title, const char *message)
{
Backend_PrintInfo("ShowMessageBox - %s - %s", title, message);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...)
{
char message_buffer[0x100];
va_list argument_list;
va_start(argument_list, format);
vsnprintf(message_buffer, sizeof(message_buffer), format, argument_list);
va_end(argument_list);
WHBLogPrint("ERROR:");
WHBLogPrint(message_buffer);
}
ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...)
{
char message_buffer[0x100];
va_list argument_list;
va_start(argument_list, format);
vsnprintf(message_buffer, sizeof(message_buffer), format, argument_list);
va_end(argument_list);
WHBLogPrint("INFO:");
WHBLogPrint(message_buffer);
}
unsigned long Backend_GetTicks(void)
{
static uint64_t accumulator;
static unsigned long last_tick;
unsigned long current_tick = OSGetTick();
accumulator += current_tick - last_tick;
last_tick = current_tick;
return (accumulator * 1000) / ticks_per_second;
}
void Backend_Delay(unsigned int ticks)
{
OSSleepTicks((ticks * ticks_per_second) / 1000);
}

View File

@ -1,35 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#pragma once
#include <stddef.h>
typedef struct RenderBackend_Surface RenderBackend_Surface;
typedef struct RenderBackend_GlyphAtlas RenderBackend_GlyphAtlas;
typedef struct RenderBackend_Rect
{
long left;
long top;
long right;
long bottom;
} RenderBackend_Rect;
RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen);
void RenderBackend_Deinit(void);
void RenderBackend_DrawScreen(void);
RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height, bool render_target);
void RenderBackend_FreeSurface(RenderBackend_Surface *surface);
bool RenderBackend_IsSurfaceLost(RenderBackend_Surface *surface);
void RenderBackend_RestoreSurface(RenderBackend_Surface *surface);
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height);
void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key);
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue);
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height);
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas);
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch);
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue);
void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height);
void RenderBackend_HandleRenderTargetLoss(void);
void RenderBackend_HandleWindowResize(size_t width, size_t height);

View File

@ -1,501 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Rendering.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <3ds.h>
#include <citro3d.h>
#include <citro2d.h>
#include "../Misc.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
// Used to transfer the final rendered display to the framebuffer
#define DISPLAY_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
// Used to convert textures to 3DS tiled format
#define TEXTURE_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
typedef struct RenderBackend_Surface
{
C3D_Tex texture;
C3D_RenderTarget *render_target;
} RenderBackend_Surface;
typedef struct RenderBackend_GlyphAtlas
{
C3D_Tex texture;
unsigned char *local_texture_buffer;
} RenderBackend_GlyphAtlas;
static RenderBackend_GlyphAtlas *glyph_atlas;
static RenderBackend_Surface *glyph_destination_surface;
static C2D_ImageTint glyph_tint;
static C3D_RenderTarget *screen_render_target;
static RenderBackend_Surface *framebuffer_surface;
static size_t framebuffer_surface_width;
static size_t framebuffer_surface_height;
static bool frame_started;
static size_t RoundUpToPowerOfTwo(size_t value)
{
size_t accumulator = 1;
while (accumulator < value)
accumulator <<= 1;
return accumulator;
}
static void EnableAlpha(bool enabled)
{
static bool previous_setting = true;
if (enabled != previous_setting)
{
// Setting will not take effect mid-frame, so
// break-up the current frame if we have to.
if (frame_started)
C2D_Flush();
if (enabled)
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
else
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ZERO, GPU_ONE, GPU_ZERO);
previous_setting = enabled;
}
}
static void SelectRenderTarget(C3D_RenderTarget *render_target)
{
static C3D_RenderTarget *previous_render_target = NULL;
if (render_target != previous_render_target)
{
previous_render_target = render_target;
C2D_SceneBegin(render_target);
}
}
static void BeginRendering(void)
{
if (!frame_started)
{
C3D_FrameBegin(0);
frame_started = true;
}
}
static void EndRendering(void)
{
if (frame_started)
{
C3D_FrameEnd(0);
frame_started = false;
}
}
RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen)
{
if (C3D_Init(C3D_DEFAULT_CMDBUF_SIZE))
{
if (C2D_Init(C2D_DEFAULT_MAX_OBJECTS))
{
C2D_Prepare();
C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL);
screen_render_target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, -1);
if (screen_render_target != NULL)
{
C3D_RenderTargetSetOutput(screen_render_target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
framebuffer_surface = RenderBackend_CreateSurface(screen_width, screen_height, true);
if (framebuffer_surface != NULL)
{
framebuffer_surface_width = screen_width;
framebuffer_surface_height = screen_height;
return framebuffer_surface;
}
else
{
Backend_PrintError("RenderBackend_CreateSurface failed in RenderBackend_Init");
}
C3D_RenderTargetDelete(screen_render_target);
}
else
{
Backend_PrintError("C2D_CreateScreenTarget failed in RenderBackend_Init");
}
C2D_Fini();
}
else
{
Backend_PrintError("C2D_Init failed in RenderBackend_Init");
}
C3D_Fini();
}
else
{
Backend_PrintError("C3D_Init failed in RenderBackend_Init");
}
return NULL;
}
void RenderBackend_Deinit(void)
{
// Just in case
EndRendering();
RenderBackend_FreeSurface(framebuffer_surface);
C3D_RenderTargetDelete(screen_render_target);
C2D_Fini();
C3D_Fini();
}
void RenderBackend_DrawScreen(void)
{
EndRendering();
EnableAlpha(false);
const float texture_left = 0.0f;
const float texture_top = 0.0f;
const float texture_right = (float)framebuffer_surface_width / framebuffer_surface->texture.width;
const float texture_bottom = (float)framebuffer_surface_height / framebuffer_surface->texture.height;
Tex3DS_SubTexture subtexture;
subtexture.width = framebuffer_surface_width;
subtexture.height = framebuffer_surface_height;
subtexture.left = texture_left;
subtexture.top = 1.0f - texture_top;
subtexture.right = texture_right;
subtexture.bottom = 1.0f - texture_bottom;
C2D_Image image;
image.tex = &framebuffer_surface->texture;
image.subtex = &subtexture;
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
C2D_TargetClear(screen_render_target, C2D_Color32(0, 0, 0, 0xFF));
SelectRenderTarget(screen_render_target);
C2D_DrawImageAt(image, (400 - framebuffer_surface_width) / 2, (240 - framebuffer_surface_height) / 2, 0.0f);
C3D_FrameEnd(0);
}
RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height, bool render_target)
{
// Just in case
EndRendering();
RenderBackend_Surface *surface = (RenderBackend_Surface*)malloc(sizeof(RenderBackend_Surface));
if (surface != NULL)
{
surface->render_target = NULL;
memset(&surface->texture, 0, sizeof(surface->texture));
if ((render_target ? C3D_TexInitVRAM : C3D_TexInit)(&surface->texture, RoundUpToPowerOfTwo(width), RoundUpToPowerOfTwo(height), GPU_RGBA8))
{
C3D_TexSetFilter(&surface->texture, GPU_NEAREST, GPU_NEAREST);
if (!render_target)
{
return surface;
}
else
{
surface->render_target = C3D_RenderTargetCreateFromTex(&surface->texture, GPU_TEXFACE_2D, 0, -1);
if (surface->render_target != NULL)
{
C2D_TargetClear(surface->render_target, C2D_Color32(0, 0, 0, 0xFF));
return surface;
}
else
{
Backend_PrintError("C3D_RenderTargetCreateFromTex failed in RenderBackend_CreateSurface");
}
}
C3D_TexDelete(&surface->texture);
}
else
{
Backend_PrintError("C3D_TexInit/C3D_TexInitVRAM failed in RenderBackend_CreateSurface");
}
free(surface);
}
return NULL;
}
void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
{
// Just in case
EndRendering();
if (surface->render_target != NULL)
C3D_RenderTargetDelete(surface->render_target);
C3D_TexDelete(&surface->texture);
free(surface);
}
bool RenderBackend_IsSurfaceLost(RenderBackend_Surface *surface)
{
(void)surface;
return false;
}
void RenderBackend_RestoreSurface(RenderBackend_Surface *surface)
{
(void)surface;
}
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
{
// If we upload while drawing, we get corruption (visible after stage transitions)
EndRendering();
unsigned char *abgr_buffer = (unsigned char*)linearAlloc(surface->texture.width * surface->texture.height * 4);
if (abgr_buffer != NULL)
{
const unsigned char *src = pixels;
// Convert from colour-keyed RGB to ABGR
for (size_t h = 0; h < height; ++h)
{
unsigned char *dst = &abgr_buffer[h * surface->texture.width * 4];
for (size_t w = 0; w < width; ++w)
{
unsigned char r = *src++;
unsigned char g = *src++;
unsigned char b = *src++;
*dst++ = r == 0 && g == 0 && b == 0 ? 0 : 0xFF;
*dst++ = b;
*dst++ = g;
*dst++ = r;
}
}
GSPGPU_FlushDataCache(abgr_buffer, surface->texture.width * surface->texture.height * 4);
C3D_SyncDisplayTransfer((u32*)abgr_buffer, GX_BUFFER_DIM(surface->texture.width, surface->texture.height), (u32*)surface->texture.data, GX_BUFFER_DIM(surface->texture.width, surface->texture.height), TEXTURE_TRANSFER_FLAGS);
linearFree(abgr_buffer);
}
else
{
Backend_PrintError("Couldn't allocate memory for RenderBackend_UploadSurface");
}
}
void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
{
EnableAlpha(colour_key);
BeginRendering();
const float texture_left = (float)rect->left / source_surface->texture.width;
const float texture_top = (float)(source_surface->texture.height - rect->top) / source_surface->texture.height;
const float texture_right = (float)rect->right / source_surface->texture.width;
const float texture_bottom = (float)(source_surface->texture.height - rect->bottom) / source_surface->texture.height;
Tex3DS_SubTexture subtexture;
subtexture.width = rect->right - rect->left;
subtexture.height = rect->bottom - rect->top;
subtexture.left = texture_left;
subtexture.top = texture_top;
subtexture.right = texture_right;
subtexture.bottom = texture_bottom;
C2D_Image image;
image.tex = &source_surface->texture;
image.subtex = &subtexture;
SelectRenderTarget(destination_surface->render_target);
C2D_DrawImageAt(image, x, y, 0.0f);
}
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue)
{
EnableAlpha(false);
BeginRendering();
SelectRenderTarget(surface->render_target);
C2D_DrawRectSolid(rect->left, rect->top, 0.0f, rect->right - rect->left, rect->bottom - rect->top, C2D_Color32(red, green, blue, red == 0 && green == 0 && blue == 0 ? 0 : 0xFF));
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
// Just in case
EndRendering();
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
width = RoundUpToPowerOfTwo(width);
height = RoundUpToPowerOfTwo(height);
atlas->local_texture_buffer = (unsigned char*)linearAlloc(width * height * 4);
if (atlas->local_texture_buffer != NULL)
{
memset(&atlas->texture, 0, sizeof(atlas->texture));
if (C3D_TexInit(&atlas->texture, width, height, GPU_RGBA8))
{
C3D_TexSetFilter(&atlas->texture, GPU_NEAREST, GPU_NEAREST);
return atlas;
}
else
{
Backend_PrintError("C3D_TexInit failed in RenderBackend_CreateGlyphAtlas");
}
linearFree(atlas->local_texture_buffer);
}
else
{
Backend_PrintError("linearAlloc failed in RenderBackend_CreateGlyphAtlas");
}
free(atlas);
}
else
{
Backend_PrintError("malloc failed in RenderBackend_CreateGlyphAtlas");
}
return NULL;
}
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas)
{
// Just in case
EndRendering();
C3D_TexDelete(&atlas->texture);
linearFree(atlas->local_texture_buffer);
free(atlas);
}
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
{
// This might be needed, but right now it actually *causes*
// corruption rather than prevent it, so it's been disabled
// (it causes the 'Studio Pixel presents' text to appear incomplete).
// EndRendering();
for (size_t h = 0; h < height; ++h)
{
const unsigned char *source_pointer = &pixels[h * pitch];
unsigned char *destination_pointer = &atlas->local_texture_buffer[((y + h) * atlas->texture.width + x) * 4];
for (size_t w = 0; w < width; ++w)
{
*destination_pointer++ = *source_pointer++;
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
}
}
GSPGPU_FlushDataCache(atlas->local_texture_buffer, atlas->texture.width * atlas->texture.height * 4);
C3D_SyncDisplayTransfer((u32*)atlas->local_texture_buffer, GX_BUFFER_DIM(atlas->texture.width, atlas->texture.height), (u32*)atlas->texture.data, GX_BUFFER_DIM(atlas->texture.width, atlas->texture.height), TEXTURE_TRANSFER_FLAGS);
}
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
{
EnableAlpha(true);
glyph_atlas = atlas;
glyph_destination_surface = destination_surface;
C2D_PlainImageTint(&glyph_tint, C2D_Color32(red, green, blue, 0xFF), 1.0f);
}
void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height)
{
BeginRendering();
SelectRenderTarget(glyph_destination_surface->render_target);
const float texture_left = (float)glyph_x / glyph_atlas->texture.width;
const float texture_top = (float)(glyph_atlas->texture.height - glyph_y) / glyph_atlas->texture.height;
const float texture_right = (float)(glyph_x + glyph_width) / glyph_atlas->texture.width;
const float texture_bottom = (float)(glyph_atlas->texture.height - (glyph_y + glyph_height)) / glyph_atlas->texture.height;
Tex3DS_SubTexture subtexture;
subtexture.width = glyph_width;
subtexture.height = glyph_height;
subtexture.left = texture_left;
subtexture.top = texture_top;
subtexture.right = texture_right;
subtexture.bottom = texture_bottom;
C2D_Image image;
image.tex = &glyph_atlas->texture;
image.subtex = &subtexture;
C2D_DrawImageAt(image, x, y, 0.0f, &glyph_tint);
}
void RenderBackend_HandleRenderTargetLoss(void)
{
// No problem for us
}
void RenderBackend_HandleWindowResize(size_t width, size_t height)
{
(void)width;
(void)height;
// Will never happen
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
// I would use -DUSE_OPENGLES2 when RENDERER=OpenGLES2 is passed instead, but CMake likes to rebuild the entire
// project if I do that, and Make doesn't bother rebuilding anything at all. This method avoids both of those problems.
#define USE_OPENGLES2
#include "OpenGL3.cpp"

View File

@ -1,277 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Rendering.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../Misc.h"
#include "../Shared/SDL.h"
typedef struct RenderBackend_Surface
{
SDL_Surface *sdlsurface;
} RenderBackend_Surface;
typedef struct RenderBackend_GlyphAtlas
{
SDL_Surface *sdlsurface;
} RenderBackend_GlyphAtlas;
SDL_Window *window;
static SDL_Surface *window_sdlsurface;
static RenderBackend_Surface framebuffer;
static RenderBackend_GlyphAtlas *glyph_atlas;
static RenderBackend_Surface *glyph_destination_surface;
static void RectToSDLRect(const RenderBackend_Rect *rect, SDL_Rect *sdl_rect)
{
sdl_rect->x = (int)rect->left;
sdl_rect->y = (int)rect->top;
sdl_rect->w = (int)(rect->right - rect->left);
sdl_rect->h = (int)(rect->bottom - rect->top);
if (sdl_rect->w < 0)
sdl_rect->w = 0;
if (sdl_rect->h < 0)
sdl_rect->h = 0;
}
RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen)
{
window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, 0);
if (window != NULL)
{
if (fullscreen)
if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) < 0)
Backend_PrintError("Could not set window to fullscreen: %s", SDL_GetError());
window_sdlsurface = SDL_GetWindowSurface(window);
if (window_sdlsurface != NULL)
{
framebuffer.sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, window_sdlsurface->w, window_sdlsurface->h, 0, SDL_PIXELFORMAT_RGB24);
if (framebuffer.sdlsurface != NULL)
{
Backend_PostWindowCreation();
return &framebuffer;
}
std::string error_message = std::string("Could not create framebuffer surface: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLSurface rendering backend)", error_message.c_str());
}
else
{
std::string error_message = std::string("Could not get SDL surface of the window: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLSurface rendering backend)", error_message.c_str());
}
SDL_DestroyWindow(window);
}
else
{
std::string error_message = std::string("Could not create window: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLSurface rendering backend)", error_message.c_str());
}
return NULL;
}
void RenderBackend_Deinit(void)
{
SDL_FreeSurface(framebuffer.sdlsurface);
SDL_DestroyWindow(window);
}
void RenderBackend_DrawScreen(void)
{
if (SDL_BlitSurface(framebuffer.sdlsurface, NULL, window_sdlsurface, NULL) < 0)
Backend_PrintError("Couldn't blit framebuffer surface to window surface: %s", SDL_GetError());
if (SDL_UpdateWindowSurface(window) < 0)
Backend_PrintError("Couldn't put window surface on screen: %s", SDL_GetError());
}
RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height, bool render_target)
{
(void)render_target;
RenderBackend_Surface *surface = (RenderBackend_Surface*)malloc(sizeof(RenderBackend_Surface));
if (surface == NULL)
return NULL;
surface->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGB24);
if (surface->sdlsurface == NULL)
{
free(surface);
return NULL;
}
return surface;
}
void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
{
SDL_FreeSurface(surface->sdlsurface);
free(surface);
}
bool RenderBackend_IsSurfaceLost(RenderBackend_Surface *surface)
{
(void)surface;
return false;
}
void RenderBackend_RestoreSurface(RenderBackend_Surface *surface)
{
(void)surface;
}
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
{
if (SDL_LockSurface(surface->sdlsurface) == 0)
{
for (size_t y = 0; y < height; ++y)
memcpy(&((unsigned char*)surface->sdlsurface->pixels)[y * surface->sdlsurface->pitch], &pixels[y * width * 3], width * 3);
SDL_UnlockSurface(surface->sdlsurface);
}
}
void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
{
SDL_Rect source_rect;
RectToSDLRect(rect, &source_rect);
SDL_Rect destination_rect;
destination_rect.x = x;
destination_rect.y = y;
destination_rect.w = source_rect.w;
destination_rect.h = source_rect.h;
// Assumes the colour key will always be #000000 (black)
if (SDL_SetColorKey(source_surface->sdlsurface, colour_key ? SDL_TRUE : SDL_FALSE, SDL_MapRGB(source_surface->sdlsurface->format, 0, 0, 0)) < 0)
Backend_PrintError("Couldn't set color key of surface: %s", SDL_GetError());
if (SDL_BlitSurface(source_surface->sdlsurface, &source_rect, destination_surface->sdlsurface, &destination_rect) < 0)
Backend_PrintError("Couldn't blit surface: %s", SDL_GetError());
}
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue)
{
SDL_Rect destination_rect;
RectToSDLRect(rect, &destination_rect);
if (SDL_FillRect(surface->sdlsurface, &destination_rect, SDL_MapRGB(surface->sdlsurface->format, red, green, blue)) < 0)
Backend_PrintError("Couldn't fill rectangle with color: %s", SDL_GetError());
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGBA32);
if (atlas->sdlsurface != NULL)
{
return atlas;
}
else
{
Backend_PrintError("Couldn't create RBG surface: %s", SDL_GetError());
}
free(atlas);
}
return NULL;
}
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas)
{
SDL_FreeSurface(atlas->sdlsurface);
free(atlas);
}
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
{
SDL_LockSurface(atlas->sdlsurface);
for (size_t iy = 0; iy < height; ++iy)
{
const unsigned char *source_pointer = &pixels[iy * pitch];
unsigned char *destination_pointer = &((unsigned char*)atlas->sdlsurface->pixels)[(y + iy) * atlas->sdlsurface->pitch + x * 4];
for (size_t ix = 0; ix < width; ++ix)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
*destination_pointer++ = *source_pointer++;
}
}
SDL_UnlockSurface(atlas->sdlsurface);
}
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
{
glyph_atlas = atlas;
glyph_destination_surface = destination_surface;
if (SDL_SetSurfaceColorMod(atlas->sdlsurface, red, green, blue) < 0)
Backend_PrintError("Couldn't set color value: %s", SDL_GetError());
}
void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height)
{
SDL_Rect source_rect;
source_rect.x = glyph_x;
source_rect.y = glyph_y;
source_rect.w = glyph_width;
source_rect.h = glyph_height;
SDL_Rect destination_rect;
destination_rect.x = x;
destination_rect.y = y;
destination_rect.w = glyph_width;
destination_rect.h = glyph_height;
if (SDL_BlitSurface(glyph_atlas->sdlsurface, &source_rect, glyph_destination_surface->sdlsurface, &destination_rect) < 0)
Backend_PrintError("Couldn't blit glyph indivual surface to final glyph surface: %s", SDL_GetError());
}
void RenderBackend_HandleRenderTargetLoss(void)
{
// No problem for us
}
void RenderBackend_HandleWindowResize(size_t width, size_t height)
{
(void)width;
(void)height;
// https://wiki.libsdl.org/SDL_GetWindowSurface
// We need to fetch a new surface pointer
window_sdlsurface = SDL_GetWindowSurface(window);
if (window_sdlsurface == NULL)
Backend_PrintError("Couldn't get SDL surface for window after resize: %s", SDL_GetError());
}

View File

@ -1,461 +0,0 @@
// Released under the MIT licence.
// See LICENCE.txt for details.
#include "../Rendering.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "SDL.h"
#include "../../WindowsWrapper.h"
#include "../Misc.h"
#include "../Shared/SDL.h"
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
typedef struct RenderBackend_Surface
{
SDL_Texture *texture;
size_t width;
size_t height;
bool render_target;
bool lost;
struct RenderBackend_Surface *next;
struct RenderBackend_Surface *prev;
} RenderBackend_Surface;
typedef struct RenderBackend_GlyphAtlas
{
SDL_Texture *texture;
} RenderBackend_GlyphAtlas;
SDL_Window *window;
static SDL_Renderer *renderer;
static RenderBackend_Surface framebuffer;
static RenderBackend_Surface upscaled_framebuffer;
static SDL_Rect window_rect;
static RenderBackend_Surface *surface_list_head;
static RenderBackend_GlyphAtlas *glyph_atlas;
static void RectToSDLRect(const RenderBackend_Rect *rect, SDL_Rect *sdl_rect)
{
sdl_rect->x = (int)rect->left;
sdl_rect->y = (int)rect->top;
sdl_rect->w = (int)(rect->right - rect->left);
sdl_rect->h = (int)(rect->bottom - rect->top);
if (sdl_rect->w < 0)
sdl_rect->w = 0;
if (sdl_rect->h < 0)
sdl_rect->h = 0;
}
RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen)
{
Backend_PrintInfo("Available SDL render drivers:");
for (int i = 0; i < SDL_GetNumRenderDrivers(); ++i)
{
SDL_RendererInfo info;
if (SDL_GetRenderDriverInfo(i, &info) < 0)
Backend_PrintError("Couldn't get render driver information: %s", SDL_GetError());
else
Backend_PrintInfo("%s", info.name);
}
window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, SDL_WINDOW_RESIZABLE);
if (window != NULL)
{
if (fullscreen)
if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) < 0)
Backend_PrintError("Couldn't set window to fullscreen: %s", SDL_GetError());
#if SDL_VERSION_ATLEAST(2,0,10)
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1"); // We never interfere with the renderer, so don't let SDL implicitly disable batching
#endif
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
if (renderer != NULL)
{
SDL_RendererInfo info;
if (SDL_GetRendererInfo(renderer, &info) < 0)
Backend_PrintError("Couldn't get selected render driver information: %s", SDL_GetError());
else
Backend_PrintInfo("Selected SDL render driver: %s", info.name);
framebuffer.texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, screen_width, screen_height);
if (framebuffer.texture != NULL)
{
SDL_SetTextureBlendMode(framebuffer.texture, SDL_BLENDMODE_NONE);
framebuffer.width = screen_width;
framebuffer.height = screen_height;
RenderBackend_HandleWindowResize(screen_width, screen_height);
Backend_PostWindowCreation();
return &framebuffer;
}
else
{
std::string error_message = std::string("Could not create framebuffer: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLTexture rendering backend)", error_message.c_str());
}
SDL_DestroyRenderer(renderer);
}
else
{
std::string error_message = std::string("Could not create renderer: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLTexture rendering backend)", error_message.c_str());
}
SDL_DestroyWindow(window);
}
else
{
std::string error_message = std::string("Could not create window: ") + SDL_GetError();
Backend_ShowMessageBox("Fatal error (SDLTexture rendering backend)", error_message.c_str());
}
return NULL;
}
void RenderBackend_Deinit(void)
{
if (upscaled_framebuffer.texture != NULL)
SDL_DestroyTexture(upscaled_framebuffer.texture);
SDL_DestroyTexture(framebuffer.texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
void RenderBackend_DrawScreen(void)
{
if (upscaled_framebuffer.texture != NULL)
{
if (SDL_SetRenderTarget(renderer, upscaled_framebuffer.texture) < 0)
Backend_PrintError("Couldn't set upscaled framebuffer as the current rendering target: %s", SDL_GetError());
if (SDL_RenderCopy(renderer, framebuffer.texture, NULL, NULL) < 0)
Backend_PrintError("Failed to copy framebuffer texture to upscaled framebuffer: %s", SDL_GetError());
}
if (SDL_SetRenderTarget(renderer, NULL) < 0)
Backend_PrintError("Couldn't set default render target as the current rendering target: %s", SDL_GetError());
if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF) < 0)
Backend_PrintError("Couldn't set color for drawing operations: %s", SDL_GetError());
SDL_RenderClear(renderer);
if (SDL_RenderCopy(renderer, upscaled_framebuffer.texture != NULL ? upscaled_framebuffer.texture : framebuffer.texture, NULL, &window_rect) < 0)
Backend_PrintError("Failed to copy upscaled framebuffer texture to default render target: %s", SDL_GetError());
SDL_RenderPresent(renderer);
}
RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height, bool render_target)
{
RenderBackend_Surface *surface = (RenderBackend_Surface*)malloc(sizeof(RenderBackend_Surface));
if (surface == NULL)
return NULL;
surface->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, render_target ? SDL_TEXTUREACCESS_TARGET : SDL_TEXTUREACCESS_STATIC, width, height);
if (surface->texture == NULL)
{
free(surface);
return NULL;
}
surface->width = width;
surface->height = height;
surface->render_target = render_target;
surface->lost = false;
// Add to linked-list
surface->prev = NULL;
surface->next = surface_list_head;
surface_list_head = surface;
if (surface->next != NULL)
surface->next->prev = surface;
return surface;
}
void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
{
// Remove from linked list
if (surface->next != NULL)
surface->next->prev = surface->prev;
if (surface->prev != NULL)
surface->prev->next = surface->next;
if (surface->prev == NULL)
surface_list_head = surface->next;
SDL_DestroyTexture(surface->texture);
free(surface);
}
bool RenderBackend_IsSurfaceLost(RenderBackend_Surface *surface)
{
return surface->lost;
}
void RenderBackend_RestoreSurface(RenderBackend_Surface *surface)
{
surface->lost = false;
}
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
{
unsigned char *buffer = (unsigned char*)malloc(width * height * 4);
if (buffer == NULL)
{
Backend_PrintError("Couldn't allocate memory for surface buffer");
return;
}
const unsigned char *src_pixel = pixels;
unsigned char *buffer_pointer = buffer;
// Convert the colour-keyed pixels to RGBA32
for (size_t y = 0; y < height; ++y)
{
for (size_t x = 0; x < width; ++x)
{
*buffer_pointer++ = src_pixel[0];
*buffer_pointer++ = src_pixel[1];
*buffer_pointer++ = src_pixel[2];
if (src_pixel[0] == 0 && src_pixel[1] == 0 && src_pixel[2] == 0) // Assumes the colour key will always be #000000 (black)
*buffer_pointer++ = 0;
else
*buffer_pointer++ = 0xFF;
src_pixel += 3;
}
}
SDL_Rect rect = {0, 0, (int)width, (int)height};
if (SDL_UpdateTexture(surface->texture, &rect, buffer, width * 4) < 0)
Backend_PrintError("Couldn't update part of texture: %s", SDL_GetError());
free(buffer);
}
void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
{
SDL_Rect source_rect;
RectToSDLRect(rect, &source_rect);
SDL_Rect destination_rect = {(int)x, (int)y, source_rect.w, source_rect.h};
// Blit the texture
if (SDL_SetTextureBlendMode(source_surface->texture, colour_key ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE) < 0)
Backend_PrintError("Couldn't set texture blend mode: %s", SDL_GetError());
if (SDL_SetRenderTarget(renderer, destination_surface->texture) < 0)
Backend_PrintError("Couldn't set current rendering target: %s", SDL_GetError());
if (SDL_RenderCopy(renderer, source_surface->texture, &source_rect, &destination_rect) < 0)
Backend_PrintError("Couldn't copy part of texture to rendering target: %s", SDL_GetError());
}
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue)
{
SDL_Rect sdl_rect;
RectToSDLRect(rect, &sdl_rect);
Uint8 alpha = SDL_ALPHA_OPAQUE;
// Check colour-key
if (red == 0 && green == 0 && blue == 0)
alpha = 0;
if (SDL_SetRenderDrawColor(renderer, red, green, blue, alpha) < 0)
Backend_PrintError("Couldn't set color for drawing operations: %s", SDL_GetError());
// Draw colour
if (SDL_SetRenderTarget(renderer, surface->texture) < 0)
Backend_PrintError("Couldn't set texture current rendering target: %s", SDL_GetError());
if (SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE) < 0)
Backend_PrintError("Couldn't disable blending for drawing operations: %s", SDL_GetError());
if (SDL_RenderFillRect(renderer, &sdl_rect) < 0)
Backend_PrintError("Couldn't fill rectangle on current rendering target: %s", SDL_GetError());
if (SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) < 0)
Backend_PrintError("Couldn't enable alpha blending for drawing operations: %s", SDL_GetError());
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
if (atlas->texture != NULL)
{
return atlas;
}
else
{
Backend_PrintError("Couldn't create texture for renderer: %s", SDL_GetError());
}
free(atlas);
}
return NULL;
}
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas)
{
SDL_DestroyTexture(atlas->texture);
free(atlas);
}
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
{
unsigned char *buffer = (unsigned char*)malloc(width * height * 4);
if (buffer != NULL)
{
unsigned char *destination_pointer = buffer;
for (size_t iy = 0; iy < height; ++iy)
{
const unsigned char *source_pointer = &pixels[iy * pitch];
for (size_t ix = 0; ix < width; ++ix)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
*destination_pointer++ = *source_pointer++;
}
}
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = width;
rect.h = height;
if (SDL_UpdateTexture(atlas->texture, &rect, buffer, width * 4) < 0)
Backend_PrintError("Couldn't update texture: %s", SDL_GetError());
free(buffer);
}
}
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
{
glyph_atlas = atlas;
if (SDL_SetRenderTarget(renderer, destination_surface->texture) < 0)
Backend_PrintError("Couldn't set texture as current rendering target: %s", SDL_GetError());
// The SDL_Texture side of things uses alpha, not a colour-key, so the bug where the font is blended
// with the colour key doesn't occur.
if (SDL_SetTextureColorMod(atlas->texture, red, green, blue) < 0)
Backend_PrintError("Couldn't set additional color value: %s", SDL_GetError());
if (SDL_SetTextureBlendMode(atlas->texture, SDL_BLENDMODE_BLEND) < 0)
Backend_PrintError("Couldn't set texture blend mode: %s", SDL_GetError());
}
void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height)
{
SDL_Rect source_rect;
source_rect.x = glyph_x;
source_rect.y = glyph_y;
source_rect.w = glyph_width;
source_rect.h = glyph_height;
SDL_Rect destination_rect;
destination_rect.x = x;
destination_rect.y = y;
destination_rect.w = glyph_width;
destination_rect.h = glyph_height;
if (SDL_RenderCopy(renderer, glyph_atlas->texture, &source_rect, &destination_rect) < 0)
Backend_PrintError("Couldn't copy glyph texture portion to renderer: %s", SDL_GetError());
}
void RenderBackend_HandleRenderTargetLoss(void)
{
for (RenderBackend_Surface *surface = surface_list_head; surface != NULL; surface = surface->next)
if (surface->render_target)
surface->lost = true;
}
void RenderBackend_HandleWindowResize(size_t width, size_t height)
{
size_t upscale_factor = MAX(1, MIN((width + framebuffer.width / 2) / framebuffer.width, (height + framebuffer.height / 2) / framebuffer.height));
upscaled_framebuffer.width = framebuffer.width * upscale_factor;
upscaled_framebuffer.height = framebuffer.height * upscale_factor;
if (upscaled_framebuffer.texture != NULL)
{
SDL_DestroyTexture(upscaled_framebuffer.texture);
upscaled_framebuffer.texture = NULL;
}
// Create rect that forces 4:3 no matter what size the window is
if (width * upscaled_framebuffer.height >= upscaled_framebuffer.width * height) // Fancy way to do `if (width / height >= upscaled_framebuffer.width / upscaled_framebuffer.height)` without floats
{
window_rect.w = (height * upscaled_framebuffer.width) / upscaled_framebuffer.height;
window_rect.h = height;
}
else
{
window_rect.w = width;
window_rect.h = (width * upscaled_framebuffer.height) / upscaled_framebuffer.width;
}
window_rect.x = (width - window_rect.w) / 2;
window_rect.y = (height - window_rect.h) / 2;
if (window_rect.w % framebuffer.width != 0 || window_rect.h % framebuffer.height != 0)
{
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
upscaled_framebuffer.texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, upscaled_framebuffer.width, upscaled_framebuffer.height);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
if (upscaled_framebuffer.texture == NULL)
Backend_PrintError("Couldn't regenerate upscaled framebuffer");
SDL_SetTextureBlendMode(upscaled_framebuffer.texture, SDL_BLENDMODE_NONE);
}
}

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