Compare commits
115 Commits
snapshot-3
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
6ce8e10adb | ||
|
47384c5572 | ||
|
de345a85a1 | ||
|
6de252eb34 | ||
|
b39f3c7f55 | ||
|
58c0ab4747 | ||
|
73daf67c34 | ||
|
3edb8c4233 | ||
|
351dc6ec87 | ||
|
0cfb91ce86 | ||
|
efeac4fd8a | ||
|
36619df4f4 | ||
|
9f02999947 | ||
|
2c55a8a9d9 | ||
|
1a0eb73ea0 | ||
|
f8873debc6 | ||
|
51f714de0f | ||
|
e371d6345b | ||
|
e55fc8703a | ||
|
40e2e4a62a | ||
|
e9fdb254af | ||
|
5e8a28b946 | ||
|
a53595ce68 | ||
|
e8c24e7e23 | ||
|
7edc413cdc | ||
|
53b9b0e286 | ||
|
99cd354a16 | ||
|
d56e8387cf | ||
|
c1c1daa9e5 | ||
|
bfdfebc1d5 | ||
|
502df57cae | ||
|
a0ba5f5398 | ||
|
178519dbb0 | ||
|
bb471e63e1 | ||
|
4b866c409a | ||
|
3fb356e2a9 | ||
|
8452d96bf6 | ||
|
eef8943a3c | ||
|
5160f4ad33 | ||
|
7870ec56a3 | ||
|
16f50b808d | ||
|
aa8ee76fbb | ||
|
228d559ccd | ||
|
758d34c4eb | ||
|
596e6cece1 | ||
|
3a3a8c1cc3 | ||
|
f47d0a9828 | ||
|
7cd684ccfe | ||
|
82bcb0ef9e | ||
|
c85ebe4a0a | ||
|
ab28f93753 | ||
|
a7e71db9a0 | ||
|
d9172faa17 | ||
|
ef308c1e48 | ||
|
79f45eb096 | ||
|
0310ac08a8 | ||
|
ea7cd41975 | ||
|
f4b836deb1 | ||
|
a250894a12 | ||
|
c3cd4f1691 | ||
|
e6e36a6b7c | ||
|
588fe293ec | ||
|
69e0a8b0aa | ||
|
ae07c55f4d | ||
|
09ae62ac9e | ||
|
622df75c29 | ||
|
cd1855fbdd | ||
|
7a10847780 | ||
|
d87130bd66 | ||
|
1cb8f0378f | ||
|
2a43e8aef0 | ||
|
3f503bcb1c | ||
|
a637a619c9 | ||
|
5839657806 | ||
|
1ef0c1a3e0 | ||
|
452b553350 | ||
|
8e6faddd2f | ||
|
5e60b53a3b | ||
|
5eb5383f08 | ||
|
708d543d29 | ||
|
00602f58a0 | ||
|
a2b5dddb83 | ||
|
137e4038b6 | ||
|
b711b2935b | ||
|
66a09ababd | ||
|
d21c23b46e | ||
|
45df2ba080 | ||
|
e314e99c4c | ||
|
ee2e53958a | ||
|
c5034dd01a | ||
|
5e35ce42b5 | ||
|
aff12209d3 | ||
|
5da4c04f35 | ||
|
bc9d43bb10 | ||
|
8a7a36bb85 | ||
|
2f302fa586 | ||
|
608f037e68 | ||
|
d05b0093b9 | ||
|
9a05e56f15 | ||
|
1dc641d13f | ||
|
99566c8003 | ||
|
c352b08d86 | ||
|
5411269fb2 | ||
|
ba056746b8 | ||
|
929b7ee525 | ||
|
2f25c3fe32 | ||
|
bc5fad1500 | ||
|
f5f275e657 | ||
|
15a22c6906 | ||
|
c4db637887 | ||
|
4377f83184 | ||
|
84b790ceaf | ||
|
78bc86d107 | ||
|
b000abcdd8 | ||
|
93cbb065dd |
106
.github/build.sh
vendored
106
.github/build.sh
vendored
@ -44,12 +44,39 @@ wasm32-emscripten-emscripten-static) ;;
|
|||||||
*) >&2 echo "configuration $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_STATIC_DYNAMIC is not supported" && exit 1;;
|
*) >&2 echo "configuration $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_STATIC_DYNAMIC is not supported" && exit 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [[ $BSH_HOST_PLATFORM == android ]]; then
|
||||||
|
android_platform=android-31
|
||||||
|
if [[ -z "${JAVA_HOME_8_X64-}" ]]; then
|
||||||
|
>&2 echo "JAVA_HOME_8_X64 not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z "${ANDROID_SDK_ROOT-}" ]]; then
|
||||||
|
>&2 echo "ANDROID_SDK_ROOT not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z "${ANDROID_NDK_LATEST_HOME-}" ]]; then
|
||||||
|
>&2 echo "ANDROID_NDK_LATEST_HOME not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z ${BSH_NO_PACKAGES-} ]]; then
|
if [[ -z ${BSH_NO_PACKAGES-} ]]; then
|
||||||
case $BSH_HOST_PLATFORM in
|
case $BSH_HOST_PLATFORM in
|
||||||
|
android)
|
||||||
|
(
|
||||||
|
export PATH=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/tools/bin:$PATH
|
||||||
|
sdkmanager "platforms;$android_platform"
|
||||||
|
)
|
||||||
|
;;
|
||||||
windows)
|
windows)
|
||||||
if [[ $BSH_BUILD_PLATFORM == linux ]] && [[ $BSH_HOST_LIBC == mingw ]]; then
|
if [[ $BSH_BUILD_PLATFORM-$BSH_HOST_LIBC == windows-mingw ]]; then
|
||||||
sudo apt update
|
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-gcc
|
||||||
sudo apt install g++-mingw-w64-x86-64
|
if [[ $BSH_STATIC_DYNAMIC == static ]]; then
|
||||||
|
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{cmake,7zip,jq} patch
|
||||||
|
else
|
||||||
|
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{pkgconf,bzip2,luajit,jsoncpp,curl,SDL2,libpng,meson,fftw,jq}
|
||||||
|
fi
|
||||||
|
export PKG_CONFIG=$(which pkg-config.exe)
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
linux)
|
linux)
|
||||||
@ -87,22 +114,6 @@ function inplace_sed() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $BSH_HOST_PLATFORM == android ]]; then
|
|
||||||
android_platform=android-30
|
|
||||||
if [[ -z "${JAVA_HOME_8_X64-}" ]]; then
|
|
||||||
>&2 echo "JAVA_HOME_8_X64 not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [[ -z "${ANDROID_SDK_ROOT-}" ]]; then
|
|
||||||
>&2 echo "ANDROID_SDK_ROOT not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [[ -z "${ANDROID_NDK_LATEST_HOME-}" ]]; then
|
|
||||||
>&2 echo "ANDROID_NDK_LATEST_HOME not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_LIBC == windows-msvc ]]; then
|
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_LIBC == windows-msvc ]]; then
|
||||||
case $BSH_HOST_ARCH in
|
case $BSH_HOST_ARCH in
|
||||||
x86_64) vs_env_arch=x64;;
|
x86_64) vs_env_arch=x64;;
|
||||||
@ -188,7 +199,7 @@ meson_configure+=$'\t'-Dapp_exe=$APP_EXE
|
|||||||
meson_configure+=$'\t'-Dapp_id=$APP_ID
|
meson_configure+=$'\t'-Dapp_id=$APP_ID
|
||||||
meson_configure+=$'\t'-Dapp_data=$APP_DATA
|
meson_configure+=$'\t'-Dapp_data=$APP_DATA
|
||||||
meson_configure+=$'\t'-Dapp_vendor=$APP_VENDOR
|
meson_configure+=$'\t'-Dapp_vendor=$APP_VENDOR
|
||||||
meson_configure+=$'\t'-Db_strip=false
|
meson_configure+=$'\t'-Dstrip=false
|
||||||
meson_configure+=$'\t'-Db_staticpic=false
|
meson_configure+=$'\t'-Db_staticpic=false
|
||||||
meson_configure+=$'\t'-Dmod_id=$MOD_ID
|
meson_configure+=$'\t'-Dmod_id=$MOD_ID
|
||||||
case $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_DEBUG_RELEASE in
|
case $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_DEBUG_RELEASE in
|
||||||
@ -208,23 +219,9 @@ if [[ $PACKAGE_MODE == nolua ]]; then
|
|||||||
fi
|
fi
|
||||||
if [[ $PACKAGE_MODE == backendvs ]]; then
|
if [[ $PACKAGE_MODE == backendvs ]]; then
|
||||||
meson_configure+=$'\t'-Dbackend=vs
|
meson_configure+=$'\t'-Dbackend=vs
|
||||||
echo "NOTE: patching CREATEPROCESS_MANIFEST_RESOURCE_ID out of powder-res.template.rc"
|
# meson 1.2.3 configures vs projects that bring their own manifest, which conflicts with ours
|
||||||
echo "TODO: remove this patch once https://github.com/mesonbuild/meson/pull/12472 makes it into a release"
|
# TODO: remove this patch once https://github.com/mesonbuild/meson/pull/12472 makes it into a release that we can use
|
||||||
echo "TODO: also remove the relevant note from the building guide"
|
meson_configure+=$'\t'-Dwindows_utf8cp=false
|
||||||
git apply <<PATCH
|
|
||||||
diff --git a/resources/powder-res.template.rc b/resources/powder-res.template.rc
|
|
||||||
index 1dc26c78..2094049f 100644
|
|
||||||
--- a/resources/powder-res.template.rc
|
|
||||||
+++ b/resources/powder-res.template.rc
|
|
||||||
@@ -7,7 +7,6 @@
|
|
||||||
|
|
||||||
IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@"
|
|
||||||
IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@"
|
|
||||||
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@"
|
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
|
||||||
FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@
|
|
||||||
PATCH
|
|
||||||
fi
|
fi
|
||||||
if [[ $BSH_STATIC_DYNAMIC == static ]]; then
|
if [[ $BSH_STATIC_DYNAMIC == static ]]; then
|
||||||
meson_configure+=$'\t'-Dstatic=prebuilt
|
meson_configure+=$'\t'-Dstatic=prebuilt
|
||||||
@ -241,6 +238,11 @@ if [[ $BSH_STATIC_DYNAMIC == static ]]; then
|
|||||||
c_link_args+=\'-static-libstdc++\',
|
c_link_args+=\'-static-libstdc++\',
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
if [[ "$BSH_HOST_PLATFORM-$BSH_HOST_LIBC $BSH_BUILD_PLATFORM" == "windows-mingw windows" ]]; then
|
||||||
|
meson_configure+=$'\t'-Dworkaround_elusive_bzip2=true
|
||||||
|
meson_configure+=$'\t'-Dworkaround_elusive_bzip2_include_dir=/ucrt64/include
|
||||||
|
meson_configure+=$'\t'-Dworkaround_elusive_bzip2_lib_dir=/ucrt64/lib
|
||||||
|
fi
|
||||||
if [[ $BSH_BUILD_PLATFORM == linux ]]; then
|
if [[ $BSH_BUILD_PLATFORM == linux ]]; then
|
||||||
meson_configure+=$'\t'-Dworkaround_elusive_bzip2=true
|
meson_configure+=$'\t'-Dworkaround_elusive_bzip2=true
|
||||||
fi
|
fi
|
||||||
@ -288,18 +290,21 @@ if [[ $RELEASE_TYPE == snapshot ]] && [[ $MOD_ID != 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
if [[ $RELEASE_TYPE == snapshot ]] || [[ $MOD_ID != 0 ]]; then
|
if [[ $RELEASE_TYPE == snapshot ]] || [[ $MOD_ID != 0 ]]; then
|
||||||
meson_configure+=$'\t'-Dupdate_server=starcatcher.us/TPT
|
meson_configure+=$'\t'-Dupdate_server=starcatcher.us/TPT
|
||||||
|
if [[ $BSH_HOST_PLATFORM == emscripten ]]; then
|
||||||
|
meson_configure+=$'\t'-Dserver=tptserv.starcatcher.us
|
||||||
|
meson_configure+=$'\t'-Dstatic_server=tptserv.starcatcher.us/Static
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $RELEASE_TYPE != dev ]]; then
|
if [[ $RELEASE_TYPE != dev ]]; then
|
||||||
meson_configure+=$'\t'-Dignore_updates=false
|
meson_configure+=$'\t'-Dignore_updates=false
|
||||||
fi
|
fi
|
||||||
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_LIBC == windows-mingw ]]; then
|
if [[ "$BSH_HOST_PLATFORM-$BSH_HOST_LIBC" == "windows-mingw" ]]; then
|
||||||
if [[ $BSH_BUILD_PLATFORM == linux ]]; then
|
|
||||||
meson_configure+=$'\t'--cross-file=.github/mingw-ghactions.ini
|
meson_configure+=$'\t'--cross-file=.github/mingw-ghactions.ini
|
||||||
|
# there is some mingw bug that only ever manifests on ghactions which makes MakeIco.exe use tons of memory and fail
|
||||||
|
# TODO: remove this hack once we figure out how to fix that
|
||||||
|
meson_configure+=$'\t'-Dwindows_icons=false
|
||||||
fi
|
fi
|
||||||
fi
|
if [[ $BSH_DEBUG_RELEASE-$BSH_STATIC_DYNAMIC == release-static ]]; then
|
||||||
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_LIBC != windows-mingw ]] && [[ $BSH_STATIC_DYNAMIC == static ]]; then
|
|
||||||
# LTO simply doesn't work with MinGW. I have no idea why and I also don't care.
|
|
||||||
# It also has a tendency to not play well with dynamic libraries.
|
|
||||||
meson_configure+=$'\t'-Db_lto=true
|
meson_configure+=$'\t'-Db_lto=true
|
||||||
fi
|
fi
|
||||||
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_ARCH == darwin-aarch64 ]]; then
|
if [[ $BSH_HOST_PLATFORM-$BSH_HOST_ARCH == darwin-aarch64 ]]; then
|
||||||
@ -308,7 +313,7 @@ fi
|
|||||||
if [[ $BSH_HOST_PLATFORM == emscripten ]]; then
|
if [[ $BSH_HOST_PLATFORM == emscripten ]]; then
|
||||||
meson_configure+=$'\t'--cross-file=.github/emscripten-ghactions.ini
|
meson_configure+=$'\t'--cross-file=.github/emscripten-ghactions.ini
|
||||||
fi
|
fi
|
||||||
if [[ $RELEASE_TYPE == tptlibsdev ]] && ([[ $BSH_HOST_PLATFORM == windows ]] || [[ $BSH_STATIC_DYNAMIC == static ]]); then
|
if [[ $RELEASE_TYPE == tptlibsdev ]] && ([[ $BSH_HOST_PLATFORM-$BSH_HOST_LIBC == windows-msvc ]] || [[ $BSH_STATIC_DYNAMIC == static ]]); then
|
||||||
if [[ -z ${TPTLIBSREMOTE-} ]]; then
|
if [[ -z ${TPTLIBSREMOTE-} ]]; then
|
||||||
if [[ -z "${GITHUB_REPOSITORY_OWNER-}" ]]; then
|
if [[ -z "${GITHUB_REPOSITORY_OWNER-}" ]]; then
|
||||||
>&2 echo "GITHUB_REPOSITORY_OWNER not set"
|
>&2 echo "GITHUB_REPOSITORY_OWNER not set"
|
||||||
@ -318,11 +323,6 @@ if [[ $RELEASE_TYPE == tptlibsdev ]] && ([[ $BSH_HOST_PLATFORM == windows ]] ||
|
|||||||
else
|
else
|
||||||
tptlibsremote=$TPTLIBSREMOTE
|
tptlibsremote=$TPTLIBSREMOTE
|
||||||
fi
|
fi
|
||||||
if [[ "$BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_STATIC_DYNAMIC $BSH_BUILD_PLATFORM" == "x86_64-windows-mingw-dynamic linux" ]]; then
|
|
||||||
>&2 echo "this configuration is not supported in tptlibsdev mode"
|
|
||||||
touch $ASSET_PATH
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
tptlibsbranch=$(echo $RELEASE_NAME | cut -d '-' -f 2-) # $RELEASE_NAME is tptlibsdev-BRANCH
|
tptlibsbranch=$(echo $RELEASE_NAME | cut -d '-' -f 2-) # $RELEASE_NAME is tptlibsdev-BRANCH
|
||||||
if [[ -d build-tpt-libs ]] && [[ ${TPTLIBSRESET-} == yes ]]; then
|
if [[ -d build-tpt-libs ]] && [[ ${TPTLIBSRESET-} == yes ]]; then
|
||||||
rm -rf build-tpt-libs
|
rm -rf build-tpt-libs
|
||||||
@ -350,7 +350,11 @@ if [[ $RELEASE_TYPE == tptlibsdev ]] && ([[ $BSH_HOST_PLATFORM == windows ]] ||
|
|||||||
meson_configure+=$'\t'-Dtpt_libs_vtag=$tpt_libs_vtag
|
meson_configure+=$'\t'-Dtpt_libs_vtag=$tpt_libs_vtag
|
||||||
fi
|
fi
|
||||||
if [[ $BSH_HOST_PLATFORM == android ]]; then
|
if [[ $BSH_HOST_PLATFORM == android ]]; then
|
||||||
android_platform=android-30
|
android_platform_jar=$ANDROID_SDK_ROOT/platforms/$android_platform/android.jar
|
||||||
|
if ! [[ -f $android_platform_jar ]]; then
|
||||||
|
>&2 echo "$android_platform_jar not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
meson_configure+=$'\t'--cross-file=android/cross/$BSH_HOST_ARCH.ini
|
meson_configure+=$'\t'--cross-file=android/cross/$BSH_HOST_ARCH.ini
|
||||||
cat << ANDROID_INI > .github/android-ghactions.ini
|
cat << ANDROID_INI > .github/android-ghactions.ini
|
||||||
[constants]
|
[constants]
|
||||||
@ -361,7 +365,7 @@ andriod_sdk_build_tools = '$ANDROID_SDK_ROOT/build-tools/32.0.0'
|
|||||||
# android_ndk_toolchain_prefix comes from the correct cross-file in ./android/cross
|
# android_ndk_toolchain_prefix comes from the correct cross-file in ./android/cross
|
||||||
android_ndk_toolchain_prefix = android_ndk_toolchain_prefix
|
android_ndk_toolchain_prefix = android_ndk_toolchain_prefix
|
||||||
android_platform = '$android_platform'
|
android_platform = '$android_platform'
|
||||||
android_platform_jar = '$ANDROID_SDK_ROOT/platforms/' + android_platform + '/android.jar'
|
android_platform_jar = '$android_platform_jar'
|
||||||
java_runtime_jar = '$JAVA_HOME_8_X64/jre/lib/rt.jar'
|
java_runtime_jar = '$JAVA_HOME_8_X64/jre/lib/rt.jar'
|
||||||
|
|
||||||
[binaries]
|
[binaries]
|
||||||
|
4
.github/create-release.sh
vendored
Executable file
4
.github/create-release.sh
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\t\n'
|
||||||
|
|
||||||
|
gh release create --draft --verify-tag --title $RELEASE_NAME $GITHUB_REF_NAME
|
4
.github/mingw-ghactions.ini
vendored
4
.github/mingw-ghactions.ini
vendored
@ -2,8 +2,8 @@
|
|||||||
prefix = 'x86_64-w64-mingw32'
|
prefix = 'x86_64-w64-mingw32'
|
||||||
|
|
||||||
[binaries]
|
[binaries]
|
||||||
c = prefix + '-gcc-posix'
|
c = prefix + '-gcc'
|
||||||
cpp = prefix + '-g++-posix'
|
cpp = prefix + '-g++'
|
||||||
strip = prefix + '-strip'
|
strip = prefix + '-strip'
|
||||||
windres = prefix + '-windres'
|
windres = prefix + '-windres'
|
||||||
|
|
||||||
|
35
.github/prepare.py
vendored
35
.github/prepare.py
vendored
@ -17,6 +17,7 @@ match_stable = re.fullmatch(r'refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)', ref)
|
|||||||
match_beta = re.fullmatch(r'refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)b', ref)
|
match_beta = re.fullmatch(r'refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)b', ref)
|
||||||
match_snapshot = re.fullmatch(r'refs/tags/snapshot-([0-9]+)', ref)
|
match_snapshot = re.fullmatch(r'refs/tags/snapshot-([0-9]+)', ref)
|
||||||
match_tptlibsdev = re.fullmatch(r'refs/heads/tptlibsdev-(.*)', ref)
|
match_tptlibsdev = re.fullmatch(r'refs/heads/tptlibsdev-(.*)', ref)
|
||||||
|
match_alljobs = re.fullmatch(r'refs/heads/(.*)-alljobs', ref)
|
||||||
do_release = False
|
do_release = False
|
||||||
do_priority = 10
|
do_priority = 10
|
||||||
if event_name == 'pull_request':
|
if event_name == 'pull_request':
|
||||||
@ -43,6 +44,8 @@ elif match_tptlibsdev:
|
|||||||
else:
|
else:
|
||||||
release_type = 'dev'
|
release_type = 'dev'
|
||||||
release_name = 'dev'
|
release_name = 'dev'
|
||||||
|
if match_alljobs:
|
||||||
|
do_priority = 0
|
||||||
do_publish = publish_hostport and do_release
|
do_publish = publish_hostport and do_release
|
||||||
|
|
||||||
set_output('release_type', release_type)
|
set_output('release_type', release_type)
|
||||||
@ -100,10 +103,10 @@ for arch, platform, libc, statdyn, bplatform, runso
|
|||||||
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, 'nohttp', None, 'debug', 10 ),
|
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, 'nohttp', None, 'debug', 10 ),
|
||||||
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, 'nolua', None, 'debug', 10 ),
|
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, 'nolua', None, 'debug', 10 ),
|
||||||
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'release', 10 ),
|
( 'x86_64', 'linux', 'gnu', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'release', 10 ),
|
||||||
# ( 'x86_64', 'windows', 'mingw', 'static', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'debug', 10 ), # ubuntu-20.04 doesn't have windows TLS headers somehow and I haven't yet figured out how to get them
|
# ( 'x86_64', 'windows', 'mingw', 'static', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'debug', 10 ), # ubuntu-20.04 doesn't have windows TLS headers somehow and I haven't yet figured out how to get them; worse, it's a different toolchain
|
||||||
# ( 'x86_64', 'windows', 'mingw', 'static', 'linux', 'ubuntu-20.04', '', False, True, '.dbg', None, None, 'release', 10 ), # ubuntu-20.04 doesn't have windows TLS headers somehow and I haven't yet figured out how to get them
|
# ( 'x86_64', 'windows', 'mingw', 'static', 'linux', 'ubuntu-20.04', '', False, True, '.dbg', None, None, 'release', 10 ), # ubuntu-20.04 doesn't have windows TLS headers somehow and I haven't yet figured out how to get them; worse, it's a different toolchain
|
||||||
( 'x86_64', 'windows', 'mingw', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'debug', 10 ),
|
# ( 'x86_64', 'windows', 'mingw', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'debug', 10 ), # ubuntu-20.04 doesn't have ucrt64-capable mingw >_>
|
||||||
( 'x86_64', 'windows', 'mingw', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'release', 10 ),
|
# ( 'x86_64', 'windows', 'mingw', 'dynamic', 'linux', 'ubuntu-20.04', '', False, False, None, None, None, 'release', 10 ), # ubuntu-20.04 doesn't have ucrt64-capable mingw >_>
|
||||||
( 'x86_64', 'windows', 'mingw', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
( 'x86_64', 'windows', 'mingw', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
||||||
( 'x86_64', 'windows', 'mingw', 'static', 'windows', 'windows-2019', '.exe', False, True, '.dbg', None, None, 'release', 10 ),
|
( 'x86_64', 'windows', 'mingw', 'static', 'windows', 'windows-2019', '.exe', False, True, '.dbg', None, None, 'release', 10 ),
|
||||||
( 'x86_64', 'windows', 'mingw', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
( 'x86_64', 'windows', 'mingw', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
||||||
@ -111,20 +114,20 @@ for arch, platform, libc, statdyn, bplatform, runso
|
|||||||
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
||||||
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None,'x86_64-win-msvc-static', 'release', 10 ),
|
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None,'x86_64-win-msvc-static', 'release', 10 ),
|
||||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
||||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build
|
# ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build
|
||||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
|
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
|
||||||
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
||||||
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None, 'i686-win-msvc-static', 'release', 10 ),
|
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None, 'i686-win-msvc-static', 'release', 10 ),
|
||||||
( 'x86', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
( 'x86', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
||||||
( 'x86', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
|
( 'x86', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
|
||||||
( 'x86_64', 'darwin', 'macos', 'static', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'debug', 0 ), # priority = 0: static debug build
|
( 'x86_64', 'darwin', 'macos', 'static', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'debug', 0 ), # priority = 0: static debug build
|
||||||
( 'x86_64', 'darwin', 'macos', 'static', 'darwin', 'macos-11.0', '.dmg', True, True, None, 'dmg', 'x86_64-mac-gcc-static', 'release', 10 ), # I have no idea how to separate debug info on macos
|
( 'x86_64', 'darwin', 'macos', 'static', 'darwin', 'macos-12', '.dmg', True, True, None, 'dmg', 'x86_64-mac-gcc-static', 'release', 10 ), # I have no idea how to separate debug info on macos
|
||||||
( 'x86_64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'debug', 10 ),
|
( 'x86_64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'debug', 10 ),
|
||||||
( 'x86_64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'release', 10 ),
|
( 'x86_64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'release', 10 ),
|
||||||
( 'aarch64', 'darwin', 'macos', 'static', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'debug', 0 ), # priority = 0: static debug build
|
( 'aarch64', 'darwin', 'macos', 'static', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'debug', 0 ), # priority = 0: static debug build
|
||||||
( 'aarch64', 'darwin', 'macos', 'static', 'darwin', 'macos-11.0', '.dmg', True, True, None, 'dmg', 'arm64-mac-gcc-static', 'release', 10 ),
|
( 'aarch64', 'darwin', 'macos', 'static', 'darwin', 'macos-12', '.dmg', True, True, None, 'dmg', 'arm64-mac-gcc-static', 'release', 10 ),
|
||||||
# ( 'aarch64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'debug', 10 ), # macos-11.0 is x86_64 and I haven't yet figured out how to get homebrew to install aarch64 libs on x86_64
|
# ( 'aarch64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'debug', 10 ), # macos-11.0 is x86_64 and I haven't yet figured out how to get homebrew to install aarch64 libs on x86_64
|
||||||
# ( 'aarch64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-11.0', '.dmg', False, False, None, 'dmg', None, 'release', 10 ), # macos-11.0 is x86_64 and I haven't yet figured out how to get homebrew to install aarch64 libs on x86_64
|
# ( 'aarch64', 'darwin', 'macos', 'dynamic', 'darwin', 'macos-12', '.dmg', False, False, None, 'dmg', None, 'release', 10 ), # macos-11.0 is x86_64 and I haven't yet figured out how to get homebrew to install aarch64 libs on x86_64
|
||||||
( 'x86', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', False, False, None, None, None, 'debug', 0 ), # priority = 0: rarely used debug build
|
( 'x86', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', False, False, None, None, None, 'debug', 0 ), # priority = 0: rarely used debug build
|
||||||
( 'x86', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', True, True, '.dbg', None, 'i686-and-gcc-static', 'release', 10 ),
|
( 'x86', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', True, True, '.dbg', None, 'i686-and-gcc-static', 'release', 10 ),
|
||||||
( 'x86_64', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', False, False, None, None, None, 'debug', 0 ), # priority = 0: rarely used debug build
|
( 'x86_64', 'android', 'bionic', 'static', 'linux', 'ubuntu-20.04', '.apk', False, False, None, None, None, 'debug', 0 ), # priority = 0: rarely used debug build
|
||||||
@ -170,6 +173,10 @@ for arch, platform, libc, statdyn, bplatform, runso
|
|||||||
debug_asset_path = f'{app_name_slug}-{arch}.AppImage.dbg'
|
debug_asset_path = f'{app_name_slug}-{arch}.AppImage.dbg'
|
||||||
debug_asset_name = f'{app_name_slug}-{arch}.AppImage.dbg'
|
debug_asset_name = f'{app_name_slug}-{arch}.AppImage.dbg'
|
||||||
starcatcher_name = f'powder-{release_name}-{starcatcher}{suffix}'
|
starcatcher_name = f'powder-{release_name}-{starcatcher}{suffix}'
|
||||||
|
msys2_bash = (bplatform == 'windows' and libc == 'mingw')
|
||||||
|
shell = 'bash'
|
||||||
|
if msys2_bash:
|
||||||
|
shell = 'msys2 {0}'
|
||||||
build_matrix.append({
|
build_matrix.append({
|
||||||
'bsh_build_platform': bplatform, # part of the unique portion of the matrix
|
'bsh_build_platform': bplatform, # part of the unique portion of the matrix
|
||||||
'bsh_host_arch': arch, # part of the unique portion of the matrix
|
'bsh_host_arch': arch, # part of the unique portion of the matrix
|
||||||
@ -178,6 +185,7 @@ for arch, platform, libc, statdyn, bplatform, runso
|
|||||||
'bsh_static_dynamic': statdyn, # part of the unique portion of the matrix
|
'bsh_static_dynamic': statdyn, # part of the unique portion of the matrix
|
||||||
'bsh_debug_release': dbgrel, # part of the unique portion of the matrix
|
'bsh_debug_release': dbgrel, # part of the unique portion of the matrix
|
||||||
'runs_on': runson,
|
'runs_on': runson,
|
||||||
|
'force_msys2_bash': msys2_bash and 'yes' or 'no',
|
||||||
'package_suffix': suffix,
|
'package_suffix': suffix,
|
||||||
'package_mode': mode,
|
'package_mode': mode,
|
||||||
'publish': publish and 'yes' or 'no',
|
'publish': publish and 'yes' or 'no',
|
||||||
@ -188,6 +196,7 @@ for arch, platform, libc, statdyn, bplatform, runso
|
|||||||
'debug_asset_path': debug_asset_path,
|
'debug_asset_path': debug_asset_path,
|
||||||
'debug_asset_name': debug_asset_name,
|
'debug_asset_name': debug_asset_name,
|
||||||
'job_name': job_name,
|
'job_name': job_name,
|
||||||
|
'shell': shell,
|
||||||
})
|
})
|
||||||
if publish:
|
if publish:
|
||||||
publish_matrix.append({
|
publish_matrix.append({
|
||||||
|
2
.github/starcatcher-publish.sh
vendored
2
.github/starcatcher-publish.sh
vendored
@ -13,6 +13,8 @@ chmod 660 ~/.netrc
|
|||||||
mountpoint=ftpmnt
|
mountpoint=ftpmnt
|
||||||
mkdir $mountpoint
|
mkdir $mountpoint
|
||||||
curlftpfs "$PUBLISH_HOSTPORT" $mountpoint -o ssl,ciphers='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256'
|
curlftpfs "$PUBLISH_HOSTPORT" $mountpoint -o ssl,ciphers='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256'
|
||||||
|
if [[ -z ${PUBLISH_ACCESSCHECK-} ]]; then
|
||||||
cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/
|
cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/
|
||||||
|
fi
|
||||||
fusermount -u $mountpoint
|
fusermount -u $mountpoint
|
||||||
rmdir $mountpoint
|
rmdir $mountpoint
|
||||||
|
12
.github/upload-release-asset.sh
vendored
Executable file
12
.github/upload-release-asset.sh
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\t\n'
|
||||||
|
|
||||||
|
temp=.temp
|
||||||
|
mkdir $temp
|
||||||
|
cp $ASSET_PATH $temp/$ASSET_NAME
|
||||||
|
(
|
||||||
|
cd $temp
|
||||||
|
gh release upload $GITHUB_REF_NAME $ASSET_NAME
|
||||||
|
)
|
||||||
|
rm -r $temp
|
||||||
|
echo browser_download_url=https://github.com/$GITHUB_REPOSITORY/releases/download/$GITHUB_REF_NAME/$ASSET_NAME >> $GITHUB_OUTPUT
|
3
.github/vs-env.sh
vendored
Normal file → Executable file
3
.github/vs-env.sh
vendored
Normal file → Executable file
@ -24,5 +24,8 @@ IFS=$'\t\n'
|
|||||||
for i in $(MSYS_NO_PATHCONV=1 cmd /c "$vs_install_dir\\VC\\Auxiliary\\Build\\vcvarsall.bat" $VS_ENV_PARAMS \& env \& exit /b); do
|
for i in $(MSYS_NO_PATHCONV=1 cmd /c "$vs_install_dir\\VC\\Auxiliary\\Build\\vcvarsall.bat" $VS_ENV_PARAMS \& env \& exit /b); do
|
||||||
set +e
|
set +e
|
||||||
export "$i" 2>/dev/null
|
export "$i" 2>/dev/null
|
||||||
|
echo $i | grep ERROR
|
||||||
set -e
|
set -e
|
||||||
done
|
done
|
||||||
|
|
||||||
|
cl
|
||||||
|
91
.github/workflows/build.yaml
vendored
91
.github/workflows/build.yaml
vendored
@ -16,7 +16,6 @@ jobs:
|
|||||||
prepare:
|
prepare:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
release_upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
do_release: ${{ steps.prepare.outputs.do_release }}
|
do_release: ${{ steps.prepare.outputs.do_release }}
|
||||||
build_matrix: ${{ steps.prepare.outputs.build_matrix }}
|
build_matrix: ${{ steps.prepare.outputs.build_matrix }}
|
||||||
publish_matrix: ${{ steps.prepare.outputs.publish_matrix }}
|
publish_matrix: ${{ steps.prepare.outputs.publish_matrix }}
|
||||||
@ -32,8 +31,8 @@ jobs:
|
|||||||
do_publish: ${{ steps.prepare.outputs.do_publish }}
|
do_publish: ${{ steps.prepare.outputs.do_publish }}
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
- run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
|
- run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
|
||||||
@ -42,16 +41,19 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
|
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
|
||||||
GITHUB_REF: ${{ github.ref }}
|
GITHUB_REF: ${{ github.ref }}
|
||||||
|
- if: steps.prepare.outputs.do_publish == 'yes'
|
||||||
|
run: sudo apt update && sudo apt install curlftpfs && bash -c './.github/starcatcher-publish.sh'
|
||||||
|
env:
|
||||||
|
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
|
||||||
|
PUBLISH_USERNAME: ${{ secrets.STARCATCHER_PUBLISH_USERNAME }}
|
||||||
|
PUBLISH_PASSWORD: ${{ secrets.STARCATCHER_PUBLISH_PASSWORD }}
|
||||||
|
PUBLISH_ACCESSCHECK: yes
|
||||||
- if: steps.prepare.outputs.do_release == 'yes'
|
- if: steps.prepare.outputs.do_release == 'yes'
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: LBPHacker/create-release@v2
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
RELEASE_NAME: ${{ steps.prepare.outputs.release_name }}
|
||||||
tag_name: ${{ github.ref }}
|
run: bash -c './.github/create-release.sh'
|
||||||
release_name: ${{ steps.prepare.outputs.release_name }}
|
|
||||||
draft: true
|
|
||||||
prerelease: false
|
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.runs_on }}
|
runs-on: ${{ matrix.runs_on }}
|
||||||
name: ${{ matrix.job_name }}
|
name: ${{ matrix.job_name }}
|
||||||
@ -59,13 +61,46 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix: ${{ fromJSON(needs.prepare.outputs.build_matrix) }}
|
matrix: ${{ fromJSON(needs.prepare.outputs.build_matrix) }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: ${{ matrix.shell }}
|
||||||
steps:
|
steps:
|
||||||
|
- if: matrix.force_msys2_bash == 'yes'
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: UCRT64
|
||||||
|
update: true
|
||||||
|
path-type: strict
|
||||||
|
cache: true
|
||||||
|
# this list doesn't have to mirror the one in build.sh perfectly
|
||||||
|
# but the packages listed here get cached properly and take less time to install
|
||||||
|
install: >-
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
mingw-w64-ucrt-x86_64-gcc
|
||||||
|
mingw-w64-ucrt-x86_64-pkgconf
|
||||||
|
mingw-w64-ucrt-x86_64-bzip2
|
||||||
|
mingw-w64-ucrt-x86_64-luajit
|
||||||
|
mingw-w64-ucrt-x86_64-jsoncpp
|
||||||
|
mingw-w64-ucrt-x86_64-curl
|
||||||
|
mingw-w64-ucrt-x86_64-SDL2
|
||||||
|
mingw-w64-ucrt-x86_64-libpng
|
||||||
|
mingw-w64-ucrt-x86_64-meson
|
||||||
|
mingw-w64-ucrt-x86_64-python
|
||||||
|
mingw-w64-ucrt-x86_64-python-pip
|
||||||
|
mingw-w64-ucrt-x86_64-fftw
|
||||||
|
mingw-w64-ucrt-x86_64-cmake
|
||||||
|
mingw-w64-ucrt-x86_64-7zip
|
||||||
|
mingw-w64-ucrt-x86_64-jq
|
||||||
|
patch
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- if: matrix.force_msys2_bash != 'yes'
|
||||||
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
- run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
|
- if: matrix.force_msys2_bash != 'yes'
|
||||||
|
run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
|
||||||
- if: matrix.bsh_build_platform == 'darwin'
|
- if: matrix.bsh_build_platform == 'darwin'
|
||||||
run: brew install bash coreutils
|
run: brew install bash coreutils
|
||||||
- run: bash -c './.github/build.sh'
|
- run: bash -c './.github/build.sh'
|
||||||
@ -89,30 +124,24 @@ jobs:
|
|||||||
PACKAGE_MODE: ${{ matrix.package_mode }}
|
PACKAGE_MODE: ${{ matrix.package_mode }}
|
||||||
ASSET_PATH: ${{ matrix.asset_path }}
|
ASSET_PATH: ${{ matrix.asset_path }}
|
||||||
DEBUG_ASSET_PATH: ${{ matrix.debug_asset_path }}
|
DEBUG_ASSET_PATH: ${{ matrix.debug_asset_path }}
|
||||||
- uses: LBPHacker/upload-release-asset@v2 # TODO-NTL: ship licenses
|
- if: needs.prepare.outputs.do_release == 'yes' && matrix.publish == 'yes' # TODO-NTL: ship licenses
|
||||||
if: needs.prepare.outputs.do_release == 'yes' && matrix.publish == 'yes'
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
ASSET_PATH: build/${{ matrix.asset_path }}
|
||||||
upload_url: ${{ needs.prepare.outputs.release_upload_url }}
|
ASSET_NAME: ${{ matrix.asset_name }}
|
||||||
asset_path: build/${{ matrix.asset_path }}
|
run: bash -c './.github/upload-release-asset.sh'
|
||||||
asset_name: ${{ matrix.asset_name }}
|
- if: needs.prepare.outputs.do_release == 'yes' && matrix.publish == 'yes' && matrix.separate_debug == 'yes'
|
||||||
asset_content_type: application/zip
|
|
||||||
- uses: LBPHacker/upload-release-asset@v2
|
|
||||||
if: needs.prepare.outputs.do_release == 'yes' && matrix.publish == 'yes' && matrix.separate_debug == 'yes'
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
ASSET_PATH: build/${{ matrix.debug_asset_path }}
|
||||||
upload_url: ${{ needs.prepare.outputs.release_upload_url }}
|
ASSET_NAME: ${{ matrix.debug_asset_name }}
|
||||||
asset_path: build/${{ matrix.debug_asset_path }}
|
run: bash -c './.github/upload-release-asset.sh'
|
||||||
asset_name: ${{ matrix.debug_asset_name }}
|
- uses: actions/upload-artifact@v4
|
||||||
asset_content_type: application/zip
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
if: matrix.artifact == 'yes'
|
if: matrix.artifact == 'yes'
|
||||||
with:
|
with:
|
||||||
path: build/${{ matrix.asset_path }}
|
path: build/${{ matrix.asset_path }}
|
||||||
name: ${{ matrix.asset_name }}
|
name: ${{ matrix.asset_name }}
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
if: matrix.artifact == 'yes' && matrix.separate_debug == 'yes'
|
if: matrix.artifact == 'yes' && matrix.separate_debug == 'yes'
|
||||||
with:
|
with:
|
||||||
path: build/${{ matrix.debug_asset_path }}
|
path: build/${{ matrix.debug_asset_path }}
|
||||||
@ -126,8 +155,8 @@ jobs:
|
|||||||
if: needs.prepare.outputs.do_publish == 'yes'
|
if: needs.prepare.outputs.do_publish == 'yes'
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.asset_name }}
|
name: ${{ matrix.asset_name }}
|
||||||
- run: mv ${{ matrix.asset_path }} ${{ matrix.starcatcher_name }}
|
- run: mv ${{ matrix.asset_path }} ${{ matrix.starcatcher_name }}
|
||||||
@ -144,7 +173,7 @@ jobs:
|
|||||||
if: needs.prepare.outputs.do_publish == 'yes'
|
if: needs.prepare.outputs.do_publish == 'yes'
|
||||||
steps:
|
steps:
|
||||||
- run: git config --global core.autocrlf false
|
- run: git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: ./.github/starcatcher-release.sh
|
- run: ./.github/starcatcher-release.sh
|
||||||
env:
|
env:
|
||||||
RELEASE_NAME: ${{ needs.prepare.outputs.release_name }}
|
RELEASE_NAME: ${{ needs.prepare.outputs.release_name }}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
The Powder Toy - January 2023
|
The Powder Toy - April 2024
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Get the latest version [from the Powder Toy website](https://powdertoy.co.uk/Download.html).
|
Get the latest version [from the Powder Toy website](https://powdertoy.co.uk/Download.html).
|
||||||
@ -108,6 +108,7 @@ Controls
|
|||||||
| Shift + R | Horizontal mirror for selected area when pasting stamps |
|
| Shift + R | Horizontal mirror for selected area when pasting stamps |
|
||||||
| Ctrl + Shift + R | Vertical mirror for selected area when pasting stamps |
|
| Ctrl + Shift + R | Vertical mirror for selected area when pasting stamps |
|
||||||
| R | Rotate selected area counterclockwise when pasting stamps |
|
| R | Rotate selected area counterclockwise when pasting stamps |
|
||||||
|
| F11 | Toggle fullscreen |
|
||||||
|
|
||||||
Command Line
|
Command Line
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
272
android/debug.sh
Executable file
272
android/debug.sh
Executable file
@ -0,0 +1,272 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# mainly based on https://www.sh-zam.com/2019/05/debugging-krita-on-android.html
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
function get_buildoption() {
|
||||||
|
jq -r '.[] | select(.name == "'$1'") | .value' < meson-info/intro-buildoptions.json
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_cpp_compiler() {
|
||||||
|
jq -r '.[] | select(.name == "'$1'") | .target_sources.[] | select(.language == "cpp") | .compiler.[]' < meson-info/intro-targets.json
|
||||||
|
}
|
||||||
|
|
||||||
|
# customize
|
||||||
|
default_app_id=uk.co.powdertoy.tpt
|
||||||
|
default_app_exe=powder
|
||||||
|
default_lldb_server=/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/17/lib/linux/aarch64/lldb-server
|
||||||
|
default_lldb_client=/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/lldb.sh
|
||||||
|
in_build_site=no
|
||||||
|
if which jq >/dev/null && [[ -f meson-info/intro-buildoptions.json ]]; then
|
||||||
|
>&2 echo "[+] pwd is a build site, auto-detecting parameters"
|
||||||
|
in_build_site=yes
|
||||||
|
default_app_id=$(get_buildoption app_id)
|
||||||
|
default_app_exe=$(get_buildoption app_exe)
|
||||||
|
found_lldb=no
|
||||||
|
compiler_path=$(get_cpp_compiler $default_app_exe)
|
||||||
|
for line in $compiler_path; do
|
||||||
|
# iterate over the command array (might be for example [ "ccache", "aarch64-linux-android21-clang++" ])
|
||||||
|
if (echo $line | grep toolchains && basename $line | grep android | grep clang++) >/dev/null; then
|
||||||
|
arch=$(basename $line | cut -d '-' -f 1)
|
||||||
|
default_lldb_server=$(realpath $(dirname $line)/../lib/clang/*/lib/linux/$arch/lldb-server)
|
||||||
|
default_lldb_client=$(realpath $(dirname $line)/lldb.sh)
|
||||||
|
found_lldb=yes
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $found_lldb != yes ]]; then
|
||||||
|
>&2 echo "[-] cannot determine LLDB paths from compiler command array:"
|
||||||
|
for line in $compiler_path; do
|
||||||
|
>&2 echo "[-] - $line"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
>&2 echo "[+] APP_ID: $default_app_id"
|
||||||
|
>&2 echo "[+] APP_EXE: $default_app_exe"
|
||||||
|
>&2 echo "[+] LLDB_SERVER: $default_lldb_server"
|
||||||
|
>&2 echo "[+] LLDB_CLIENT: $default_lldb_client"
|
||||||
|
else
|
||||||
|
>&2 echo "[+] pwd is not a build site, not auto-detecting parameters"
|
||||||
|
fi
|
||||||
|
app_id=${APP_ID:-$default_app_id}
|
||||||
|
app_exe=${APP_EXE:-$default_app_exe}
|
||||||
|
lldb_server=${LLDB_SERVER:-$default_lldb_server}
|
||||||
|
lldb_server_port=${LLDB_SERVER_PORT:-9998}
|
||||||
|
jdb_port=${JDB_PORT:-13456}
|
||||||
|
lldb_client=${LLDB_CLIENT:-$default_lldb_client}
|
||||||
|
meson=${MESON:-meson}
|
||||||
|
adb=${ADB:-adb}
|
||||||
|
jdb=${JDB:-jdb}
|
||||||
|
|
||||||
|
# don't customize unless necessary
|
||||||
|
app_activity=${APP_ACTIVITY:-PowderActivity}
|
||||||
|
lldb_server_staging=${LLDB_SERVER_STAGING:-/data/local/tmp/lldb-server}
|
||||||
|
lldb_server_remote=${LLDB_SERVER_REMOTE:-lldb-server}
|
||||||
|
pidof_retry_count=${PIDOF_RETRY_COUNT:-20}
|
||||||
|
pidof_retry_delay=${PIDOF_RETRY_DELAY:-0.1}
|
||||||
|
|
||||||
|
function check_which() {
|
||||||
|
if ! which $1 >/dev/null; then
|
||||||
|
>&2 echo "[-] can't run $1"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_env() {
|
||||||
|
if ! [[ -f $lldb_server ]]; then
|
||||||
|
>&2 echo "[-] $lldb_server doesn't exist"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
check_which $lldb_client
|
||||||
|
check_which $adb
|
||||||
|
check_which $jdb
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_adb() {
|
||||||
|
$adb shell whoami >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybe_install_app() {
|
||||||
|
if [[ $in_build_site != yes ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
android_keystore=$(get_buildoption android_keystore)
|
||||||
|
android_keyalias=$(get_buildoption android_keyalias)
|
||||||
|
if [[ -z ${ANDROID_KEYSTORE_PASS-} ]]; then
|
||||||
|
>&2 echo "[-] ANDROID_KEYSTORE_PASS not set"
|
||||||
|
>&2 echo
|
||||||
|
>&2 cat << HELP
|
||||||
|
The current directory seems to be a build site, but ANDROID_KEYSTORE_PASS is not set, so android/$app_exe.apk cannot be invoked. If you don't have a keystore yet, create one with:
|
||||||
|
|
||||||
|
ANDROID_KEYSTORE_PASS=bagelsbagels keytool -genkey \\
|
||||||
|
-keystore $android_keystore \\
|
||||||
|
-alias $android_keyalias \\
|
||||||
|
-storepass:env ANDROID_KEYSTORE_PASS \\
|
||||||
|
-keypass:env ANDROID_KEYSTORE_PASS \\
|
||||||
|
-dname CN=bagels
|
||||||
|
|
||||||
|
Then try again with:
|
||||||
|
|
||||||
|
ANDROID_KEYSTORE_PASS=bagelsbagels $0
|
||||||
|
|
||||||
|
Naturally, replace bagelsbagels with an appropriate password.
|
||||||
|
HELP
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
>&2 echo "[+] meson compiling android/$app_exe.apk"
|
||||||
|
if ! $meson compile sign-apk; then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
>&2 echo "[+] adb installing android/$app_exe.apk"
|
||||||
|
if ! $adb install android/$app_exe.apk; then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_debuggable() {
|
||||||
|
$adb shell run-as $app_id whoami >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function find_lldb_server() {
|
||||||
|
$adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function kill_lldb_server() {
|
||||||
|
if ! $adb shell run-as $app_id pkill $lldb_server_remote; then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function adb_forward() {
|
||||||
|
>&2 echo "[+] adb forwarding tcp:$jdb_port jdwp:$pid"
|
||||||
|
if ! ($adb forward tcp:$jdb_port jdwp:$pid | grep $jdb_port >/dev/null); then
|
||||||
|
>&2 echo "[+] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function adb_unforward() {
|
||||||
|
$adb forward --remove tcp:$jdb_port
|
||||||
|
}
|
||||||
|
|
||||||
|
function undo_current_adb_forward() {
|
||||||
|
>&2 echo "[+] adb un-forwarding orphaned tcp:$jdb_port"
|
||||||
|
adb_unforward
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybe_undo_previous_adb_forward() {
|
||||||
|
if $adb forward --list | grep tcp:$jdb_port; then
|
||||||
|
>&2 echo "[+] adb un-forwarding orphaned tcp:$jdb_port"
|
||||||
|
adb_unforward
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybe_kill_previous_lldb_server() {
|
||||||
|
if find_lldb_server; then
|
||||||
|
>&2 echo "[+] killing orphaned $lldb_server_remote"
|
||||||
|
kill_lldb_server
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function kill_current_lldb_server() {
|
||||||
|
>&2 echo "[+] killing $lldb_server_remote"
|
||||||
|
kill_lldb_server
|
||||||
|
}
|
||||||
|
|
||||||
|
function start_app() {
|
||||||
|
>&2 echo "[+] starting $app_id/.$app_activity"
|
||||||
|
set +e
|
||||||
|
$adb shell am start -D -n "$app_id/.$app_activity" >/dev/null
|
||||||
|
set -e
|
||||||
|
local i
|
||||||
|
local maybe_pid
|
||||||
|
local pidof_result
|
||||||
|
for ((i = 0; i <= $pidof_retry_count; i++)); do
|
||||||
|
set +e
|
||||||
|
maybe_pid=$($adb shell pidof $app_id)
|
||||||
|
pidof_result=$?
|
||||||
|
set -e
|
||||||
|
if [[ $pidof_result == 0 ]]; then
|
||||||
|
pid=$maybe_pid
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep $pidof_retry_delay
|
||||||
|
done
|
||||||
|
if [[ -z ${pid-} ]]; then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo $pid
|
||||||
|
}
|
||||||
|
|
||||||
|
function jdb_attach() {
|
||||||
|
>&2 echo "[+] attaching jdb in the background"
|
||||||
|
$jdb -attach localhost:$jdb_port >/dev/null 2>/dev/null &
|
||||||
|
disown $!
|
||||||
|
# at some point jdb exits because it doesn't have an stdin... fine by me
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybe_deploy_lldb_server() {
|
||||||
|
if ! $adb shell [[ -f $lldb_server_staging ]]; then
|
||||||
|
>&2 echo "[+] $lldb_server_remote not present on host, deploying"
|
||||||
|
if ! ($adb push $lldb_server $lldb_server_staging && $adb shell chmod +x $lldb_server_staging); then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function start_lldb_server() {
|
||||||
|
if ! $adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null; then
|
||||||
|
>&2 echo "[+] $lldb_server_remote not running on host, starting"
|
||||||
|
$adb shell run-as $app_id cp $lldb_server_staging /data/data/$app_id/$lldb_server_remote
|
||||||
|
$adb shell run-as $app_id ./$lldb_server_remote platform --server --listen "*:$lldb_server_port" >/dev/null 2>/dev/null &
|
||||||
|
disown $!
|
||||||
|
if ! $adb shell run-as $app_id pgrep $lldb_server_remote >/dev/null; then
|
||||||
|
>&2 echo "[-] failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function start_lldb() {
|
||||||
|
local pid=$1
|
||||||
|
>&2 echo "[+] starting $lldb_client"
|
||||||
|
local lldb_init=$(mktemp)
|
||||||
|
cat - << LLDB_INIT > $lldb_init
|
||||||
|
platform select remote-android
|
||||||
|
platform connect connect://localhost:$lldb_server_port
|
||||||
|
attach $pid
|
||||||
|
continue
|
||||||
|
LLDB_INIT
|
||||||
|
local lldb_status
|
||||||
|
set +e
|
||||||
|
$lldb_client --source $lldb_init
|
||||||
|
lldb_status=$?
|
||||||
|
set -e
|
||||||
|
>&2 echo "[+] $lldb_client exited with status $lldb_status"
|
||||||
|
rm $lldb_init
|
||||||
|
}
|
||||||
|
|
||||||
|
check_env
|
||||||
|
check_adb
|
||||||
|
maybe_install_app
|
||||||
|
check_debuggable
|
||||||
|
maybe_kill_previous_lldb_server
|
||||||
|
maybe_undo_previous_adb_forward
|
||||||
|
if [[ ${1-} == clean ]]; then
|
||||||
|
>&2 echo "[+] done"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
maybe_deploy_lldb_server
|
||||||
|
start_lldb_server
|
||||||
|
pid=$(start_app)
|
||||||
|
adb_forward
|
||||||
|
jdb_attach
|
||||||
|
start_lldb $pid
|
||||||
|
kill_current_lldb_server
|
||||||
|
undo_current_adb_forward
|
||||||
|
>&2 echo "[+] done"
|
@ -23,6 +23,3 @@ if subprocess.run([
|
|||||||
apk_path,
|
apk_path,
|
||||||
]).returncode:
|
]).returncode:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(phony_path, 'w') as _:
|
|
||||||
pass
|
|
||||||
|
36
meson.build
36
meson.build
@ -44,9 +44,6 @@ if c_compiler.get_id() in [ 'msvc' ]
|
|||||||
host_libc = 'msvc'
|
host_libc = 'msvc'
|
||||||
elif c_compiler.get_id() in [ 'gcc' ] and host_platform == 'windows'
|
elif c_compiler.get_id() in [ 'gcc' ] and host_platform == 'windows'
|
||||||
host_libc = 'mingw'
|
host_libc = 'mingw'
|
||||||
if get_option('b_lto')
|
|
||||||
warning('mingw does not like static + lto')
|
|
||||||
endif
|
|
||||||
elif host_platform in [ 'darwin' ]
|
elif host_platform in [ 'darwin' ]
|
||||||
host_libc = 'macos'
|
host_libc = 'macos'
|
||||||
elif host_platform in [ 'emscripten' ]
|
elif host_platform in [ 'emscripten' ]
|
||||||
@ -69,8 +66,8 @@ if static_variant != 'prebuilt' and host_platform == 'android'
|
|||||||
warning('only prebuilt libs are supported for android')
|
warning('only prebuilt libs are supported for android')
|
||||||
static_variant = 'prebuilt'
|
static_variant = 'prebuilt'
|
||||||
endif
|
endif
|
||||||
if static_variant == 'system' and host_platform == 'windows'
|
if static_variant == 'system' and host_platform == 'windows' and host_libc == 'msvc'
|
||||||
warning('no way to find system libs on windows')
|
warning('no way to find system libs for msvc on windows')
|
||||||
static_variant = 'prebuilt'
|
static_variant = 'prebuilt'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -82,20 +79,19 @@ tpt_libs_static = 'none'
|
|||||||
if static_variant == 'prebuilt'
|
if static_variant == 'prebuilt'
|
||||||
tpt_libs_static = 'static'
|
tpt_libs_static = 'static'
|
||||||
endif
|
endif
|
||||||
if static_variant == 'none' and host_platform == 'windows'
|
if static_variant == 'none' and host_platform == 'windows' and host_libc == 'msvc'
|
||||||
tpt_libs_static = 'dynamic'
|
tpt_libs_static = 'dynamic'
|
||||||
endif
|
endif
|
||||||
tpt_libs_debug = is_debug ? 'debug' : 'release'
|
tpt_libs_debug = is_debug ? 'debug' : 'release'
|
||||||
tpt_libs_variant = '@0@-@1@-@2@-@3@'.format(host_arch, host_platform, host_libc, tpt_libs_static)
|
tpt_libs_variant = '@0@-@1@-@2@-@3@'.format(host_arch, host_platform, host_libc, tpt_libs_static)
|
||||||
tpt_libs_vtag = get_option('tpt_libs_vtag')
|
tpt_libs_vtag = get_option('tpt_libs_vtag')
|
||||||
if tpt_libs_vtag == ''
|
if tpt_libs_vtag == ''
|
||||||
tpt_libs_vtag = 'v20231003175140'
|
tpt_libs_vtag = 'v20240112165024'
|
||||||
endif
|
endif
|
||||||
if tpt_libs_static != 'none'
|
if tpt_libs_static != 'none'
|
||||||
if tpt_libs_variant not in [
|
if tpt_libs_variant not in [
|
||||||
'x86_64-linux-gnu-static',
|
'x86_64-linux-gnu-static',
|
||||||
'x86_64-windows-mingw-static',
|
'x86_64-windows-mingw-static',
|
||||||
'x86_64-windows-mingw-dynamic',
|
|
||||||
'x86_64-windows-msvc-static',
|
'x86_64-windows-msvc-static',
|
||||||
'x86_64-windows-msvc-dynamic',
|
'x86_64-windows-msvc-dynamic',
|
||||||
'x86-windows-msvc-static',
|
'x86-windows-msvc-static',
|
||||||
@ -329,7 +325,8 @@ if host_platform == 'windows'
|
|||||||
if host_arch == 'x86_64'
|
if host_arch == 'x86_64'
|
||||||
args_ccomp_win += [ '-DZLIB_WINAPI' ]
|
args_ccomp_win += [ '-DZLIB_WINAPI' ]
|
||||||
endif
|
endif
|
||||||
else
|
endif
|
||||||
|
if tpt_libs_static == 'dynamic'
|
||||||
foreach input_output_condition : tpt_libs.get_variable('config_dlls')
|
foreach input_output_condition : tpt_libs.get_variable('config_dlls')
|
||||||
dll_input = input_output_condition[0]
|
dll_input = input_output_condition[0]
|
||||||
dll_output = input_output_condition[1]
|
dll_output = input_output_condition[1]
|
||||||
@ -365,6 +362,8 @@ project_deps = []
|
|||||||
data_files = []
|
data_files = []
|
||||||
powder_deps = []
|
powder_deps = []
|
||||||
|
|
||||||
|
project_export_dynamic = false
|
||||||
|
|
||||||
subdir('src')
|
subdir('src')
|
||||||
subdir('resources')
|
subdir('resources')
|
||||||
|
|
||||||
@ -377,6 +376,22 @@ if host_platform == 'emscripten'
|
|||||||
'-o', app_exe + '.js', # so we get a .wasm, and a .js
|
'-o', app_exe + '.js', # so we get a .wasm, and a .js
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
if get_option('export_lua_symbols')
|
||||||
|
if is_static and lua_variant != 'none' and not project_export_dynamic
|
||||||
|
if host_platform == 'windows'
|
||||||
|
error('Lua symbols are currently impossible to export correctly on Windows')
|
||||||
|
elif c_compiler.has_link_argument('-Wl,--export-dynamic-symbol')
|
||||||
|
project_link_args += [
|
||||||
|
'-Wl,--export-dynamic-symbol=lua_*',
|
||||||
|
'-Wl,--export-dynamic-symbol=luaL_*',
|
||||||
|
'-Wl,--export-dynamic-symbol=luaopen_*',
|
||||||
|
]
|
||||||
|
else
|
||||||
|
warning('your linker does not support -Wl,--export-dynamic-symbol so Meson will be instructed to export all symbols in order to enable loading Lua shared modules, which may blow up the size of the resulting binary')
|
||||||
|
project_export_dynamic = true
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('build_powder')
|
if get_option('build_powder')
|
||||||
powder_deps += project_deps + [
|
powder_deps += project_deps + [
|
||||||
@ -411,6 +426,7 @@ if get_option('build_powder')
|
|||||||
win_subsystem: is_debug ? 'console' : 'windows',
|
win_subsystem: is_debug ? 'console' : 'windows',
|
||||||
link_args: project_link_args,
|
link_args: project_link_args,
|
||||||
dependencies: powder_deps,
|
dependencies: powder_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
@ -439,6 +455,7 @@ if get_option('build_render')
|
|||||||
cpp_args: project_cpp_args,
|
cpp_args: project_cpp_args,
|
||||||
link_args: render_link_args,
|
link_args: render_link_args,
|
||||||
dependencies: render_deps,
|
dependencies: render_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -462,5 +479,6 @@ if get_option('build_font')
|
|||||||
cpp_args: project_cpp_args,
|
cpp_args: project_cpp_args,
|
||||||
link_args: project_link_args,
|
link_args: project_link_args,
|
||||||
dependencies: font_deps,
|
dependencies: font_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
@ -40,42 +40,42 @@ option(
|
|||||||
'display_version_major',
|
'display_version_major',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 97,
|
value: 98,
|
||||||
description: 'Major component of the display version, should more or less map to the MINOR version in semantic versioning'
|
description: 'Major component of the display version, should more or less map to the MINOR version in semantic versioning'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
'display_version_minor',
|
'display_version_minor',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 0,
|
value: 2,
|
||||||
description: 'Minor component of the display version, should more or less map to the PATCH version in semantic versioning'
|
description: 'Minor component of the display version, should more or less map to the PATCH version in semantic versioning'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
'build_num',
|
'build_num',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 357,
|
value: 365,
|
||||||
description: 'Build number, should be strictly monotonously increasing across public releases'
|
description: 'Build number, should be strictly monotonously increasing across public releases'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
'upstream_version_major',
|
'upstream_version_major',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 97,
|
value: 98,
|
||||||
description: 'Major component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
description: 'Major component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
'upstream_version_minor',
|
'upstream_version_minor',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 0,
|
value: 2,
|
||||||
description: 'Minor component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
description: 'Minor component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
'upstream_build_num',
|
'upstream_build_num',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
min: 0,
|
min: 0,
|
||||||
value: 357,
|
value: 365,
|
||||||
description: 'Upstream build number, mod owners should not change this but merge upstream changes to it'
|
description: 'Upstream build number, mod owners should not change this but merge upstream changes to it'
|
||||||
)
|
)
|
||||||
option(
|
option(
|
||||||
@ -293,3 +293,21 @@ option(
|
|||||||
value: 'auto',
|
value: 'auto',
|
||||||
description: 'Show blue error screen upon unhandled signals and exceptions'
|
description: 'Show blue error screen upon unhandled signals and exceptions'
|
||||||
)
|
)
|
||||||
|
option(
|
||||||
|
'windows_icons',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Add icon resources to the executable on Windows'
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'windows_utf8cp',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Ask Windows nicely for UTF-8 as the codepage'
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'export_lua_symbols',
|
||||||
|
type: 'boolean',
|
||||||
|
value: false,
|
||||||
|
description: 'Export Lua symbols to enable loading of Lua shared modules'
|
||||||
|
)
|
||||||
|
@ -1,67 +1,137 @@
|
|||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static void writeU32LE(uint8_t *dest, uint32_t value)
|
||||||
|
{
|
||||||
|
dest[0] = uint8_t( value & 0xFF);
|
||||||
|
dest[1] = uint8_t((value >> 8) & 0xFF);
|
||||||
|
dest[2] = uint8_t((value >> 16) & 0xFF);
|
||||||
|
dest[3] = uint8_t((value >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t readU32BE(const uint8_t *src)
|
||||||
|
{
|
||||||
|
return uint32_t(src[3]) |
|
||||||
|
(uint32_t(src[2]) << 8) |
|
||||||
|
(uint32_t(src[1]) << 16) |
|
||||||
|
(uint32_t(src[0]) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
{
|
{
|
||||||
return 1;
|
std::cerr << "usage: " << argv[0] << " OUTPUT INPUT..." << std::endl;
|
||||||
}
|
exit(1);
|
||||||
auto *outputIcoPath = argv[1];
|
|
||||||
std::ofstream outputIco(outputIcoPath, std::ios::binary);
|
|
||||||
if (!outputIco)
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
auto images = argc - 2;
|
auto images = argc - 2;
|
||||||
std::vector<char> header(22 + images * 16);
|
if (images > 255)
|
||||||
auto *incondir = &header[0];
|
|
||||||
*reinterpret_cast<uint16_t *>(&incondir[0]) = 0; // reserved
|
|
||||||
*reinterpret_cast<uint16_t *>(&incondir[2]) = 1; // icon
|
|
||||||
*reinterpret_cast<uint16_t *>(&incondir[4]) = uint16_t(images);
|
|
||||||
std::vector<char> allData;
|
|
||||||
for (auto i = 0; i < images; ++i)
|
|
||||||
{
|
{
|
||||||
auto *inputAnyPath = argv[i + 2];
|
std::cerr << "too many images specified" << std::endl;
|
||||||
std::ifstream inputAny(inputAnyPath, std::ios::binary);
|
exit(1);
|
||||||
std::vector<char> data;
|
}
|
||||||
while (true)
|
std::string outputPath = argv[1];
|
||||||
|
std::ofstream output(outputPath, std::ios::binary);
|
||||||
|
auto outputFailure = [&outputPath](std::string action) {
|
||||||
|
std::cerr << "failed to " << action << " " << outputPath << ": " << strerror(errno) << std::endl;
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
if (!output)
|
||||||
{
|
{
|
||||||
char ch;
|
outputFailure("open");
|
||||||
inputAny.read(&ch, 1);
|
}
|
||||||
if (inputAny.eof())
|
std::vector<char> header(6 + images * 16, 0);
|
||||||
|
auto writeHeader = [&header, &output, &outputFailure]() {
|
||||||
|
output.seekp(0, std::ios_base::beg);
|
||||||
|
output.write(&header[0], header.size());
|
||||||
|
if (!output)
|
||||||
{
|
{
|
||||||
break;
|
outputFailure("write");
|
||||||
}
|
}
|
||||||
if (!inputAny)
|
};
|
||||||
|
writeHeader(); // make space for header
|
||||||
|
auto *headerU8 = reinterpret_cast<uint8_t *>(&header[0]);
|
||||||
|
headerU8[2] = 1;
|
||||||
|
headerU8[4] = images;
|
||||||
|
for (auto image = 0; image < images; ++image)
|
||||||
{
|
{
|
||||||
return 3;
|
std::string inputPath = argv[2 + image];
|
||||||
}
|
std::ifstream input(inputPath, std::ios::binary);
|
||||||
data.push_back(ch);
|
auto inputFailure = [&inputPath](std::string action) {
|
||||||
}
|
std::cerr << "failed to " << action << " " << inputPath << ": " << strerror(errno) << std::endl;
|
||||||
if (*reinterpret_cast<uint64_t *>(&data[0]) != UINT64_C(0x0A1A0A0D474E5089)) // png magic
|
exit(1);
|
||||||
|
};
|
||||||
|
auto imageFailure = [&inputPath](std::string failure) {
|
||||||
|
std::cerr << "failed to process " << inputPath << ": " << failure << std::endl;
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
if (!input)
|
||||||
{
|
{
|
||||||
return 5;
|
inputFailure("open");
|
||||||
}
|
}
|
||||||
auto width = uint8_t(data[19]);
|
std::vector<char> buf;
|
||||||
auto height = uint8_t(data[23]);
|
input.seekg(0, std::ios_base::end);
|
||||||
auto *incondirentry = &header[6 + i * 16];
|
buf.resize(input.tellg());
|
||||||
*reinterpret_cast<uint8_t *>(&incondirentry[0]) = width;
|
input.seekg(0, std::ios_base::beg);
|
||||||
*reinterpret_cast<uint8_t *>(&incondirentry[1]) = height;
|
input.read(&buf[0], buf.size());
|
||||||
*reinterpret_cast<uint8_t *>(&incondirentry[2]) = 0; // no color palette
|
if (!input)
|
||||||
*reinterpret_cast<uint8_t *>(&incondirentry[3]) = 0; // reserved
|
|
||||||
*reinterpret_cast<uint16_t *>(&incondirentry[4]) = 1; // 1 color plane
|
|
||||||
*reinterpret_cast<uint16_t *>(&incondirentry[6]) = 32; // 32 bits per pixel
|
|
||||||
*reinterpret_cast<uint32_t *>(&incondirentry[8]) = uint32_t(data.size()); // data size
|
|
||||||
*reinterpret_cast<uint32_t *>(&incondirentry[12]) = uint32_t(header.size() + allData.size()); // data offset
|
|
||||||
allData.insert(allData.end(), data.begin(), data.end());
|
|
||||||
}
|
|
||||||
outputIco.write(&header[0], header.size());
|
|
||||||
outputIco.write(&allData[0], allData.size());
|
|
||||||
if (!outputIco)
|
|
||||||
{
|
{
|
||||||
return 4;
|
inputFailure("read");
|
||||||
}
|
}
|
||||||
|
auto *bufU8 = reinterpret_cast<uint8_t *>(&buf[0]);
|
||||||
|
if (buf.size() < 0x21 ||
|
||||||
|
readU32BE(&bufU8[0]) != UINT32_C(0x89504E47) ||
|
||||||
|
readU32BE(&bufU8[4]) != UINT32_C(0x0D0A1A0A) ||
|
||||||
|
bufU8[0x18] != 8 ||
|
||||||
|
bufU8[0x19] != 6)
|
||||||
|
{
|
||||||
|
imageFailure("not a 32bpp RGBA PNG");
|
||||||
|
}
|
||||||
|
auto writeOffset = output.tellp();
|
||||||
|
output.write(&buf[0], buf.size());
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
outputFailure("write");
|
||||||
|
}
|
||||||
|
auto width = readU32BE(&bufU8[0x10]);
|
||||||
|
auto height = readU32BE(&bufU8[0x14]);
|
||||||
|
if (width == 256)
|
||||||
|
{
|
||||||
|
width = 0;
|
||||||
|
}
|
||||||
|
if (width > 255)
|
||||||
|
{
|
||||||
|
imageFailure("width exceeds U8 limit");
|
||||||
|
}
|
||||||
|
if (height == 256)
|
||||||
|
{
|
||||||
|
height = 0;
|
||||||
|
}
|
||||||
|
if (height > 255)
|
||||||
|
{
|
||||||
|
imageFailure("height exceeds U8 limit");
|
||||||
|
}
|
||||||
|
auto *entryU8 = headerU8 + 6 + image * 16;
|
||||||
|
entryU8[0] = width;
|
||||||
|
entryU8[1] = height;
|
||||||
|
entryU8[4] = 1;
|
||||||
|
entryU8[6] = 32;
|
||||||
|
if (buf.size() > UINT32_MAX)
|
||||||
|
{
|
||||||
|
imageFailure("data size exceeds U32 limit");
|
||||||
|
}
|
||||||
|
writeU32LE(&entryU8[8], uint32_t(buf.size()));
|
||||||
|
if (writeOffset > UINT32_MAX)
|
||||||
|
{
|
||||||
|
std::cerr << "output data size exceeds U32 limit" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
writeU32LE(&entryU8[12], uint32_t(writeOffset));
|
||||||
|
}
|
||||||
|
writeHeader(); // actually write it out
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -32,6 +32,16 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
if host_platform == 'windows'
|
if host_platform == 'windows'
|
||||||
|
windows_icons = get_option('windows_icons')
|
||||||
|
windows_utf8cp = get_option('windows_utf8cp')
|
||||||
|
rc_conf_depends = []
|
||||||
|
rc_conf_depend_files = [
|
||||||
|
'resource.h',
|
||||||
|
]
|
||||||
|
icon_exe_ico_path = ''
|
||||||
|
icon_cps_ico_path = ''
|
||||||
|
winutf8_xml_path = ''
|
||||||
|
if windows_icons
|
||||||
make_ico = executable('makeico', sources: 'MakeIco.cpp', native: true)
|
make_ico = executable('makeico', sources: 'MakeIco.cpp', native: true)
|
||||||
generated_win_icos = {}
|
generated_win_icos = {}
|
||||||
win_icos = {
|
win_icos = {
|
||||||
@ -52,26 +62,35 @@ if host_platform == 'windows'
|
|||||||
command: command,
|
command: command,
|
||||||
) }
|
) }
|
||||||
endforeach
|
endforeach
|
||||||
|
rc_conf_depends += [
|
||||||
|
generated_win_icos['icon_exe'],
|
||||||
|
generated_win_icos['icon_cps'],
|
||||||
|
]
|
||||||
|
icon_exe_ico_path = join_paths(meson.current_build_dir(), 'icon_exe.ico')
|
||||||
|
icon_cps_ico_path = join_paths(meson.current_build_dir(), 'icon_cps.ico')
|
||||||
|
endif
|
||||||
|
if windows_utf8cp
|
||||||
|
rc_conf_depend_files += [
|
||||||
|
'winutf8.xml',
|
||||||
|
]
|
||||||
|
winutf8_xml_path = join_paths(meson.current_source_dir(), 'winutf8.xml')
|
||||||
|
endif
|
||||||
rc_conf_data = configuration_data()
|
rc_conf_data = configuration_data()
|
||||||
rc_conf_data.merge_from(conf_data)
|
rc_conf_data.merge_from(conf_data)
|
||||||
|
rc_conf_data.set('HAVE_ICONS', windows_icons ? 1 : 0)
|
||||||
|
rc_conf_data.set('HAVE_UTF8CP', windows_utf8cp ? 1 : 0)
|
||||||
rc_conf_data.set('RESOUCE_H', join_paths(meson.current_source_dir(), 'resource.h'))
|
rc_conf_data.set('RESOUCE_H', join_paths(meson.current_source_dir(), 'resource.h'))
|
||||||
rc_conf_data.set('WINUTF8_XML', join_paths(meson.current_source_dir(), 'winutf8.xml'))
|
rc_conf_data.set('WINUTF8_XML', winutf8_xml_path)
|
||||||
rc_conf_data.set('ICON_EXE_ICO', join_paths(meson.current_build_dir(), 'icon_exe.ico'))
|
rc_conf_data.set('ICON_EXE_ICO', icon_exe_ico_path)
|
||||||
rc_conf_data.set('ICON_CPS_ICO', join_paths(meson.current_build_dir(), 'icon_cps.ico'))
|
rc_conf_data.set('ICON_CPS_ICO', icon_cps_ico_path)
|
||||||
powder_files += windows_mod.compile_resources(
|
powder_files += windows_mod.compile_resources(
|
||||||
configure_file(
|
configure_file(
|
||||||
input: 'powder-res.template.rc',
|
input: 'powder-res.template.rc',
|
||||||
output: 'powder-res.rc',
|
output: 'powder-res.rc',
|
||||||
configuration: rc_conf_data,
|
configuration: rc_conf_data,
|
||||||
),
|
),
|
||||||
depends: [
|
depends: rc_conf_depends,
|
||||||
generated_win_icos['icon_exe'],
|
depend_files: rc_conf_depend_files,
|
||||||
generated_win_icos['icon_cps'],
|
|
||||||
],
|
|
||||||
depend_files: [
|
|
||||||
'resource.h',
|
|
||||||
'winutf8.xml',
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
elif host_platform == 'darwin'
|
elif host_platform == 'darwin'
|
||||||
configure_file(
|
configure_file(
|
||||||
|
@ -5,9 +5,15 @@
|
|||||||
#include <winver.h>
|
#include <winver.h>
|
||||||
#include <ntdef.h>
|
#include <ntdef.h>
|
||||||
|
|
||||||
|
#define HAVE_ICONS @HAVE_ICONS@
|
||||||
|
#define HAVE_UTF8CP @HAVE_UTF8CP@
|
||||||
|
#if HAVE_ICONS
|
||||||
IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@"
|
IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@"
|
||||||
IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@"
|
IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@"
|
||||||
|
#endif
|
||||||
|
#if HAVE_UTF8CP
|
||||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@"
|
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@"
|
||||||
|
#endif
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@
|
FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@
|
||||||
|
@ -51,6 +51,11 @@ inline int isign(float i)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int iabs(int i)
|
||||||
|
{
|
||||||
|
return i * isign(i);
|
||||||
|
}
|
||||||
|
|
||||||
inline unsigned clamp_flt(float f, float min, float max)
|
inline unsigned clamp_flt(float f, float min, float max)
|
||||||
{
|
{
|
||||||
if (f<min)
|
if (f<min)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "gui/dialogues/ConfirmPrompt.h"
|
#include "gui/dialogues/ConfirmPrompt.h"
|
||||||
#include "gui/dialogues/ErrorMessage.h"
|
#include "gui/dialogues/ErrorMessage.h"
|
||||||
#include "gui/interface/Engine.h"
|
#include "gui/interface/Engine.h"
|
||||||
|
#include "gui/interface/TextWrapper.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "SimulationConfig.h"
|
#include "SimulationConfig.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -29,6 +30,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
void LoadWindowPosition()
|
void LoadWindowPosition()
|
||||||
{
|
{
|
||||||
@ -97,16 +100,11 @@ void TickClient()
|
|||||||
Client::Ref().Tick();
|
Client::Ref().Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTrace)
|
static void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTrace)
|
||||||
{
|
{
|
||||||
auto &engine = ui::Engine::Ref();
|
auto &engine = ui::Engine::Ref();
|
||||||
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
|
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
|
||||||
|
|
||||||
String errorText;
|
|
||||||
auto addParapgraph = [&errorText](String str) {
|
|
||||||
errorText += str + "\n\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto crashPrevLogPath = ByteString("crash.prev.log");
|
auto crashPrevLogPath = ByteString("crash.prev.log");
|
||||||
auto crashLogPath = ByteString("crash.log");
|
auto crashLogPath = ByteString("crash.log");
|
||||||
Platform::RenameFile(crashLogPath, crashPrevLogPath, true);
|
Platform::RenameFile(crashLogPath, crashPrevLogPath, true);
|
||||||
@ -131,25 +129,41 @@ void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTr
|
|||||||
{
|
{
|
||||||
crashInfo << "Stack trace not available\n";
|
crashInfo << "Stack trace not available\n";
|
||||||
}
|
}
|
||||||
addParapgraph(crashInfo.Build());
|
String errorText = crashInfo.Build();
|
||||||
|
constexpr auto width = 440;
|
||||||
engine.g->BlendText(ui::Point((engine.g->Size().X - 440) / 2, 80), errorText, 0xFFFFFF_rgb .WithAlpha(0xFF));
|
ui::TextWrapper tw;
|
||||||
|
tw.Update(errorText, true, width);
|
||||||
|
engine.g->BlendText(ui::Point((engine.g->Size().X - width) / 2, 80), tw.WrappedText(), 0xFFFFFF_rgb .WithAlpha(0xFF));
|
||||||
|
|
||||||
auto crashLogData = errorText.ToUtf8();
|
auto crashLogData = errorText.ToUtf8();
|
||||||
|
std::cerr << crashLogData << std::endl;
|
||||||
Platform::WriteFile(std::vector<char>(crashLogData.begin(), crashLogData.end()), crashLogPath);
|
Platform::WriteFile(std::vector<char>(crashLogData.begin(), crashLogData.end()), crashLogPath);
|
||||||
|
|
||||||
//Death loop
|
//Death loop
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while(true)
|
auto running = true;
|
||||||
|
while (running)
|
||||||
{
|
{
|
||||||
while (SDL_PollEvent(&event))
|
while (SDL_PollEvent(&event))
|
||||||
|
{
|
||||||
if (event.type == SDL_QUIT)
|
if (event.type == SDL_QUIT)
|
||||||
exit(-1); // Don't use Platform::Exit, we're practically zombies at this point anyway.
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
blit(engine.g->Data());
|
blit(engine.g->Data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't use Platform::Exit, we're practically zombies at this point anyway.
|
||||||
|
#if defined(__MINGW32__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
|
||||||
|
// Come on...
|
||||||
|
exit(-1);
|
||||||
|
#else
|
||||||
|
quick_exit(-1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct
|
static struct
|
||||||
{
|
{
|
||||||
int sig;
|
int sig;
|
||||||
const char *message;
|
const char *message;
|
||||||
@ -161,7 +175,7 @@ struct
|
|||||||
{ 0, nullptr },
|
{ 0, nullptr },
|
||||||
};
|
};
|
||||||
|
|
||||||
void SigHandler(int signal)
|
static void SigHandler(int signal)
|
||||||
{
|
{
|
||||||
const char *message = "Unknown signal";
|
const char *message = "Unknown signal";
|
||||||
for (auto *msg = signalMessages; msg->message; ++msg)
|
for (auto *msg = signalMessages; msg->message; ++msg)
|
||||||
@ -172,7 +186,29 @@ void SigHandler(int signal)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlueScreen(ByteString(message).FromUtf8(), Platform::StackTrace(Platform::stackTraceFromHere));
|
BlueScreen(ByteString(message).FromUtf8(), Platform::StackTrace());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TerminateHandler()
|
||||||
|
{
|
||||||
|
ByteString err = "std::terminate called without a current exception";
|
||||||
|
auto eptr = std::current_exception();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (eptr)
|
||||||
|
{
|
||||||
|
std::rethrow_exception(eptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
err = "unhandled exception: " + ByteString(e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
err = "unhandled exception not derived from std::exception, cannot determine reason";
|
||||||
|
}
|
||||||
|
BlueScreen(err.FromUtf8(), Platform::StackTrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int SCALE_MAXIMUM = 10;
|
constexpr int SCALE_MAXIMUM = 10;
|
||||||
@ -409,19 +445,20 @@ int Main(int argc, char *argv[])
|
|||||||
engine.Begin();
|
engine.Begin();
|
||||||
engine.SetFastQuit(prefs.Get("FastQuit", true));
|
engine.SetFastQuit(prefs.Get("FastQuit", true));
|
||||||
engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI);
|
engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI);
|
||||||
|
engine.windowFrameOps = windowFrameOps;
|
||||||
|
|
||||||
|
SDLOpen();
|
||||||
|
|
||||||
if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone)
|
if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone)
|
||||||
{
|
{
|
||||||
auto guessed = GuessBestScale();
|
auto guessed = GuessBestScale();
|
||||||
if (windowFrameOps.scale != guessed)
|
if (engine.windowFrameOps.scale != guessed)
|
||||||
{
|
{
|
||||||
windowFrameOps.scale = guessed;
|
engine.windowFrameOps.scale = guessed;
|
||||||
prefs.Set("Scale", windowFrameOps.scale);
|
prefs.Set("Scale", windowFrameOps.scale);
|
||||||
showLargeScreenDialog = true;
|
showLargeScreenDialog = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
engine.windowFrameOps = windowFrameOps;
|
|
||||||
|
|
||||||
SDLOpen();
|
|
||||||
|
|
||||||
bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]);
|
bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]);
|
||||||
if (enableBluescreen)
|
if (enableBluescreen)
|
||||||
@ -431,6 +468,7 @@ int Main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
signal(msg->sig, SigHandler);
|
signal(msg->sig, SigHandler);
|
||||||
}
|
}
|
||||||
|
std::set_terminate(TerminateHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (X86)
|
if constexpr (X86)
|
||||||
@ -438,7 +476,6 @@ int Main(int argc, char *argv[])
|
|||||||
X86KillDenormals();
|
X86KillDenormals();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wrapWithBluescreen = [&]() {
|
|
||||||
explicitSingletons->simulationData = std::make_unique<SimulationData>();
|
explicitSingletons->simulationData = std::make_unique<SimulationData>();
|
||||||
explicitSingletons->gameController = std::make_unique<GameController>();
|
explicitSingletons->gameController = std::make_unique<GameController>();
|
||||||
auto *gameController = explicitSingletons->gameController.get();
|
auto *gameController = explicitSingletons->gameController.get();
|
||||||
@ -529,23 +566,7 @@ int Main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
MainLoop();
|
MainLoop();
|
||||||
};
|
|
||||||
|
|
||||||
if (enableBluescreen)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wrapWithBluescreen();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
BlueScreen(ByteString(e.what()).FromUtf8(), Platform::StackTrace(Platform::stackTraceFromException));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wrapWithBluescreen();
|
|
||||||
}
|
|
||||||
Platform::Exit(0);
|
Platform::Exit(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "path to font.cpp not supplied" << std::endl;
|
std::cerr << "path to font.bz2 not supplied" << std::endl;
|
||||||
Platform::Exit(1);
|
Platform::Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ int main(int argc, char *argv[])
|
|||||||
auto inputFilename = ByteString(argv[1]);
|
auto inputFilename = ByteString(argv[1]);
|
||||||
auto outputFilename = ByteString(argv[2]) + ".png";
|
auto outputFilename = ByteString(argv[2]) + ".png";
|
||||||
|
|
||||||
|
auto simulationData = std::make_unique<SimulationData>();
|
||||||
|
|
||||||
std::vector<char> fileData;
|
std::vector<char> fileData;
|
||||||
if (!Platform::ReadFile(fileData, inputFilename))
|
if (!Platform::ReadFile(fileData, inputFilename))
|
||||||
{
|
{
|
||||||
@ -40,7 +42,6 @@ int main(int argc, char *argv[])
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto simulationData = std::make_unique<SimulationData>();
|
|
||||||
Simulation * sim = new Simulation();
|
Simulation * sim = new Simulation();
|
||||||
Renderer * ren = new Renderer(sim);
|
Renderer * ren = new Renderer(sim);
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ren->clearScreen();
|
||||||
int w = Graphics::TextSize("Save file invalid").X + 15, x = (XRES-w)/2, y = (YRES-24)/2;
|
int w = Graphics::TextSize("Save file invalid").X + 15, x = (XRES-w)/2, y = (YRES-24)/2;
|
||||||
ren->DrawRect(RectSized(Vec2{ x, y }, Vec2{ w, 24 }), 0xC0C0C0_rgb);
|
ren->DrawRect(RectSized(Vec2{ x, y }, Vec2{ w, 24 }), 0xC0C0C0_rgb);
|
||||||
ren->BlendText({ x+8, y+8 }, "Save file invalid", 0xC0C0F0_rgb .WithAlpha(255));
|
ren->BlendText({ x+8, y+8 }, "Save file invalid", 0xC0C0F0_rgb .WithAlpha(255));
|
||||||
|
@ -349,7 +349,7 @@ static void EventProcess(const SDL_Event &event)
|
|||||||
mousey = event.button.y;
|
mousey = event.button.y;
|
||||||
}
|
}
|
||||||
mouseButton = event.button.button;
|
mouseButton = event.button.button;
|
||||||
engine.onMouseClick(mousex, mousey, mouseButton);
|
engine.onMouseDown(mousex, mousey, mouseButton);
|
||||||
|
|
||||||
mouseDown = true;
|
mouseDown = true;
|
||||||
if constexpr (!DEBUG)
|
if constexpr (!DEBUG)
|
||||||
@ -365,7 +365,7 @@ static void EventProcess(const SDL_Event &event)
|
|||||||
mousey = event.button.y;
|
mousey = event.button.y;
|
||||||
}
|
}
|
||||||
mouseButton = event.button.button;
|
mouseButton = event.button.button;
|
||||||
engine.onMouseUnclick(mousex, mousey, mouseButton);
|
engine.onMouseUp(mousex, mousey, mouseButton);
|
||||||
|
|
||||||
mouseDown = false;
|
mouseDown = false;
|
||||||
if constexpr (!DEBUG)
|
if constexpr (!DEBUG)
|
||||||
|
@ -42,10 +42,13 @@ constexpr float AIR_PLOSS = 0.9999f;
|
|||||||
|
|
||||||
constexpr int NGOL = 24;
|
constexpr int NGOL = 24;
|
||||||
|
|
||||||
constexpr int CIRCLE_BRUSH = 0;
|
enum DefaultBrushes
|
||||||
constexpr int SQUARE_BRUSH = 1;
|
{
|
||||||
constexpr int TRI_BRUSH = 2;
|
BRUSH_CIRCLE,
|
||||||
constexpr int BRUSH_NUM = 3;
|
BRUSH_SQUARE,
|
||||||
|
BRUSH_TRIANGLE,
|
||||||
|
NUM_DEFAULTBRUSHES,
|
||||||
|
};
|
||||||
|
|
||||||
//Photon constants
|
//Photon constants
|
||||||
constexpr int SURF_RANGE = 10;
|
constexpr int SURF_RANGE = 10;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "client/http/StartupRequest.h"
|
#include "client/http/StartupRequest.h"
|
||||||
#include "ClientListener.h"
|
#include "ClientListener.h"
|
||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
#include "MD5.h"
|
|
||||||
#include "client/GameSave.h"
|
#include "client/GameSave.h"
|
||||||
#include "client/SaveFile.h"
|
#include "client/SaveFile.h"
|
||||||
#include "client/SaveInfo.h"
|
#include "client/SaveInfo.h"
|
||||||
@ -118,7 +117,7 @@ void Client::Tick()
|
|||||||
{
|
{
|
||||||
if (versionCheckRequest->StatusCode() == 618)
|
if (versionCheckRequest->StatusCode() == 618)
|
||||||
{
|
{
|
||||||
AddServerNotification({ "Failed to load SSL certificates", ByteString(SCHEME) + "powdertoy.co.uk/FAQ.html" });
|
AddServerNotification({ "Failed to load SSL certificates", ByteString::Build(SCHEME, SERVER, "/FAQ.html") });
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -378,7 +377,6 @@ void Client::RescanStamps()
|
|||||||
newStampIDs.push_back(stampID);
|
newStampIDs.push_back(stampID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto oldCount = newStampIDs.size();
|
|
||||||
auto stampIDsSet = std::set<ByteString>(stampIDs.begin(), stampIDs.end());
|
auto stampIDsSet = std::set<ByteString>(stampIDs.begin(), stampIDs.end());
|
||||||
for (auto &stampID : stampFilesSet)
|
for (auto &stampID : stampFilesSet)
|
||||||
{
|
{
|
||||||
@ -390,8 +388,6 @@ void Client::RescanStamps()
|
|||||||
}
|
}
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
// Move newly discovered stamps to front.
|
|
||||||
std::rotate(newStampIDs.begin(), newStampIDs.begin() + oldCount, newStampIDs.end());
|
|
||||||
stampIDs = newStampIDs;
|
stampIDs = newStampIDs;
|
||||||
WriteStamps();
|
WriteStamps();
|
||||||
}
|
}
|
||||||
|
@ -51,9 +51,18 @@ GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
|
|||||||
void GameSave::MapPalette()
|
void GameSave::MapPalette()
|
||||||
{
|
{
|
||||||
int partMap[PT_NUM];
|
int partMap[PT_NUM];
|
||||||
|
bool ignoreMissingErrors[PT_NUM];
|
||||||
for(int i = 0; i < PT_NUM; i++)
|
for(int i = 0; i < PT_NUM; i++)
|
||||||
{
|
{
|
||||||
partMap[i] = i;
|
partMap[i] = i;
|
||||||
|
ignoreMissingErrors[i] = false;
|
||||||
|
}
|
||||||
|
if (version <= Version(98, 2))
|
||||||
|
{
|
||||||
|
ignoreMissingErrors[PT_ICEI] = true;
|
||||||
|
ignoreMissingErrors[PT_SNOW] = true;
|
||||||
|
ignoreMissingErrors[PT_RSST] = true;
|
||||||
|
ignoreMissingErrors[PT_RSSS] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &sd = SimulationData::CRef();
|
auto &sd = SimulationData::CRef();
|
||||||
@ -90,12 +99,14 @@ void GameSave::MapPalette()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto paletteLookup = [this, &partMap](int type) {
|
auto paletteLookup = [this, &partMap](int type, bool ignoreMissingErrors) {
|
||||||
if (type > 0 && type < PT_NUM)
|
if (type > 0 && type < PT_NUM)
|
||||||
{
|
{
|
||||||
auto carriedType = partMap[type];
|
auto carriedType = partMap[type];
|
||||||
if (!carriedType) // type is not 0 so this shouldn't be 0 either
|
if (!carriedType) // type is not 0 so this shouldn't be 0 either
|
||||||
{
|
{
|
||||||
|
if (ignoreMissingErrors)
|
||||||
|
return type;
|
||||||
missingElements.ids.insert(type);
|
missingElements.ids.insert(type);
|
||||||
}
|
}
|
||||||
type = carriedType;
|
type = carriedType;
|
||||||
@ -113,7 +124,7 @@ void GameSave::MapPalette()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tempPart.type = paletteLookup(tempPart.type);
|
tempPart.type = paletteLookup(tempPart.type, false);
|
||||||
for (auto index : possiblyCarriesType)
|
for (auto index : possiblyCarriesType)
|
||||||
{
|
{
|
||||||
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
|
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
|
||||||
@ -121,7 +132,7 @@ void GameSave::MapPalette()
|
|||||||
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
|
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
|
||||||
auto carriedType = *prop & int(pmapmask);
|
auto carriedType = *prop & int(pmapmask);
|
||||||
auto extra = *prop >> pmapbits;
|
auto extra = *prop >> pmapbits;
|
||||||
carriedType = paletteLookup(carriedType);
|
carriedType = paletteLookup(carriedType, ignoreMissingErrors[tempPart.type]);
|
||||||
*prop = PMAP(extra, carriedType);
|
*prop = PMAP(extra, carriedType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1858,21 +1869,21 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
|
|||||||
if (p+6 > dataLength)
|
if (p+6 > dataLength)
|
||||||
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
|
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
|
||||||
{
|
{
|
||||||
auto x = data[p++];
|
int x = data[p++];
|
||||||
x |= ((unsigned)data[p++])<<8;
|
x |= ((unsigned)data[p++])<<8;
|
||||||
tempSign.x = x+partP.X;
|
tempSign.x = x+partP.X;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto y = data[p++];
|
int y = data[p++];
|
||||||
y |= ((unsigned)data[p++])<<8;
|
y |= ((unsigned)data[p++])<<8;
|
||||||
tempSign.y = y+partP.Y;
|
tempSign.y = y+partP.Y;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto ju = data[p++];
|
int ju = data[p++];
|
||||||
tempSign.ju = (sign::Justification)ju;
|
tempSign.ju = (sign::Justification)ju;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto l = data[p++];
|
int l = data[p++];
|
||||||
if (p+l > dataLength)
|
if (p+l > dataLength)
|
||||||
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
|
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
|
||||||
if(l>254)
|
if(l>254)
|
||||||
@ -2336,6 +2347,14 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
|
|||||||
{
|
{
|
||||||
RESTRICTVERSION(97, 0);
|
RESTRICTVERSION(97, 0);
|
||||||
}
|
}
|
||||||
|
if (particles[i].type == PT_RSST || particles[i].type == PT_RSSS)
|
||||||
|
{
|
||||||
|
RESTRICTVERSION(98, 0);
|
||||||
|
}
|
||||||
|
if (particles[i].type == PT_ETRD && (particles[i].tmp || particles[i].tmp2))
|
||||||
|
{
|
||||||
|
RESTRICTVERSION(98, 0);
|
||||||
|
}
|
||||||
|
|
||||||
//Get the pmap entry for the next particle in the same position
|
//Get the pmap entry for the next particle in the same position
|
||||||
i = partsPosLink[i];
|
i = partsPosLink[i];
|
||||||
|
@ -1,231 +0,0 @@
|
|||||||
// based on public-domain code from Colin Plumb (1993)
|
|
||||||
#include "MD5.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
static unsigned getu32(const unsigned char *addr)
|
|
||||||
{
|
|
||||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void putu32(unsigned data, unsigned char *addr)
|
|
||||||
{
|
|
||||||
addr[0] = (unsigned char)data;
|
|
||||||
addr[1] = (unsigned char)(data >> 8);
|
|
||||||
addr[2] = (unsigned char)(data >> 16);
|
|
||||||
addr[3] = (unsigned char)(data >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
void md5_init(struct md5_context *ctx)
|
|
||||||
{
|
|
||||||
ctx->buf[0] = 0x67452301;
|
|
||||||
ctx->buf[1] = 0xefcdab89;
|
|
||||||
ctx->buf[2] = 0x98badcfe;
|
|
||||||
ctx->buf[3] = 0x10325476;
|
|
||||||
|
|
||||||
ctx->bits[0] = 0;
|
|
||||||
ctx->bits[1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void md5_update(struct md5_context *ctx, unsigned char const *buf, unsigned len)
|
|
||||||
{
|
|
||||||
unsigned t;
|
|
||||||
|
|
||||||
// update bit count
|
|
||||||
t = ctx->bits[0];
|
|
||||||
if ((ctx->bits[0] = (t + ((unsigned)len << 3)) & 0xffffffff) < t)
|
|
||||||
ctx->bits[1]++; // carry
|
|
||||||
ctx->bits[1] += len >> 29;
|
|
||||||
|
|
||||||
t = (t >> 3) & 0x3f;
|
|
||||||
|
|
||||||
// use leading data to top up the buffer
|
|
||||||
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
unsigned char *p = ctx->in + t;
|
|
||||||
|
|
||||||
t = 64-t;
|
|
||||||
if (len < t)
|
|
||||||
{
|
|
||||||
memcpy(p, buf, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(p, buf, t);
|
|
||||||
md5_transform(ctx->buf, ctx->in);
|
|
||||||
buf += t;
|
|
||||||
len -= t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// following 64-byte chunks
|
|
||||||
|
|
||||||
while (len >= 64)
|
|
||||||
{
|
|
||||||
memcpy(ctx->in, buf, 64);
|
|
||||||
md5_transform(ctx->buf, ctx->in);
|
|
||||||
buf += 64;
|
|
||||||
len -= 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save rest of bytes for later
|
|
||||||
|
|
||||||
memcpy(ctx->in, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void md5_final(unsigned char digest[16], struct md5_context *ctx)
|
|
||||||
{
|
|
||||||
unsigned count;
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
// #bytes mod64
|
|
||||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
|
||||||
|
|
||||||
// first char of padding = 0x80
|
|
||||||
p = ctx->in + count;
|
|
||||||
*p++ = 0x80;
|
|
||||||
|
|
||||||
// calculate # of bytes to pad
|
|
||||||
count = 64 - 1 - count;
|
|
||||||
|
|
||||||
// Pad out to 56 mod 64
|
|
||||||
if (count < 8)
|
|
||||||
{
|
|
||||||
// we need to finish a whole block before padding
|
|
||||||
memset(p, 0, count);
|
|
||||||
md5_transform(ctx->buf, ctx->in);
|
|
||||||
memset(ctx->in, 0, 56);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// just pad to 56 bytes
|
|
||||||
memset(p, 0, count-8);
|
|
||||||
}
|
|
||||||
|
|
||||||
// append length & final transform
|
|
||||||
putu32(ctx->bits[0], ctx->in + 56);
|
|
||||||
putu32(ctx->bits[1], ctx->in + 60);
|
|
||||||
|
|
||||||
md5_transform(ctx->buf, ctx->in);
|
|
||||||
putu32(ctx->buf[0], digest);
|
|
||||||
putu32(ctx->buf[1], digest + 4);
|
|
||||||
putu32(ctx->buf[2], digest + 8);
|
|
||||||
putu32(ctx->buf[3], digest + 12);
|
|
||||||
memset(&ctx, 0, sizeof(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
|
||||||
#define F2(x, y, z) F1(z, x, y)
|
|
||||||
#define F3(x, y, z) (x ^ y ^ z)
|
|
||||||
#define F4(x, y, z) (y ^ (x | ~z))
|
|
||||||
|
|
||||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
|
||||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
|
||||||
|
|
||||||
void md5_transform(unsigned buf[4], const unsigned char inraw[64])
|
|
||||||
{
|
|
||||||
unsigned a, b, c, d;
|
|
||||||
unsigned in[16];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
in[i] = getu32 (inraw + 4 * i);
|
|
||||||
|
|
||||||
a = buf[0];
|
|
||||||
b = buf[1];
|
|
||||||
c = buf[2];
|
|
||||||
d = buf[3];
|
|
||||||
|
|
||||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
|
||||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
|
||||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
|
||||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
|
||||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
|
||||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
|
||||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
|
||||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
|
||||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
|
||||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
|
||||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
|
||||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
|
||||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
|
||||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
|
||||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
|
||||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
|
||||||
|
|
||||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
|
||||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
|
||||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
|
||||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
|
||||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
|
||||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
|
||||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
|
||||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
|
||||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
|
||||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
|
||||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
|
||||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
|
||||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
|
||||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
|
||||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
|
||||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
|
||||||
|
|
||||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
|
||||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
|
||||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
|
||||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
|
||||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
|
||||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
|
||||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
|
||||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
|
||||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
|
||||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
|
||||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
|
||||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
|
||||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
|
||||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
|
||||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
|
||||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
|
||||||
|
|
||||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
|
||||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
|
||||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
|
||||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
|
||||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
|
||||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
|
||||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
|
||||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
|
||||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
|
||||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
|
||||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
|
||||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
|
||||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
|
||||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
|
||||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
|
||||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
|
||||||
|
|
||||||
buf[0] += a;
|
|
||||||
buf[1] += b;
|
|
||||||
buf[2] += c;
|
|
||||||
buf[3] += d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char hexChars[] = "0123456789abcdef";
|
|
||||||
void md5_ascii(char *result, unsigned char const *buf, unsigned len)
|
|
||||||
{
|
|
||||||
struct md5_context md5;
|
|
||||||
unsigned char hash[16];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (len==0)
|
|
||||||
len = strlen((char *)buf);
|
|
||||||
|
|
||||||
md5_init(&md5);
|
|
||||||
md5_update(&md5, buf, len);
|
|
||||||
md5_final(hash, &md5);
|
|
||||||
|
|
||||||
for (i=0; i<16; i++)
|
|
||||||
{
|
|
||||||
result[i*2] = hexChars[(hash[i]>>4)&0xF];
|
|
||||||
result[i*2+1] = hexChars[hash[i]&0x0F];
|
|
||||||
}
|
|
||||||
result[32] = 0;
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
struct md5_context
|
|
||||||
{
|
|
||||||
unsigned buf[4];
|
|
||||||
unsigned bits[2];
|
|
||||||
unsigned char in[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
void md5_init(struct md5_context *context);
|
|
||||||
void md5_update(struct md5_context *context, unsigned char const *buf, unsigned len);
|
|
||||||
void md5_final(unsigned char digest[16], struct md5_context *context);
|
|
||||||
void md5_transform(unsigned buf[4], const unsigned char in[64]);
|
|
||||||
|
|
||||||
void md5_ascii(char *result, unsigned char const *buf, unsigned len);
|
|
@ -14,4 +14,13 @@ namespace http
|
|||||||
sortByVotes,
|
sortByVotes,
|
||||||
sortByDate,
|
sortByDate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Period
|
||||||
|
{
|
||||||
|
allSaves,
|
||||||
|
todaySaves,
|
||||||
|
weekSaves,
|
||||||
|
monthSaves,
|
||||||
|
yearSaves,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
LogoutRequest::LogoutRequest() :
|
LogoutRequest::LogoutRequest() :
|
||||||
APIRequest(ByteString::Build(SCHEME, SERVER, "/Logout.json?Key=" + Client::Ref().GetAuthUser().SessionKey), authRequire, false)
|
APIRequest(ByteString::Build(SCHEME, SERVER, "/Logout.json?Key=" + Client::Ref().GetAuthUser().SessionKey), authRequire, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <ctime>
|
||||||
#include "SearchSavesRequest.h"
|
#include "SearchSavesRequest.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "client/Client.h"
|
#include "client/Client.h"
|
||||||
@ -6,7 +7,7 @@
|
|||||||
|
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
static ByteString Url(int start, int count, ByteString query, Sort sort, Category category)
|
static ByteString Url(int start, int count, ByteString query, Period period, Sort sort, Category category)
|
||||||
{
|
{
|
||||||
ByteStringBuilder builder;
|
ByteStringBuilder builder;
|
||||||
builder << SCHEME << SERVER << "/Browse.json?Start=" << start << "&Count=" << count;
|
builder << SCHEME << SERVER << "/Browse.json?Start=" << start << "&Count=" << count;
|
||||||
@ -17,6 +18,38 @@ namespace http
|
|||||||
}
|
}
|
||||||
query += str;
|
query += str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
time_t currentTime = time(NULL);
|
||||||
|
|
||||||
|
if(period)
|
||||||
|
{
|
||||||
|
switch (period)
|
||||||
|
{
|
||||||
|
case todaySaves:
|
||||||
|
currentTime -= 60*60*24; // One day
|
||||||
|
break;
|
||||||
|
case weekSaves:
|
||||||
|
currentTime -= 60*60*24*7; // One week
|
||||||
|
break;
|
||||||
|
case monthSaves:
|
||||||
|
currentTime -= 60*60*24*31; // One month
|
||||||
|
break;
|
||||||
|
case yearSaves:
|
||||||
|
currentTime -= 60*60*24*365; // One year
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm currentTimeData = *localtime(¤tTime);
|
||||||
|
ByteStringBuilder afterQuery;
|
||||||
|
|
||||||
|
afterQuery << "after:" << currentTimeData.tm_year+1900 << "-" <<
|
||||||
|
(currentTimeData.tm_mon < 9 ? "0" : "") << currentTimeData.tm_mon+1 << "-" <<
|
||||||
|
(currentTimeData.tm_mday < 10 ? "0" : "") << currentTimeData.tm_mday;
|
||||||
|
appendToQuery(afterQuery.Build());
|
||||||
|
}
|
||||||
|
|
||||||
switch (sort)
|
switch (sort)
|
||||||
{
|
{
|
||||||
case sortByDate:
|
case sortByDate:
|
||||||
@ -48,7 +81,7 @@ namespace http
|
|||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category) : APIRequest(Url(start, count, query, sort, category), authUse, false)
|
SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category) : APIRequest(Url(start, count, query, period, sort, category), authUse, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ namespace http
|
|||||||
class SearchSavesRequest : public APIRequest
|
class SearchSavesRequest : public APIRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category);
|
SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category);
|
||||||
|
|
||||||
std::pair<int, std::vector<std::unique_ptr<SaveInfo>>> Finish();
|
std::pair<int, std::vector<std::unique_ptr<SaveInfo>>> Finish();
|
||||||
};
|
};
|
||||||
|
@ -52,6 +52,10 @@ namespace http
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &info = versions[key];
|
auto &info = versions[key];
|
||||||
|
if (info.isNull())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto getOr = [&info](ByteString key, int defaultValue) -> int {
|
auto getOr = [&info](ByteString key, int defaultValue) -> int {
|
||||||
if (!info.isMember(key))
|
if (!info.isMember(key))
|
||||||
{
|
{
|
||||||
@ -59,7 +63,7 @@ namespace http
|
|||||||
}
|
}
|
||||||
return info[key].asInt();
|
return info[key].asInt();
|
||||||
};
|
};
|
||||||
auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", -1);
|
auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", 0);
|
||||||
if (!updateAvailableFunc(build))
|
if (!updateAvailableFunc(build))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -68,8 +72,8 @@ namespace http
|
|||||||
channel,
|
channel,
|
||||||
ByteString::Build(SCHEME, alternate ? UPDATESERVER : SERVER, info["File"].asString()),
|
ByteString::Build(SCHEME, alternate ? UPDATESERVER : SERVER, info["File"].asString()),
|
||||||
ByteString(info["Changelog"].asString()).FromUtf8(),
|
ByteString(info["Changelog"].asString()).FromUtf8(),
|
||||||
getOr("Major", -1),
|
getOr("Major", 0),
|
||||||
getOr("Minor", -1),
|
getOr("Minor", 0),
|
||||||
build,
|
build,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ else
|
|||||||
if host_platform == 'windows'
|
if host_platform == 'windows'
|
||||||
use_system_cert_provider = true
|
use_system_cert_provider = true
|
||||||
client_files += files('WindowsCertProvider.cpp')
|
client_files += files('WindowsCertProvider.cpp')
|
||||||
|
powder_deps += c_compiler.find_library('crypt32')
|
||||||
endif
|
endif
|
||||||
if host_platform == 'android'
|
if host_platform == 'android'
|
||||||
use_system_cert_provider = true
|
use_system_cert_provider = true
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
client_files = files(
|
client_files = files(
|
||||||
'MD5.cpp',
|
|
||||||
'SaveFile.cpp',
|
'SaveFile.cpp',
|
||||||
'SaveInfo.cpp',
|
'SaveInfo.cpp',
|
||||||
'ThumbnailRendererTask.cpp',
|
'ThumbnailRendererTask.cpp',
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "common/tpt-thread-local.h"
|
|
||||||
#include "String.h"
|
#include "String.h"
|
||||||
|
|
||||||
ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto)
|
ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto)
|
||||||
@ -376,7 +375,7 @@ struct LocaleImpl
|
|||||||
|
|
||||||
static LocaleImpl *getLocaleImpl()
|
static LocaleImpl *getLocaleImpl()
|
||||||
{
|
{
|
||||||
static THREAD_LOCAL(LocaleImpl, li);
|
thread_local LocaleImpl li;
|
||||||
return &li;
|
return &li;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,14 @@ struct Vec2
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec2<T> Min(Vec2<T> other) const
|
||||||
|
{
|
||||||
|
return Vec2<T>(
|
||||||
|
std::min(X, other.X),
|
||||||
|
std::min(Y, other.Y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Return a rectangle starting at origin, whose dimensions match this vector
|
// Return a rectangle starting at origin, whose dimensions match this vector
|
||||||
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
|
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
|
||||||
constexpr inline Rect<T> OriginRect() const
|
constexpr inline Rect<T> OriginRect() const
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include "common/String.h"
|
#include "common/String.h"
|
||||||
|
|
||||||
class GameSave;
|
class GameSave;
|
||||||
@ -13,4 +14,5 @@ namespace Clipboard
|
|||||||
bool GetEnabled();
|
bool GetEnabled();
|
||||||
void SetEnabled(bool newEnabled);
|
void SetEnabled(bool newEnabled);
|
||||||
void RecreateWindow();
|
void RecreateWindow();
|
||||||
|
std::optional<String> Explanation();
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,11 @@ namespace Clipboard
|
|||||||
}
|
}
|
||||||
return gdc;
|
return gdc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<String> Explanation() final override
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ClipboardImpl> CocoaClipboardFactory()
|
std::unique_ptr<ClipboardImpl> CocoaClipboardFactory()
|
||||||
|
@ -24,7 +24,7 @@ namespace Clipboard
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<GameSave> clipboardData;
|
std::unique_ptr<GameSave> clipboardData;
|
||||||
std::unique_ptr<ClipboardImpl> clipboard;
|
static std::unique_ptr<ClipboardImpl> clipboard;
|
||||||
|
|
||||||
void InvokeClipboardSetClipboardData()
|
void InvokeClipboardSetClipboardData()
|
||||||
{
|
{
|
||||||
@ -94,7 +94,7 @@ namespace Clipboard
|
|||||||
static bool enabled = false;
|
static bool enabled = false;
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
enabled = GlobalPrefs::Ref().Get<bool>("NativeClipboard.Enabled", true);
|
enabled = GlobalPrefs::Ref().Get("NativeClipboard.Enabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetEnabled()
|
bool GetEnabled()
|
||||||
@ -131,4 +131,9 @@ namespace Clipboard
|
|||||||
}
|
}
|
||||||
InvokeClipboardSetClipboardData();
|
InvokeClipboardSetClipboardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<String> Explanation()
|
||||||
|
{
|
||||||
|
return clipboard ? clipboard->Explanation() : std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class GameSave;
|
class GameSave;
|
||||||
|
|
||||||
@ -35,6 +36,8 @@ namespace Clipboard
|
|||||||
GetClipboardDataUnknown
|
GetClipboardDataUnknown
|
||||||
>;
|
>;
|
||||||
virtual GetClipboardDataResult GetClipboardData() = 0;
|
virtual GetClipboardDataResult GetClipboardData() = 0;
|
||||||
|
|
||||||
|
virtual std::optional<String> Explanation() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<GameSave> clipboardData;
|
extern std::unique_ptr<GameSave> clipboardData;
|
||||||
|
@ -18,6 +18,7 @@ namespace Clipboard
|
|||||||
ByteString inCommand;
|
ByteString inCommand;
|
||||||
ByteString formatsCommand;
|
ByteString formatsCommand;
|
||||||
ByteString outCommand;
|
ByteString outCommand;
|
||||||
|
std::optional<String> explanation;
|
||||||
std::optional<int> defaultForSubsystem;
|
std::optional<int> defaultForSubsystem;
|
||||||
};
|
};
|
||||||
std::map<ByteString, Preset> builtInPresets = {
|
std::map<ByteString, Preset> builtInPresets = {
|
||||||
@ -25,12 +26,14 @@ namespace Clipboard
|
|||||||
"xclip -selection clipboard -target %s",
|
"xclip -selection clipboard -target %s",
|
||||||
"xclip -out -selection clipboard -target TARGETS",
|
"xclip -out -selection clipboard -target TARGETS",
|
||||||
"xclip -out -selection clipboard -target %s",
|
"xclip -out -selection clipboard -target %s",
|
||||||
|
"Requires the xclip utility to be installed",
|
||||||
SDL_SYSWM_X11,
|
SDL_SYSWM_X11,
|
||||||
} },
|
} },
|
||||||
{ "wl-clipboard", {
|
{ "wl-clipboard", {
|
||||||
"wl-copy --type %s",
|
"wl-copy --type %s",
|
||||||
"wl-paste --list-types",
|
"wl-paste --list-types",
|
||||||
"wl-paste --type %s",
|
"wl-paste --type %s",
|
||||||
|
"Requires the wl-clipboard utility to be installed",
|
||||||
SDL_SYSWM_WAYLAND,
|
SDL_SYSWM_WAYLAND,
|
||||||
} },
|
} },
|
||||||
};
|
};
|
||||||
@ -98,6 +101,7 @@ namespace Clipboard
|
|||||||
SubstFormat(it->second.inCommand),
|
SubstFormat(it->second.inCommand),
|
||||||
SubstFormat(it->second.formatsCommand),
|
SubstFormat(it->second.formatsCommand),
|
||||||
SubstFormat(it->second.outCommand),
|
SubstFormat(it->second.outCommand),
|
||||||
|
it->second.explanation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +244,12 @@ namespace Clipboard
|
|||||||
}
|
}
|
||||||
return GetClipboardDataChanged{ std::move(*saveDataOpt) };
|
return GetClipboardDataChanged{ std::move(*saveDataOpt) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<String> Explanation() final override
|
||||||
|
{
|
||||||
|
auto preset = GetPreset();
|
||||||
|
return preset ? preset->explanation : std::nullopt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ClipboardImpl> ExternalClipboardFactory()
|
std::unique_ptr<ClipboardImpl> ExternalClipboardFactory()
|
||||||
|
@ -28,4 +28,9 @@ namespace Clipboard
|
|||||||
void RecreateWindow()
|
void RecreateWindow()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<String> Explanation()
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,11 @@ namespace Clipboard
|
|||||||
auto base = reinterpret_cast<const char *>(data.get());
|
auto base = reinterpret_cast<const char *>(data.get());
|
||||||
return GetClipboardDataChanged{ std::vector<char>(base, base + size) };
|
return GetClipboardDataChanged{ std::vector<char>(base, base + size) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<String> Explanation() final override
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ClipboardImpl> WindowsClipboardFactory()
|
std::unique_ptr<ClipboardImpl> WindowsClipboardFactory()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
common_files += files(
|
common_files += files(
|
||||||
'String.cpp',
|
'String.cpp',
|
||||||
'tpt-rand.cpp',
|
'tpt-rand.cpp',
|
||||||
'tpt-thread-local.cpp',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('clipboard')
|
subdir('clipboard')
|
||||||
|
@ -58,7 +58,7 @@ bool ReadFile(std::vector<char> &fileData, ByteString filename)
|
|||||||
if (f) f.seekg(0, std::ios::end);
|
if (f) f.seekg(0, std::ios::end);
|
||||||
if (f) fileData.resize(f.tellg());
|
if (f) fileData.resize(f.tellg());
|
||||||
if (f) f.seekg(0);
|
if (f) f.seekg(0);
|
||||||
if (f) f.read(&fileData[0], fileData.size());
|
if (f && fileData.size()) f.read(&fileData[0], fileData.size());
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl;
|
std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl;
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
@ -25,9 +28,28 @@ long unsigned int GetTime()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ByteString ExecutableNameFirstApprox()
|
ByteString ExecutableNameFirstApprox()
|
||||||
|
{
|
||||||
|
if (Stat("/proc/self/exe"))
|
||||||
{
|
{
|
||||||
return "/proc/self/exe";
|
return "/proc/self/exe";
|
||||||
}
|
}
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
{
|
||||||
|
int mib[4];
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC;
|
||||||
|
mib[2] = KERN_PROC_PATHNAME;
|
||||||
|
mib[3] = -1;
|
||||||
|
std::array<char, 1000> buf;
|
||||||
|
size_t cb = buf.size();
|
||||||
|
if (!sysctl(mib, 4, &buf[0], &cb, NULL, 0))
|
||||||
|
{
|
||||||
|
return ByteString(&buf[0], &buf[0] + cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
bool CanUpdate()
|
bool CanUpdate()
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "common/String.h"
|
#include "common/String.h"
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -69,12 +70,7 @@ namespace Platform
|
|||||||
|
|
||||||
int InvokeMain(int argc, char *argv[]);
|
int InvokeMain(int argc, char *argv[]);
|
||||||
|
|
||||||
enum StackTraceType
|
std::optional<std::vector<String>> StackTrace();
|
||||||
{
|
|
||||||
stackTraceFromHere,
|
|
||||||
stackTraceFromException,
|
|
||||||
};
|
|
||||||
std::optional<std::vector<String>> StackTrace(StackTraceType StackTraceType);
|
|
||||||
|
|
||||||
void MarkPresentable();
|
void MarkPresentable();
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,15 @@ else
|
|||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
bluescreen_export_symbols = false
|
||||||
|
|
||||||
subdir('stacktrace')
|
subdir('stacktrace')
|
||||||
|
|
||||||
if use_bluescreen
|
if use_bluescreen
|
||||||
common_files += stacktrace_files
|
common_files += stacktrace_files
|
||||||
|
if bluescreen_export_symbols and is_debug
|
||||||
|
project_export_dynamic = true
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
common_files += files('stacktrace/Null.cpp')
|
common_files += files('stacktrace/Null.cpp')
|
||||||
endif
|
endif
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
std::optional<std::vector<String>> StackTrace(StackTraceType)
|
std::optional<std::vector<String>> StackTrace()
|
||||||
{
|
{
|
||||||
std::array<void *, 100> buf;
|
std::array<void *, 100> buf;
|
||||||
auto used = backtrace(&buf[0], buf.size());
|
auto used = backtrace(&buf[0], buf.size());
|
||||||
@ -19,7 +21,27 @@ std::optional<std::vector<String>> StackTrace(StackTraceType)
|
|||||||
{
|
{
|
||||||
if (strs)
|
if (strs)
|
||||||
{
|
{
|
||||||
res.push_back(ByteString(strs[i]).FromUtf8());
|
auto line = ByteString(strs[i]);
|
||||||
|
if (auto beginSymbolName = line.SplitBy('('))
|
||||||
|
{
|
||||||
|
auto afterBeginSymbolName = beginSymbolName.After();
|
||||||
|
if (auto endSymbolName = afterBeginSymbolName.SplitBy('+'))
|
||||||
|
{
|
||||||
|
auto beforeSymbolName = beginSymbolName.Before();
|
||||||
|
auto symbolName = endSymbolName.Before();
|
||||||
|
auto afterSymbolName = endSymbolName.After();
|
||||||
|
int status;
|
||||||
|
char *demangled = abi::__cxa_demangle(symbolName.c_str(), NULL, NULL, &status);
|
||||||
|
Defer freeDemangled([demangled]() {
|
||||||
|
free(demangled);
|
||||||
|
});
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
line = ByteString::Build(beforeSymbolName, "(", demangled, "+", afterSymbolName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push_back(line.FromUtf8());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
std::optional<std::vector<String>> StackTrace(StackTraceType)
|
std::optional<std::vector<String>> StackTrace()
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,47 @@
|
|||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <cstdint>
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
|
||||||
extern "C" void **__cdecl __current_exception_context();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static CONTEXT *CurrentExceptionContext()
|
|
||||||
{
|
|
||||||
// TODO: find the corresponding hack for mingw and older msvc; stack traces printed for exceptions are broken without it
|
|
||||||
CONTEXT **pctx = nullptr;
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
|
||||||
pctx = (CONTEXT **)__current_exception_context();
|
|
||||||
#endif
|
|
||||||
return pctx ? *pctx : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
std::optional<std::vector<String>> StackTrace(StackTraceType stackTraceType)
|
struct SymbolInfo
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
uintptr_t displacement;
|
||||||
|
};
|
||||||
|
static std::optional<SymbolInfo> GetSymbolInfo(HANDLE process, uintptr_t offset)
|
||||||
|
{
|
||||||
|
DWORD64 displacement;
|
||||||
|
std::array<char, sizeof(SYMBOL_INFOW) + 1000> symbolData{};
|
||||||
|
auto &symbol = *reinterpret_cast<SYMBOL_INFOW *>(&symbolData[0]);
|
||||||
|
symbol.SizeOfStruct = sizeof(symbol);
|
||||||
|
symbol.MaxNameLen = symbolData.size() - sizeof(symbol);
|
||||||
|
if (SymFromAddrW(process, offset, &displacement, &symbol))
|
||||||
|
{
|
||||||
|
return SymbolInfo{ WinNarrow(&symbol.Name[0]).FromUtf8(), uintptr_t(displacement) };
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModuleInfo
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
uintptr_t displacement;
|
||||||
|
};
|
||||||
|
static std::optional<ModuleInfo> GetModuleInfo(HANDLE process, uintptr_t offset)
|
||||||
|
{
|
||||||
|
IMAGEHLP_MODULEW64 module{};
|
||||||
|
module.SizeOfStruct = sizeof(module);
|
||||||
|
if (SymGetModuleInfoW64(process, offset, &module))
|
||||||
|
{
|
||||||
|
auto displacement = offset - uintptr_t(module.BaseOfImage);
|
||||||
|
return ModuleInfo{ WinNarrow(&module.LoadedImageName[0]).FromUtf8(), displacement };
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::vector<String>> StackTrace()
|
||||||
{
|
{
|
||||||
static std::mutex mx;
|
static std::mutex mx;
|
||||||
std::unique_lock lk(mx);
|
std::unique_lock lk(mx);
|
||||||
@ -36,32 +59,11 @@ std::optional<std::vector<String>> StackTrace(StackTraceType stackTraceType)
|
|||||||
});
|
});
|
||||||
SymInitialize(process, NULL, TRUE);
|
SymInitialize(process, NULL, TRUE);
|
||||||
|
|
||||||
CONTEXT context;
|
CONTEXT context{};
|
||||||
memset(&context, 0, sizeof(context));
|
|
||||||
switch (stackTraceType)
|
|
||||||
{
|
|
||||||
case stackTraceFromException:
|
|
||||||
if (auto *ec = CurrentExceptionContext())
|
|
||||||
{
|
|
||||||
if (ec->ContextFlags)
|
|
||||||
{
|
|
||||||
context = *ec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!context.ContextFlags)
|
|
||||||
{
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
context.ContextFlags = CONTEXT_FULL;
|
context.ContextFlags = CONTEXT_FULL;
|
||||||
RtlCaptureContext(&context);
|
RtlCaptureContext(&context);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
STACKFRAME64 frame;
|
STACKFRAME64 frame{};
|
||||||
memset(&frame, 0, sizeof(frame));
|
|
||||||
DWORD machine;
|
DWORD machine;
|
||||||
#if defined(_M_IX86)
|
#if defined(_M_IX86)
|
||||||
machine = IMAGE_FILE_MACHINE_I386;
|
machine = IMAGE_FILE_MACHINE_I386;
|
||||||
@ -108,20 +110,25 @@ std::optional<std::vector<String>> StackTrace(StackTraceType stackTraceType)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
auto offset = uintptr_t(frame.AddrPC.Offset);
|
||||||
StringBuilder addr;
|
StringBuilder addr;
|
||||||
addr << "0x" << Format::Hex() << uintptr_t(frame.AddrPC.Offset);
|
addr << Format::Hex();
|
||||||
std::array<wchar_t, 1000> moduleBaseName;
|
if (auto moduleInfo = GetModuleInfo(process, offset))
|
||||||
HMODULE module;
|
|
||||||
MODULEINFO moduleInfo;
|
|
||||||
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)frame.AddrPC.Offset, &module) &&
|
|
||||||
GetModuleBaseNameW(process, module, &moduleBaseName[0], moduleBaseName.size()) &&
|
|
||||||
GetModuleInformation(process, module, &moduleInfo, sizeof(moduleInfo)))
|
|
||||||
{
|
{
|
||||||
auto offset = uintptr_t(frame.AddrPC.Offset) - uintptr_t(moduleInfo.lpBaseOfDll);
|
addr << moduleInfo->name << "(";
|
||||||
if (offset < moduleInfo.SizeOfImage)
|
if (auto symbolInfo = GetSymbolInfo(process, offset))
|
||||||
{
|
{
|
||||||
addr << " (" << WinNarrow(&moduleBaseName[0]).FromUtf8() << "+0x" << Format::Hex() << offset << ")";
|
addr << symbolInfo->name << "+0x" << symbolInfo->displacement;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addr << "+0x" << moduleInfo->displacement;
|
||||||
|
}
|
||||||
|
addr << ") [0x" << offset << "]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addr << "0x" << offset;
|
||||||
}
|
}
|
||||||
res.push_back(addr.Build());
|
res.push_back(addr.Build());
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,20 @@ if host_platform == 'windows'
|
|||||||
endif
|
endif
|
||||||
stacktrace_files = files('Windows.cpp')
|
stacktrace_files = files('Windows.cpp')
|
||||||
elif host_platform == 'darwin'
|
elif host_platform == 'darwin'
|
||||||
# stacktrace_files = files('Execinfo.cpp') # macos has this but it's useless >_>
|
# TODO: good impl; current one is only slightly better than nothing
|
||||||
stacktrace_files = files('Null.cpp')
|
stacktrace_files = files('Execinfo.cpp')
|
||||||
|
# export symbols so backtrace_symbols works, see https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
|
||||||
|
bluescreen_export_symbols = true
|
||||||
elif host_platform == 'linux'
|
elif host_platform == 'linux'
|
||||||
# TODO: again, this is more like "posix" than "linux"
|
# TODO: again, this is more like "posix" than "linux"
|
||||||
stacktrace_files = files('Execinfo.cpp')
|
stacktrace_files = files('Execinfo.cpp')
|
||||||
|
# export symbols so backtrace_symbols works, see above
|
||||||
|
bluescreen_export_symbols = true
|
||||||
|
if host_machine.system() in [ 'freebsd' ]
|
||||||
|
project_deps += [
|
||||||
|
c_compiler.find_library('execinfo'),
|
||||||
|
]
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
stacktrace_files = files('Null.cpp')
|
stacktrace_files = files('Null.cpp')
|
||||||
endif
|
endif
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
#include "tpt-thread-local.h"
|
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
# include <pthread.h>
|
|
||||||
# include <cstdlib>
|
|
||||||
# include <cassert>
|
|
||||||
|
|
||||||
void *ThreadLocalCommon::Get() const
|
|
||||||
{
|
|
||||||
// https://stackoverflow.com/questions/16552710/how-do-you-get-the-start-and-end-addresses-of-a-custom-elf-section
|
|
||||||
extern ThreadLocalCommon __start_tpt_tls;
|
|
||||||
extern ThreadLocalCommon __stop_tpt_tls;
|
|
||||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
|
||||||
static pthread_key_t key;
|
|
||||||
|
|
||||||
struct ThreadLocalEntry
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto *staticsBegin = &__start_tpt_tls;
|
|
||||||
auto *staticsEnd = &__stop_tpt_tls;
|
|
||||||
pthread_once(&once, []() -> void {
|
|
||||||
assert(!pthread_key_create(&key, [](void *opaque) -> void {
|
|
||||||
auto *staticsBegin = &__start_tpt_tls;
|
|
||||||
auto *staticsEnd = &__stop_tpt_tls;
|
|
||||||
auto staticsCount = staticsEnd - staticsBegin;
|
|
||||||
auto *liveObjects = reinterpret_cast<ThreadLocalEntry *>(opaque);
|
|
||||||
if (liveObjects)
|
|
||||||
{
|
|
||||||
for (auto i = 0; i < staticsCount; ++i)
|
|
||||||
{
|
|
||||||
if (liveObjects[i].ptr)
|
|
||||||
{
|
|
||||||
staticsBegin[i].dtor(liveObjects[i].ptr);
|
|
||||||
free(liveObjects[i].ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(liveObjects);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
auto *liveObjects = reinterpret_cast<ThreadLocalEntry *>(pthread_getspecific(key));
|
|
||||||
if (!liveObjects)
|
|
||||||
{
|
|
||||||
auto staticsCount = staticsEnd - staticsBegin;
|
|
||||||
liveObjects = reinterpret_cast<ThreadLocalEntry *>(calloc(staticsCount, sizeof(ThreadLocalEntry)));
|
|
||||||
assert(liveObjects);
|
|
||||||
assert(!pthread_setspecific(key, reinterpret_cast<void *>(liveObjects)));
|
|
||||||
}
|
|
||||||
auto idx = this - staticsBegin;
|
|
||||||
auto &entry = liveObjects[idx];
|
|
||||||
if (!entry.ptr)
|
|
||||||
{
|
|
||||||
entry.ptr = malloc(staticsBegin[idx].size);
|
|
||||||
assert(entry.ptr);
|
|
||||||
staticsBegin[idx].ctor(entry.ptr);
|
|
||||||
}
|
|
||||||
return entry.ptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
# include <cstddef>
|
|
||||||
|
|
||||||
class ThreadLocalCommon
|
|
||||||
{
|
|
||||||
ThreadLocalCommon(const ThreadLocalCommon &other) = delete;
|
|
||||||
ThreadLocalCommon &operator =(const ThreadLocalCommon &other) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
size_t size;
|
|
||||||
void (*ctor)(void *);
|
|
||||||
void (*dtor)(void *);
|
|
||||||
size_t padding;
|
|
||||||
|
|
||||||
void *Get() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ThreadLocalCommon() = default;
|
|
||||||
|
|
||||||
static constexpr size_t Alignment = 0x20;
|
|
||||||
};
|
|
||||||
// * If this fails, add or remove padding fields, possibly change Alignment to a larger power of 2.
|
|
||||||
static_assert(sizeof(ThreadLocalCommon) == ThreadLocalCommon::Alignment, "fix me");
|
|
||||||
|
|
||||||
template<class Type>
|
|
||||||
class ThreadLocal : public ThreadLocalCommon
|
|
||||||
{
|
|
||||||
static void Ctor(void *type)
|
|
||||||
{
|
|
||||||
new(type) Type();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Dtor(void *type)
|
|
||||||
{
|
|
||||||
reinterpret_cast<Type *>(type)->~Type();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ThreadLocal()
|
|
||||||
{
|
|
||||||
// * If this fails, you're out of luck.
|
|
||||||
static_assert(sizeof(ThreadLocal<Type>) == sizeof(ThreadLocalCommon), "fix me");
|
|
||||||
size = sizeof(Type);
|
|
||||||
ctor = Ctor;
|
|
||||||
dtor = Dtor;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *operator &() const
|
|
||||||
{
|
|
||||||
return reinterpret_cast<Type *>(Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
operator Type &() const
|
|
||||||
{
|
|
||||||
return *(this->operator &());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
# define THREAD_LOCAL(Type, tl) const ThreadLocal<Type> tl __attribute__((section("tpt_tls"), aligned(ThreadLocalCommon::Alignment)))
|
|
||||||
#else
|
|
||||||
# define THREAD_LOCAL(Type, tl) thread_local Type tl
|
|
||||||
#endif
|
|
@ -183,6 +183,8 @@ void Renderer::render_parts()
|
|||||||
gfctx.pipeSubcallTpart = nullptr;
|
gfctx.pipeSubcallTpart = nullptr;
|
||||||
int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y;
|
int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y;
|
||||||
int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0};
|
int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0};
|
||||||
|
int drawing_budget = 1000000; //Serves as an upper bound for costly effects such as SPARK, FLARE and LFLARE
|
||||||
|
|
||||||
if(!sim)
|
if(!sim)
|
||||||
return;
|
return;
|
||||||
auto *parts = sim->parts;
|
auto *parts = sim->parts;
|
||||||
@ -633,7 +635,7 @@ void Renderer::render_parts()
|
|||||||
{
|
{
|
||||||
auto flicker = float(gfctx.rng()%20);
|
auto flicker = float(gfctx.rng()%20);
|
||||||
auto gradv = 4*sim->parts[i].life + flicker;
|
auto gradv = 4*sim->parts[i].life + flicker;
|
||||||
for (x = 0; gradv>0.5; x++) {
|
for (x = 0; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||||
auto col = RGBA<uint8_t>(
|
auto col = RGBA<uint8_t>(
|
||||||
std::min(0xFF, colr * int(gradv) / 255),
|
std::min(0xFF, colr * int(gradv) / 255),
|
||||||
std::min(0xFF, colg * int(gradv) / 255),
|
std::min(0xFF, colg * int(gradv) / 255),
|
||||||
@ -644,6 +646,7 @@ void Renderer::render_parts()
|
|||||||
AddPixel({ nx, ny+x }, col);
|
AddPixel({ nx, ny+x }, col);
|
||||||
AddPixel({ nx, ny-x }, col);
|
AddPixel({ nx, ny-x }, col);
|
||||||
gradv = gradv/1.5f;
|
gradv = gradv/1.5f;
|
||||||
|
drawing_budget--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pixel_mode & PMODE_FLARE)
|
if(pixel_mode & PMODE_FLARE)
|
||||||
@ -660,12 +663,13 @@ void Renderer::render_parts()
|
|||||||
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
for (x = 1; gradv>0.5; x++) {
|
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||||
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
gradv = gradv/1.2f;
|
gradv = gradv/1.2f;
|
||||||
|
drawing_budget--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pixel_mode & PMODE_LFLARE)
|
if(pixel_mode & PMODE_LFLARE)
|
||||||
@ -682,12 +686,13 @@ void Renderer::render_parts()
|
|||||||
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
for (x = 1; gradv>0.5; x++) {
|
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||||
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||||
gradv = gradv/1.01f;
|
gradv = gradv/1.01f;
|
||||||
|
drawing_budget--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pixel_mode & EFFECT_GRAVIN)
|
if (pixel_mode & EFFECT_GRAVIN)
|
||||||
|
@ -41,6 +41,8 @@ class Renderer: public RasterDrawMethods<Renderer>
|
|||||||
|
|
||||||
friend struct RasterDrawMethods<Renderer>;
|
friend struct RasterDrawMethods<Renderer>;
|
||||||
|
|
||||||
|
float fireIntensity = 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vec2<int> Size() const
|
Vec2<int> Size() const
|
||||||
{
|
{
|
||||||
@ -97,6 +99,10 @@ public:
|
|||||||
void DrawSigns();
|
void DrawSigns();
|
||||||
void render_gravlensing(const Video &source);
|
void render_gravlensing(const Video &source);
|
||||||
void render_fire();
|
void render_fire();
|
||||||
|
float GetFireIntensity() const
|
||||||
|
{
|
||||||
|
return fireIntensity;
|
||||||
|
}
|
||||||
void prepare_alpha(int size, float intensity);
|
void prepare_alpha(int size, float intensity);
|
||||||
void render_parts();
|
void render_parts();
|
||||||
void draw_grav_zones();
|
void draw_grav_zones();
|
||||||
|
@ -11,7 +11,6 @@ constexpr auto VIDYRES = WINDOWH;
|
|||||||
|
|
||||||
void Renderer::RenderBegin()
|
void Renderer::RenderBegin()
|
||||||
{
|
{
|
||||||
draw_air();
|
|
||||||
draw_grav();
|
draw_grav();
|
||||||
DrawWalls();
|
DrawWalls();
|
||||||
render_parts();
|
render_parts();
|
||||||
@ -142,9 +141,10 @@ float glow_alphaf[11][11];
|
|||||||
float blur_alphaf[7][7];
|
float blur_alphaf[7][7];
|
||||||
void Renderer::prepare_alpha(int size, float intensity)
|
void Renderer::prepare_alpha(int size, float intensity)
|
||||||
{
|
{
|
||||||
|
fireIntensity = intensity;
|
||||||
//TODO: implement size
|
//TODO: implement size
|
||||||
int x,y,i,j;
|
int x,y,i,j;
|
||||||
float multiplier = 255.0f*intensity;
|
float multiplier = 255.0f*fireIntensity;
|
||||||
|
|
||||||
memset(temp, 0, sizeof(temp));
|
memset(temp, 0, sizeof(temp));
|
||||||
for (x=0; x<CELL; x++)
|
for (x=0; x<CELL; x++)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "gui/interface/Textbox.h"
|
#include "gui/interface/Textbox.h"
|
||||||
|
#include "gui/interface/ScrollPanel.h"
|
||||||
#include "gui/interface/Label.h"
|
#include "gui/interface/Label.h"
|
||||||
#include "gui/game/Tool.h"
|
#include "gui/game/Tool.h"
|
||||||
#include "gui/game/Menu.h"
|
#include "gui/game/Menu.h"
|
||||||
@ -52,6 +53,9 @@ ElementSearchActivity::ElementSearchActivity(GameController * gameController, st
|
|||||||
AddComponent(okButton);
|
AddComponent(okButton);
|
||||||
AddComponent(closeButton);
|
AddComponent(closeButton);
|
||||||
|
|
||||||
|
scrollPanel = new ui::ScrollPanel(searchField->Position + Vec2{ 1, searchField->Size.Y+9 }, { searchField->Size.X - 2, Size.Y-(searchField->Position.Y+searchField->Size.Y+6)-23 });
|
||||||
|
AddComponent(scrollPanel);
|
||||||
|
|
||||||
searchTools("");
|
searchTools("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,12 +63,12 @@ void ElementSearchActivity::searchTools(String query)
|
|||||||
{
|
{
|
||||||
firstResult = NULL;
|
firstResult = NULL;
|
||||||
for (auto &toolButton : toolButtons) {
|
for (auto &toolButton : toolButtons) {
|
||||||
RemoveComponent(toolButton);
|
scrollPanel->RemoveChild(toolButton);
|
||||||
delete toolButton;
|
delete toolButton;
|
||||||
}
|
}
|
||||||
toolButtons.clear();
|
toolButtons.clear();
|
||||||
|
|
||||||
ui::Point viewPosition = searchField->Position + ui::Point(2+0, searchField->Size.Y+2+8);
|
ui::Point viewPosition = { 1, 1 };
|
||||||
ui::Point current = ui::Point(0, 0);
|
ui::Point current = ui::Point(0, 0);
|
||||||
|
|
||||||
String queryLower = query.ToLower();
|
String queryLower = query.ToLower();
|
||||||
@ -178,7 +182,7 @@ void ElementSearchActivity::searchTools(String query)
|
|||||||
}
|
}
|
||||||
|
|
||||||
toolButtons.push_back(tempButton);
|
toolButtons.push_back(tempButton);
|
||||||
AddComponent(tempButton);
|
scrollPanel->AddChild(tempButton);
|
||||||
|
|
||||||
current.X += 31;
|
current.X += 31;
|
||||||
|
|
||||||
@ -186,10 +190,13 @@ void ElementSearchActivity::searchTools(String query)
|
|||||||
current.X = 0;
|
current.X = 0;
|
||||||
current.Y += 19;
|
current.Y += 19;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current.Y + viewPosition.Y + 18 > Size.Y-23)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current.X == 0)
|
||||||
|
{
|
||||||
|
current.Y -= 19;
|
||||||
|
}
|
||||||
|
scrollPanel->InnerSize = ui::Point(scrollPanel->Size.X, current.Y + 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElementSearchActivity::SetActiveTool(int selectionState, Tool * tool)
|
void ElementSearchActivity::SetActiveTool(int selectionState, Tool * tool)
|
||||||
@ -216,8 +223,7 @@ void ElementSearchActivity::OnDraw()
|
|||||||
g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb);
|
g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb);
|
||||||
|
|
||||||
g->BlendRect(
|
g->BlendRect(
|
||||||
RectSized(Position + searchField->Position + Vec2{ 0, searchField->Size.Y+8 },
|
RectSized(Position + scrollPanel->Position - Vec2{ 1, 1 }, scrollPanel->Size + Vec2{ 2, 2 }),
|
||||||
{ searchField->Size.X, Size.Y-(searchField->Position.Y+searchField->Size.Y+8)-23 }),
|
|
||||||
0xFFFFFF_rgb .WithAlpha(180));
|
0xFFFFFF_rgb .WithAlpha(180));
|
||||||
if (toolTipPresence && toolTip.length())
|
if (toolTipPresence && toolTip.length())
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ class GameController;
|
|||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
|
class ScrollPanel;
|
||||||
class Textbox;
|
class Textbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ class ElementSearchActivity: public WindowActivity
|
|||||||
std::vector<Tool*> tools;
|
std::vector<Tool*> tools;
|
||||||
ui::Textbox * searchField;
|
ui::Textbox * searchField;
|
||||||
std::vector<ToolButton*> toolButtons;
|
std::vector<ToolButton*> toolButtons;
|
||||||
|
ui::ScrollPanel *scrollPanel = nullptr;
|
||||||
String toolTip;
|
String toolTip;
|
||||||
int toolTipPresence;
|
int toolTipPresence;
|
||||||
bool shiftPressed;
|
bool shiftPressed;
|
||||||
|
@ -39,7 +39,7 @@ class LoadFilesTask: public Task
|
|||||||
bool doWork() override
|
bool doWork() override
|
||||||
{
|
{
|
||||||
std::vector<ByteString> files = Platform::DirectorySearch(directory, search, { ".cps" });
|
std::vector<ByteString> files = Platform::DirectorySearch(directory, search, { ".cps" });
|
||||||
std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() < b.ToLower(); });
|
std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() > b.ToLower(); });
|
||||||
|
|
||||||
notifyProgress(-1);
|
notifyProgress(-1);
|
||||||
for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter)
|
for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter)
|
||||||
|
@ -52,6 +52,14 @@ void Brush::InitOutline()
|
|||||||
|
|
||||||
void Brush::SetRadius(ui::Point newRadius)
|
void Brush::SetRadius(ui::Point newRadius)
|
||||||
{
|
{
|
||||||
|
if (newRadius.X < 0)
|
||||||
|
newRadius.X = 0;
|
||||||
|
if (newRadius.Y < 0)
|
||||||
|
newRadius.Y = 0;
|
||||||
|
if (newRadius.X > 200)
|
||||||
|
newRadius.X = 200;
|
||||||
|
if (newRadius.Y > 200)
|
||||||
|
newRadius.Y = 200;
|
||||||
radius = newRadius;
|
radius = newRadius;
|
||||||
InitOutline();
|
InitOutline();
|
||||||
}
|
}
|
||||||
@ -67,14 +75,6 @@ void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY)
|
|||||||
newSize = oldSize + ui::Point(delta * std::max(oldSize.X / 5, 1), delta * std::max(oldSize.Y / 5, 1));
|
newSize = oldSize + ui::Point(delta * std::max(oldSize.X / 5, 1), delta * std::max(oldSize.Y / 5, 1));
|
||||||
else
|
else
|
||||||
newSize = oldSize + ui::Point(delta, delta);
|
newSize = oldSize + ui::Point(delta, delta);
|
||||||
if (newSize.X < 0)
|
|
||||||
newSize.X = 0;
|
|
||||||
if (newSize.Y < 0)
|
|
||||||
newSize.Y = 0;
|
|
||||||
if (newSize.X > 200)
|
|
||||||
newSize.X = 200;
|
|
||||||
if (newSize.Y > 200)
|
|
||||||
newSize.Y = 200;
|
|
||||||
|
|
||||||
if (keepY)
|
if (keepY)
|
||||||
SetRadius(ui::Point(newSize.X, oldSize.Y));
|
SetRadius(ui::Point(newSize.X, oldSize.Y));
|
||||||
|
@ -90,7 +90,7 @@ GameController::GameController():
|
|||||||
|
|
||||||
gameView->SetDebugHUD(GlobalPrefs::Ref().Get("Renderer.DebugMode", false));
|
gameView->SetDebugHUD(GlobalPrefs::Ref().Get("Renderer.DebugMode", false));
|
||||||
|
|
||||||
CommandInterface::Create(this, gameModel);
|
commandInterface = CommandInterface::Create(this, gameModel);
|
||||||
|
|
||||||
Client::Ref().AddListener(this);
|
Client::Ref().AddListener(this);
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ GameController::~GameController()
|
|||||||
{
|
{
|
||||||
delete *iter;
|
delete *iter;
|
||||||
}
|
}
|
||||||
delete commandInterface;
|
commandInterface.reset();
|
||||||
delete gameModel;
|
delete gameModel;
|
||||||
if (gameView->CloseActiveWindow())
|
if (gameView->CloseActiveWindow())
|
||||||
{
|
{
|
||||||
@ -552,7 +552,7 @@ bool GameController::MouseUp(int x, int y, unsigned button, MouseupReason reason
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case sign::Type::Thread:
|
case sign::Type::Thread:
|
||||||
Platform::OpenURI(ByteString::Build(SCHEME, "powdertoy.co.uk/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8()));
|
Platform::OpenURI(ByteString::Build(SCHEME, SERVER, "/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8()));
|
||||||
break;
|
break;
|
||||||
case sign::Type::Search:
|
case sign::Type::Search:
|
||||||
OpenSearch(str.Substr(3, si.first - 3));
|
OpenSearch(str.Substr(3, si.first - 3));
|
||||||
@ -785,7 +785,7 @@ void GameController::ResetSpark()
|
|||||||
|
|
||||||
void GameController::SwitchGravity()
|
void GameController::SwitchGravity()
|
||||||
{
|
{
|
||||||
gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode + 1) % NUM_GRAV_MODES;
|
gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode + 1) % NUM_GRAVMODES;
|
||||||
|
|
||||||
switch (gameModel->GetSimulation()->gravityMode)
|
switch (gameModel->GetSimulation()->gravityMode)
|
||||||
{
|
{
|
||||||
@ -806,23 +806,23 @@ void GameController::SwitchGravity()
|
|||||||
|
|
||||||
void GameController::SwitchAir()
|
void GameController::SwitchAir()
|
||||||
{
|
{
|
||||||
gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode + 1) % NUM_AIR_MODES;
|
gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode + 1) % NUM_AIRMODES;
|
||||||
|
|
||||||
switch (gameModel->GetSimulation()->air->airMode)
|
switch (gameModel->GetSimulation()->air->airMode)
|
||||||
{
|
{
|
||||||
case AIR_ON:
|
case AIR_ON:
|
||||||
gameModel->SetInfoTip("Air: On");
|
gameModel->SetInfoTip("Air: On");
|
||||||
break;
|
break;
|
||||||
case AIR_PRESSURE_OFF:
|
case AIR_PRESSUREOFF:
|
||||||
gameModel->SetInfoTip("Air: Pressure Off");
|
gameModel->SetInfoTip("Air: Pressure Off");
|
||||||
break;
|
break;
|
||||||
case AIR_VELOCITY_OFF:
|
case AIR_VELOCITYOFF:
|
||||||
gameModel->SetInfoTip("Air: Velocity Off");
|
gameModel->SetInfoTip("Air: Velocity Off");
|
||||||
break;
|
break;
|
||||||
case AIR_OFF:
|
case AIR_OFF:
|
||||||
gameModel->SetInfoTip("Air: Off");
|
gameModel->SetInfoTip("Air: Off");
|
||||||
break;
|
break;
|
||||||
case AIR_NO_UPDATE:
|
case AIR_NOUPDATE:
|
||||||
gameModel->SetInfoTip("Air: No Update");
|
gameModel->SetInfoTip("Air: No Update");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1031,7 +1031,7 @@ int GameController::GetEdgeMode()
|
|||||||
|
|
||||||
void GameController::SetEdgeMode(int edgeMode)
|
void GameController::SetEdgeMode(int edgeMode)
|
||||||
{
|
{
|
||||||
if (edgeMode < 0 || edgeMode >= NUM_EDGE_MODES)
|
if (edgeMode < 0 || edgeMode >= NUM_EDGEMODES)
|
||||||
edgeMode = 0;
|
edgeMode = 0;
|
||||||
|
|
||||||
gameModel->SetEdgeMode(edgeMode);
|
gameModel->SetEdgeMode(edgeMode);
|
||||||
@ -1111,9 +1111,12 @@ void GameController::SetActiveTool(int toolSelection, Tool * tool)
|
|||||||
gameModel->SetLastTool(tool);
|
gameModel->SetLastTool(tool);
|
||||||
for(int i = 0; i < 3; i++)
|
for(int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if(gameModel->GetActiveTool(i) == gameModel->GetMenuList().at(SC_WALL)->GetToolList().at(WL_GRAV))
|
auto *activeTool = gameModel->GetActiveTool(i);
|
||||||
|
if (activeTool && activeTool->Identifier == "DEFAULT_WL_GRVTY")
|
||||||
|
{
|
||||||
gameModel->GetRenderer()->gravityZonesEnabled = true;
|
gameModel->GetRenderer()->gravityZonesEnabled = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (tool->Identifier == "DEFAULT_UI_PROPERTY")
|
if (tool->Identifier == "DEFAULT_UI_PROPERTY")
|
||||||
{
|
{
|
||||||
static_cast<PropertyTool *>(tool)->OpenWindow(gameModel->GetSimulation(), nullptr);
|
static_cast<PropertyTool *>(tool)->OpenWindow(gameModel->GetSimulation(), nullptr);
|
||||||
@ -1386,7 +1389,7 @@ void GameController::OpenOptions()
|
|||||||
void GameController::ShowConsole()
|
void GameController::ShowConsole()
|
||||||
{
|
{
|
||||||
if (!console)
|
if (!console)
|
||||||
console = new ConsoleController(NULL, commandInterface);
|
console = new ConsoleController(NULL, commandInterface.get());
|
||||||
if (console->GetView() != ui::Engine::Ref().GetWindow())
|
if (console->GetView() != ui::Engine::Ref().GetWindow())
|
||||||
ui::Engine::Ref().ShowWindow(console->GetView());
|
ui::Engine::Ref().ShowWindow(console->GetView());
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "lua/CommandInterfacePtr.h"
|
||||||
#include "client/ClientListener.h"
|
#include "client/ClientListener.h"
|
||||||
#include "client/StartupInfo.h"
|
#include "client/StartupInfo.h"
|
||||||
#include "gui/interface/Point.h"
|
#include "gui/interface/Point.h"
|
||||||
@ -28,7 +29,6 @@ class LocalBrowserController;
|
|||||||
class SearchController;
|
class SearchController;
|
||||||
class PreviewController;
|
class PreviewController;
|
||||||
class RenderController;
|
class RenderController;
|
||||||
class CommandInterface;
|
|
||||||
class VideoBuffer;
|
class VideoBuffer;
|
||||||
class Tool;
|
class Tool;
|
||||||
class Menu;
|
class Menu;
|
||||||
@ -39,6 +39,8 @@ class TagsController;
|
|||||||
class ConsoleController;
|
class ConsoleController;
|
||||||
class GameController: public ClientListener
|
class GameController: public ClientListener
|
||||||
{
|
{
|
||||||
|
CommandInterfacePtr commandInterface;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool firstTick;
|
bool firstTick;
|
||||||
int foundSignID;
|
int foundSignID;
|
||||||
@ -126,6 +128,7 @@ public:
|
|||||||
int GetEdgeMode();
|
int GetEdgeMode();
|
||||||
void SetEdgeMode(int edgeMode);
|
void SetEdgeMode(int edgeMode);
|
||||||
void SetDebugFlags(unsigned int flags) { debugFlags = flags; }
|
void SetDebugFlags(unsigned int flags) { debugFlags = flags; }
|
||||||
|
unsigned int GetDebugFlags() const { return debugFlags; }
|
||||||
void SetActiveMenu(int menuID);
|
void SetActiveMenu(int menuID);
|
||||||
std::vector<Menu*> GetMenuList();
|
std::vector<Menu*> GetMenuList();
|
||||||
int GetNumMenus(bool onlyEnabled);
|
int GetNumMenus(bool onlyEnabled);
|
||||||
|
@ -54,16 +54,16 @@ GameModel::GameModel():
|
|||||||
colour(255, 0, 0, 255),
|
colour(255, 0, 0, 255),
|
||||||
edgeMode(EDGE_VOID),
|
edgeMode(EDGE_VOID),
|
||||||
ambientAirTemp(R_TEMP + 273.15f),
|
ambientAirTemp(R_TEMP + 273.15f),
|
||||||
decoSpace(0)
|
decoSpace(DECOSPACE_SRGB)
|
||||||
{
|
{
|
||||||
sim = new Simulation();
|
sim = new Simulation();
|
||||||
sim->useLuaCallbacks = true;
|
sim->useLuaCallbacks = true;
|
||||||
ren = new Renderer(sim);
|
ren = new Renderer(sim);
|
||||||
|
|
||||||
activeTools = regularToolset;
|
activeTools = ®ularToolset[0];
|
||||||
|
|
||||||
std::fill(decoToolset, decoToolset+4, (Tool*)NULL);
|
std::fill(decoToolset.begin(), decoToolset.end(), nullptr);
|
||||||
std::fill(regularToolset, regularToolset+4, (Tool*)NULL);
|
std::fill(regularToolset.begin(), regularToolset.end(), nullptr);
|
||||||
|
|
||||||
//Default render prefs
|
//Default render prefs
|
||||||
ren->SetRenderMode({
|
ren->SetRenderMode({
|
||||||
@ -93,7 +93,7 @@ GameModel::GameModel():
|
|||||||
ren->decorations_enable = prefs.Get("Renderer.Decorations", true);
|
ren->decorations_enable = prefs.Get("Renderer.Decorations", true);
|
||||||
|
|
||||||
//Load config into simulation
|
//Load config into simulation
|
||||||
edgeMode = prefs.Get("Simulation.EdgeMode", (int)EDGE_VOID);
|
edgeMode = prefs.Get("Simulation.EdgeMode", NUM_EDGEMODES, EDGE_VOID);
|
||||||
sim->SetEdgeMode(edgeMode);
|
sim->SetEdgeMode(edgeMode);
|
||||||
ambientAirTemp = float(R_TEMP) + 273.15f;
|
ambientAirTemp = float(R_TEMP) + 273.15f;
|
||||||
{
|
{
|
||||||
@ -104,9 +104,9 @@ GameModel::GameModel():
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sim->air->ambientAirTemp = ambientAirTemp;
|
sim->air->ambientAirTemp = ambientAirTemp;
|
||||||
decoSpace = prefs.Get("Simulation.DecoSpace", 0); // TODO: DecoSpace enum
|
decoSpace = prefs.Get("Simulation.DecoSpace", NUM_DECOSPACES, DECOSPACE_SRGB);
|
||||||
sim->SetDecoSpace(decoSpace);
|
sim->SetDecoSpace(decoSpace);
|
||||||
int ngrav_enable = prefs.Get("Simulation.NewtonianGravity", 0); // TODO: NewtonianGravity enum
|
int ngrav_enable = prefs.Get("Simulation.NewtonianGravity", NUM_GRAVMODES, GRAV_VERTICAL);
|
||||||
if (ngrav_enable)
|
if (ngrav_enable)
|
||||||
sim->grav->start_grav_async();
|
sim->grav->start_grav_async();
|
||||||
sim->aheat_enable = prefs.Get("Simulation.AmbientHeat", 0); // TODO: AmbientHeat enum
|
sim->aheat_enable = prefs.Get("Simulation.AmbientHeat", 0); // TODO: AmbientHeat enum
|
||||||
@ -228,7 +228,7 @@ void GameModel::BuildMenus()
|
|||||||
if(activeMenu != -1)
|
if(activeMenu != -1)
|
||||||
lastMenu = activeMenu;
|
lastMenu = activeMenu;
|
||||||
|
|
||||||
ByteString activeToolIdentifiers[4];
|
std::array<ByteString, NUM_TOOLINDICES> activeToolIdentifiers;
|
||||||
if(regularToolset[0])
|
if(regularToolset[0])
|
||||||
activeToolIdentifiers[0] = regularToolset[0]->Identifier;
|
activeToolIdentifiers[0] = regularToolset[0]->Identifier;
|
||||||
if(regularToolset[1])
|
if(regularToolset[1])
|
||||||
@ -881,17 +881,17 @@ void GameModel::SetActiveMenu(int menuID)
|
|||||||
|
|
||||||
if(menuID == SC_DECO)
|
if(menuID == SC_DECO)
|
||||||
{
|
{
|
||||||
if(activeTools != decoToolset)
|
if(activeTools != &decoToolset[0])
|
||||||
{
|
{
|
||||||
activeTools = decoToolset;
|
activeTools = &decoToolset[0];
|
||||||
notifyActiveToolsChanged();
|
notifyActiveToolsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(activeTools != regularToolset)
|
if(activeTools != ®ularToolset[0])
|
||||||
{
|
{
|
||||||
activeTools = regularToolset;
|
activeTools = ®ularToolset[0];
|
||||||
notifyActiveToolsChanged();
|
notifyActiveToolsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1712,7 +1712,7 @@ void GameModel::BeforeSim()
|
|||||||
{
|
{
|
||||||
if (!sim->sys_pause || sim->framerender)
|
if (!sim->sys_pause || sim->framerender)
|
||||||
{
|
{
|
||||||
commandInterface->HandleEvent(BeforeSimEvent{});
|
CommandInterface::Ref().HandleEvent(BeforeSimEvent{});
|
||||||
}
|
}
|
||||||
sim->BeforeSim();
|
sim->BeforeSim();
|
||||||
}
|
}
|
||||||
@ -1720,5 +1720,5 @@ void GameModel::BeforeSim()
|
|||||||
void GameModel::AfterSim()
|
void GameModel::AfterSim()
|
||||||
{
|
{
|
||||||
sim->AfterSim();
|
sim->AfterSim();
|
||||||
commandInterface->HandleEvent(AfterSimEvent{});
|
CommandInterface::Ref().HandleEvent(AfterSimEvent{});
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
constexpr auto NUM_TOOLINDICES = 4;
|
||||||
|
|
||||||
class Menu;
|
class Menu;
|
||||||
class Tool;
|
class Tool;
|
||||||
@ -72,8 +75,8 @@ private:
|
|||||||
std::unique_ptr<SaveFile> currentFile;
|
std::unique_ptr<SaveFile> currentFile;
|
||||||
Tool * lastTool;
|
Tool * lastTool;
|
||||||
Tool ** activeTools;
|
Tool ** activeTools;
|
||||||
Tool * decoToolset[4];
|
std::array<Tool *, NUM_TOOLINDICES> decoToolset;
|
||||||
Tool * regularToolset[4];
|
std::array<Tool *, NUM_TOOLINDICES> regularToolset;
|
||||||
User currentUser;
|
User currentUser;
|
||||||
float toolStrength;
|
float toolStrength;
|
||||||
std::deque<HistoryEntry> history;
|
std::deque<HistoryEntry> history;
|
||||||
@ -192,6 +195,10 @@ public:
|
|||||||
Brush &GetBrush();
|
Brush &GetBrush();
|
||||||
Brush *GetBrushByID(int i);
|
Brush *GetBrushByID(int i);
|
||||||
int GetBrushID();
|
int GetBrushID();
|
||||||
|
int BrushListSize() const
|
||||||
|
{
|
||||||
|
return int(brushList.size());
|
||||||
|
}
|
||||||
void SetBrushID(int i);
|
void SetBrushID(int i);
|
||||||
|
|
||||||
void SetVote(int direction);
|
void SetVote(int direction);
|
||||||
|
@ -87,7 +87,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void OnMouseUnclick(int x, int y, unsigned int button) override
|
void OnMouseClick(int x, int y, unsigned int button) override
|
||||||
{
|
{
|
||||||
if(isButtonDown)
|
if(isButtonDown)
|
||||||
{
|
{
|
||||||
@ -96,7 +96,7 @@ public:
|
|||||||
else if(rightDown)
|
else if(rightDown)
|
||||||
DoRightAction();
|
DoRightAction();
|
||||||
}
|
}
|
||||||
ui::Button::OnMouseUnclick(x, y, button);
|
ui::Button::OnMouseClick(x, y, button);
|
||||||
|
|
||||||
}
|
}
|
||||||
void OnMouseHover(int x, int y) override
|
void OnMouseHover(int x, int y) override
|
||||||
@ -120,16 +120,19 @@ public:
|
|||||||
toolTip = newToolTip1;
|
toolTip = newToolTip1;
|
||||||
toolTip2 = newToolTip2;
|
toolTip2 = newToolTip2;
|
||||||
}
|
}
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override
|
void OnMouseDown(int x, int y, unsigned int button) override
|
||||||
|
{
|
||||||
|
ui::Button::OnMouseDown(x, y, button);
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
ui::Button::OnMouseClick(x, y, button);
|
|
||||||
rightDown = false;
|
rightDown = false;
|
||||||
leftDown = false;
|
leftDown = false;
|
||||||
if(x >= splitPosition)
|
if(x - Position.X >= splitPosition)
|
||||||
rightDown = true;
|
rightDown = true;
|
||||||
else if(x < splitPosition)
|
else if(x - Position.X < splitPosition)
|
||||||
leftDown = true;
|
leftDown = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void DoRightAction()
|
void DoRightAction()
|
||||||
{
|
{
|
||||||
if(!Enabled)
|
if(!Enabled)
|
||||||
@ -1052,14 +1055,21 @@ void GameView::updateToolButtonScroll()
|
|||||||
{
|
{
|
||||||
for (auto *button : toolButtons)
|
for (auto *button : toolButtons)
|
||||||
{
|
{
|
||||||
if (button->Position.X < x && button->Position.X + button->Size.X > x)
|
auto inside = button->Position.X < x && button->Position.X + button->Size.X > x;
|
||||||
|
if (inside && !button->MouseInside)
|
||||||
|
{
|
||||||
|
button->MouseInside = true;
|
||||||
button->OnMouseEnter(x, y);
|
button->OnMouseEnter(x, y);
|
||||||
else
|
}
|
||||||
|
if (!inside && button->MouseInside)
|
||||||
|
{
|
||||||
|
button->MouseInside = false;
|
||||||
button->OnMouseLeave(x, y);
|
button->OnMouseLeave(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameView::OnMouseMove(int x, int y, int dx, int dy)
|
void GameView::OnMouseMove(int x, int y, int dx, int dy)
|
||||||
{
|
{
|
||||||
@ -2124,6 +2134,7 @@ void GameView::OnDraw()
|
|||||||
auto &sd = SimulationData::Ref();
|
auto &sd = SimulationData::Ref();
|
||||||
std::unique_lock lk(sd.elementGraphicsMx);
|
std::unique_lock lk(sd.elementGraphicsMx);
|
||||||
ren->clearScreen();
|
ren->clearScreen();
|
||||||
|
ren->draw_air();
|
||||||
c->BeforeSimDraw();
|
c->BeforeSimDraw();
|
||||||
ren->RenderBegin();
|
ren->RenderBegin();
|
||||||
ren->SetSample(c->PointTranslate(currentMouse));
|
ren->SetSample(c->PointTranslate(currentMouse));
|
||||||
@ -2370,7 +2381,7 @@ void GameView::OnDraw()
|
|||||||
if (type == PT_CRAY || type == PT_DRAY || type == PT_EXOT || type == PT_LIGH || type == PT_SOAP || type == PT_TRON
|
if (type == PT_CRAY || type == PT_DRAY || type == PT_EXOT || type == PT_LIGH || type == PT_SOAP || type == PT_TRON
|
||||||
|| type == PT_VIBR || type == PT_VIRS || type == PT_WARP || type == PT_LCRY || type == PT_CBNW || type == PT_TSNS
|
|| type == PT_VIBR || type == PT_VIRS || type == PT_WARP || type == PT_LCRY || type == PT_CBNW || type == PT_TSNS
|
||||||
|| type == PT_DTEC || type == PT_LSNS || type == PT_PSTN || type == PT_LDTC || type == PT_VSNS || type == PT_LITH
|
|| type == PT_DTEC || type == PT_LSNS || type == PT_PSTN || type == PT_LDTC || type == PT_VSNS || type == PT_LITH
|
||||||
|| type == PT_CONV)
|
|| type == PT_CONV || type == PT_ETRD)
|
||||||
sampleInfo << ", Tmp2: " << sample.particle.tmp2;
|
sampleInfo << ", Tmp2: " << sample.particle.tmp2;
|
||||||
|
|
||||||
sampleInfo << ", Pressure: " << sample.AirPressure;
|
sampleInfo << ", Pressure: " << sample.AirPressure;
|
||||||
|
@ -76,7 +76,7 @@ inline ByteString IntroText()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb << "\bgTo use online features such as saving, you need to register at: \brhttps://powdertoy.co.uk/Register.html\n";
|
sb << "\bgTo use online features such as saving, you need to register at: \brhttps://" << SERVER << "/Register.html\n";
|
||||||
}
|
}
|
||||||
sb << "\n\bt" << VersionInfo();
|
sb << "\n\bt" << VersionInfo();
|
||||||
return sb.Build();
|
return sb.Build();
|
||||||
|
@ -16,12 +16,15 @@ ToolButton::ToolButton(ui::Point position, ui::Point size, String text, ByteStri
|
|||||||
Component::TextPosition(buttonDisplayText);
|
Component::TextPosition(buttonDisplayText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolButton::OnMouseClick(int x, int y, unsigned int button)
|
void ToolButton::OnMouseDown(int x, int y, unsigned int button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
isButtonDown = true;
|
isButtonDown = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ToolButton::OnMouseUnclick(int x, int y, unsigned int button)
|
void ToolButton::OnMouseClick(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
if(isButtonDown)
|
if(isButtonDown)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@ class ToolButton: public ui::Button
|
|||||||
ByteString toolIdentifier;
|
ByteString toolIdentifier;
|
||||||
public:
|
public:
|
||||||
ToolButton(ui::Point position, ui::Point size, String text, ByteString toolIdentifier, String toolTip = String());
|
ToolButton(ui::Point position, ui::Point size, String text, ByteString toolIdentifier, String toolTip = String());
|
||||||
void OnMouseUnclick(int x, int y, unsigned int button) override;
|
void OnMouseDown(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned int button) override;
|
void OnMouseUp(int x, int y, unsigned int button) override;
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override;
|
void OnMouseClick(int x, int y, unsigned int button) override;
|
||||||
void Draw(const ui::Point& screenPos) override;
|
void Draw(const ui::Point& screenPos) override;
|
||||||
|
@ -51,7 +51,7 @@ void AvatarButton::Draw(const Point& screenPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarButton::OnMouseUnclick(int x, int y, unsigned int button)
|
void AvatarButton::OnMouseClick(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
if(button != 1)
|
if(button != 1)
|
||||||
{
|
{
|
||||||
@ -70,18 +70,21 @@ void AvatarButton::OnContextMenuAction(int item)
|
|||||||
//Do nothing
|
//Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarButton::OnMouseClick(int x, int y, unsigned int button)
|
void AvatarButton::OnMouseDown(int x, int y, unsigned int button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
if(button == SDL_BUTTON_RIGHT)
|
if(button == SDL_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
if(menu)
|
if(menu)
|
||||||
menu->Show(GetScreenPos() + ui::Point(x, y));
|
menu->Show(GetContainerPos() + ui::Point(x, y));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isButtonDown = true;
|
isButtonDown = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarButton::OnMouseEnter(int x, int y)
|
void AvatarButton::OnMouseEnter(int x, int y)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ public:
|
|||||||
virtual ~AvatarButton() = default;
|
virtual ~AvatarButton() = default;
|
||||||
|
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override;
|
void OnMouseClick(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUnclick(int x, int y, unsigned int button) override;
|
void OnMouseDown(int x, int y, unsigned int button) override;
|
||||||
|
|
||||||
void OnMouseEnter(int x, int y) override;
|
void OnMouseEnter(int x, int y) override;
|
||||||
void OnMouseLeave(int x, int y) override;
|
void OnMouseLeave(int x, int y) override;
|
||||||
|
@ -86,7 +86,7 @@ void Button::Draw(const Point& screenPos)
|
|||||||
|
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
{
|
{
|
||||||
if (isButtonDown || (isTogglable && toggle))
|
if ((isButtonDown && MouseDownInside) || (isTogglable && toggle))
|
||||||
{
|
{
|
||||||
textColour = Appearance.TextActive;
|
textColour = Appearance.TextActive;
|
||||||
borderColour = Appearance.BorderActive;
|
borderColour = Appearance.BorderActive;
|
||||||
@ -140,7 +140,7 @@ void Button::Draw(const Point& screenPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::OnMouseUnclick(int x, int y, unsigned int button)
|
void Button::OnMouseClick(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
if(button == 1)
|
if(button == 1)
|
||||||
{
|
{
|
||||||
@ -171,7 +171,9 @@ void Button::OnMouseUp(int x, int y, unsigned int button)
|
|||||||
isAltButtonDown = false;
|
isAltButtonDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::OnMouseClick(int x, int y, unsigned int button)
|
void Button::OnMouseDown(int x, int y, unsigned int button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
if(!Enabled)
|
if(!Enabled)
|
||||||
return;
|
return;
|
||||||
@ -184,6 +186,7 @@ void Button::OnMouseClick(int x, int y, unsigned int button)
|
|||||||
isAltButtonDown = true;
|
isAltButtonDown = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Button::OnMouseEnter(int x, int y)
|
void Button::OnMouseEnter(int x, int y)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
virtual ~Button() = default;
|
virtual ~Button() = default;
|
||||||
|
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override;
|
void OnMouseClick(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUnclick(int x, int y, unsigned int button) override;
|
void OnMouseDown(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned int button) override;
|
void OnMouseUp(int x, int y, unsigned int button) override;
|
||||||
|
|
||||||
void OnMouseEnter(int x, int y) override;
|
void OnMouseEnter(int x, int y) override;
|
||||||
|
@ -124,17 +124,21 @@ void Component::SetParent(Panel* new_parent)
|
|||||||
this->_parent = new_parent;
|
this->_parent = new_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point Component::GetScreenPos()
|
Point Component::GetContainerPos()
|
||||||
{
|
{
|
||||||
Point newPos(0,0);
|
Point newPos(0,0);
|
||||||
if(GetParentWindow())
|
if(GetParentWindow())
|
||||||
newPos += GetParentWindow()->Position;
|
newPos += GetParentWindow()->Position;
|
||||||
if(GetParent())
|
if(GetParent())
|
||||||
newPos += GetParent()->Position + GetParent()->ViewportPosition;
|
newPos += GetParent()->Position + GetParent()->ViewportPosition;
|
||||||
newPos += Position;
|
|
||||||
return newPos;
|
return newPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point Component::GetScreenPos()
|
||||||
|
{
|
||||||
|
return GetContainerPos() + Position;
|
||||||
|
}
|
||||||
|
|
||||||
Graphics * Component::GetGraphics()
|
Graphics * Component::GetGraphics()
|
||||||
{
|
{
|
||||||
return parentstate_->GetGraphics();
|
return parentstate_->GetGraphics();
|
||||||
@ -185,11 +189,7 @@ void Component::OnMouseHover(int localx, int localy)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Component::OnMouseMoved(int localx, int localy, int dx, int dy)
|
void Component::OnMouseMoved(int localx, int localy)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Component::OnMouseMovedInside(int localx, int localy, int dx, int dy)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,10 +201,6 @@ void Component::OnMouseLeave(int localx, int localy)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Component::OnMouseUnclick(int localx, int localy, unsigned button)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Component::OnMouseUp(int x, int y, unsigned button)
|
void Component::OnMouseUp(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ namespace ui
|
|||||||
bool Enabled;
|
bool Enabled;
|
||||||
bool Visible;
|
bool Visible;
|
||||||
bool DoesTextInput;
|
bool DoesTextInput;
|
||||||
|
bool MouseInside;
|
||||||
|
bool MouseDownInside;
|
||||||
|
|
||||||
ui::Appearance Appearance;
|
ui::Appearance Appearance;
|
||||||
//virtual void SetAppearance(ui::Appearance);
|
//virtual void SetAppearance(ui::Appearance);
|
||||||
@ -51,6 +53,7 @@ namespace ui
|
|||||||
|
|
||||||
void Refresh();
|
void Refresh();
|
||||||
|
|
||||||
|
Point GetContainerPos();
|
||||||
Point GetScreenPos();
|
Point GetScreenPos();
|
||||||
|
|
||||||
/* See the parent of this component.
|
/* See the parent of this component.
|
||||||
@ -94,20 +97,8 @@ namespace ui
|
|||||||
// Params:
|
// Params:
|
||||||
// localx: Local mouse X position.
|
// localx: Local mouse X position.
|
||||||
// localy: Local mouse Y position.
|
// localy: Local mouse Y position.
|
||||||
// dx: Mouse X delta.
|
|
||||||
// dy: Mouse Y delta.
|
|
||||||
///
|
///
|
||||||
virtual void OnMouseMoved(int localx, int localy, int dx, int dy);
|
virtual void OnMouseMoved(int localx, int localy);
|
||||||
|
|
||||||
///
|
|
||||||
// Called: When the mouse moves.
|
|
||||||
// Params:
|
|
||||||
// localx: Local mouse X position.
|
|
||||||
// localy: Local mouse Y position.
|
|
||||||
// dx: Mouse X delta.
|
|
||||||
// dy: Mouse Y delta.
|
|
||||||
///
|
|
||||||
virtual void OnMouseMovedInside(int localx, int localy, int dx, int dy);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
// Called: When the mouse moves on top of the item.
|
// Called: When the mouse moves on top of the item.
|
||||||
@ -146,7 +137,7 @@ namespace ui
|
|||||||
virtual void OnMouseUp(int x, int y, unsigned button);
|
virtual void OnMouseUp(int x, int y, unsigned button);
|
||||||
|
|
||||||
///
|
///
|
||||||
// Called: When a mouse button is pressed on top of the item.
|
// Called: When a mouse button is pressed and then released on top of the item.
|
||||||
// Params:
|
// Params:
|
||||||
// x: X position of the mouse.
|
// x: X position of the mouse.
|
||||||
// y: Y position of the mouse.
|
// y: Y position of the mouse.
|
||||||
@ -154,15 +145,6 @@ namespace ui
|
|||||||
///
|
///
|
||||||
virtual void OnMouseClick(int localx, int localy, unsigned button);
|
virtual void OnMouseClick(int localx, int localy, unsigned button);
|
||||||
|
|
||||||
///
|
|
||||||
// Called: When a mouse button is released on top of the item.
|
|
||||||
// Params:
|
|
||||||
// x: X position of the mouse.
|
|
||||||
// y: Y position of the mouse.
|
|
||||||
// button: The button that is being released.
|
|
||||||
///
|
|
||||||
virtual void OnMouseUnclick(int localx, int localy, unsigned button);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
// Called: When the mouse wheel moves/changes.
|
// Called: When the mouse wheel moves/changes.
|
||||||
// Params:
|
// Params:
|
||||||
|
@ -133,7 +133,7 @@ void DirectionSelector::Draw(const ui::Point& screenPos)
|
|||||||
g->BlendEllipse(center + value.offset, { handleRadius, handleRadius }, borderColor);
|
g->BlendEllipse(center + value.offset, { handleRadius, handleRadius }, borderColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy)
|
void DirectionSelector::OnMouseMoved(int x, int y)
|
||||||
{
|
{
|
||||||
if (mouseDown)
|
if (mouseDown)
|
||||||
{
|
{
|
||||||
@ -142,11 +142,14 @@ void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy)
|
|||||||
CheckHovering(x, y);
|
CheckHovering(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionSelector::OnMouseClick(int x, int y, unsigned button)
|
void DirectionSelector::OnMouseDown(int x, int y, unsigned button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
mouseDown = true;
|
mouseDown = true;
|
||||||
SetPositionAbs({ x, y });
|
SetPositionAbs({ x - Position.X, y - Position.Y });
|
||||||
CheckHovering(x, y);
|
CheckHovering(x - Position.X, y - Position.Y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionSelector::OnMouseUp(int x, int y, unsigned button)
|
void DirectionSelector::OnMouseUp(int x, int y, unsigned button)
|
||||||
|
@ -78,8 +78,8 @@ public:
|
|||||||
void SetValues(float x, float y);
|
void SetValues(float x, float y);
|
||||||
|
|
||||||
void Draw(const ui::Point& screenPos) override;
|
void Draw(const ui::Point& screenPos) override;
|
||||||
void OnMouseMoved(int x, int y, int dx, int dy) override;
|
void OnMouseMoved(int x, int y) override;
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override;
|
void OnMouseDown(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned button) override;
|
void OnMouseUp(int x, int y, unsigned button) override;
|
||||||
inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
|
inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
|
||||||
inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
|
inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
|
||||||
|
@ -15,7 +15,8 @@ class DropDownWindow : public ui::Window
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
DropDownWindow(DropDown * dropDown):
|
DropDownWindow(DropDown * dropDown):
|
||||||
Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - dropDown->optionIndex * 16), ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
|
Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - (dropDown->optionIndex*16 < dropDown->GetScreenPos().Y ? dropDown->optionIndex*16 : 0)),
|
||||||
|
ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
|
||||||
dropDown(dropDown),
|
dropDown(dropDown),
|
||||||
appearance(dropDown->Appearance)
|
appearance(dropDown->Appearance)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,8 @@ void Engine::ShowWindow(Window * window)
|
|||||||
{
|
{
|
||||||
window->Position.Y = (g->Size().Y - window->Size.Y) / 2;
|
window->Position.Y = (g->Size().Y - window->Size.Y) / 2;
|
||||||
}
|
}
|
||||||
|
window->Size = window->Size.Min(g->Size());
|
||||||
|
window->Position = window->Position.Clamp(RectBetween<int>({0, 0}, g->Size()));
|
||||||
/*if(window->Position.Y > 0)
|
/*if(window->Position.Y > 0)
|
||||||
{
|
{
|
||||||
windowTargetPosition = window->Position;
|
windowTargetPosition = window->Position;
|
||||||
@ -268,14 +270,14 @@ void Engine::onTextEditing(String text, int start)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::onMouseClick(int x, int y, unsigned button)
|
void Engine::onMouseDown(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
mouseb_ |= button;
|
mouseb_ |= button;
|
||||||
if (state_ && !ignoreEvents)
|
if (state_ && !ignoreEvents)
|
||||||
state_->DoMouseDown(x, y, button);
|
state_->DoMouseDown(x, y, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::onMouseUnclick(int x, int y, unsigned button)
|
void Engine::onMouseUp(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
mouseb_ &= ~button;
|
mouseb_ &= ~button;
|
||||||
if (state_ && !ignoreEvents)
|
if (state_ && !ignoreEvents)
|
||||||
|
@ -30,8 +30,8 @@ namespace ui
|
|||||||
|
|
||||||
void initialMouse(int x, int y);
|
void initialMouse(int x, int y);
|
||||||
void onMouseMove(int x, int y);
|
void onMouseMove(int x, int y);
|
||||||
void onMouseClick(int x, int y, unsigned button);
|
void onMouseDown(int x, int y, unsigned button);
|
||||||
void onMouseUnclick(int x, int y, unsigned button);
|
void onMouseUp(int x, int y, unsigned button);
|
||||||
void onMouseWheel(int x, int y, int delta);
|
void onMouseWheel(int x, int y, int delta);
|
||||||
void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
|
@ -88,26 +88,29 @@ void Label::OnContextMenuAction(int item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Label::OnMouseClick(int x, int y, unsigned button)
|
void Label::OnMouseDown(int x, int y, unsigned button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
if(button == SDL_BUTTON_RIGHT)
|
if(button == SDL_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
if (menu)
|
if (menu)
|
||||||
{
|
{
|
||||||
menu->Show(GetScreenPos() + ui::Point(x, y));
|
menu->Show(GetContainerPos() + ui::Point(x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selecting = true;
|
selecting = true;
|
||||||
auto tp = textPosition - Vec2{ scrollX, 0 };
|
auto tp = textPosition - Vec2{ scrollX, 0 };
|
||||||
selectionIndex0 = textWrapper.Point2Index(x - tp.X, y - tp.Y);
|
selectionIndex0 = textWrapper.Point2Index(x - Position.X - tp.X, y - Position.Y - tp.Y);
|
||||||
selectionIndexL = selectionIndex0;
|
selectionIndexL = selectionIndex0;
|
||||||
selectionIndexH = selectionIndex0;
|
selectionIndexH = selectionIndex0;
|
||||||
|
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Label::copySelection()
|
void Label::copySelection()
|
||||||
{
|
{
|
||||||
@ -143,7 +146,7 @@ void Label::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Label::OnMouseMoved(int localx, int localy, int dx, int dy)
|
void Label::OnMouseMoved(int localx, int localy)
|
||||||
{
|
{
|
||||||
if (selecting)
|
if (selecting)
|
||||||
{
|
{
|
||||||
|
@ -58,9 +58,9 @@ namespace ui
|
|||||||
void SetTextColour(Colour textColour) { this->textColour = textColour; }
|
void SetTextColour(Colour textColour) { this->textColour = textColour; }
|
||||||
|
|
||||||
void OnContextMenuAction(int item) override;
|
void OnContextMenuAction(int item) override;
|
||||||
virtual void OnMouseClick(int x, int y, unsigned button) override;
|
virtual void OnMouseDown(int x, int y, unsigned button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned button) override;
|
void OnMouseUp(int x, int y, unsigned button) override;
|
||||||
void OnMouseMoved(int localx, int localy, int dx, int dy) override;
|
void OnMouseMoved(int localx, int localy) override;
|
||||||
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
||||||
void Draw(const Point& screenPos) override;
|
void Draw(const Point& screenPos) override;
|
||||||
void Tick(float dt) override;
|
void Tick(float dt) override;
|
||||||
|
@ -10,8 +10,7 @@ using namespace ui;
|
|||||||
Panel::Panel(Point position, Point size):
|
Panel::Panel(Point position, Point size):
|
||||||
Component(position, size),
|
Component(position, size),
|
||||||
InnerSize(size),
|
InnerSize(size),
|
||||||
ViewportPosition(0, 0),
|
ViewportPosition(0, 0)
|
||||||
mouseInside(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +26,8 @@ void Panel::AddChild(Component* c)
|
|||||||
{
|
{
|
||||||
c->SetParent(this);
|
c->SetParent(this);
|
||||||
c->SetParentWindow(this->GetParentWindow());
|
c->SetParentWindow(this->GetParentWindow());
|
||||||
|
c->MouseInside = false;
|
||||||
|
c->MouseDownInside = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Panel::GetChildCount()
|
int Panel::GetChildCount()
|
||||||
@ -108,8 +109,15 @@ void Panel::OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
|
|
||||||
void Panel::OnMouseClick(int localx, int localy, unsigned button)
|
void Panel::OnMouseClick(int localx, int localy, unsigned button)
|
||||||
{
|
{
|
||||||
bool childclicked = false;
|
XOnMouseClick(localx, localy, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::OnMouseDown(int x, int y, unsigned button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
|
{
|
||||||
|
auto localx = x - Position.X;
|
||||||
|
auto localy = y - Position.Y;
|
||||||
//check if clicked a child
|
//check if clicked a child
|
||||||
for(int i = children.size()-1; i >= 0 ; --i)
|
for(int i = children.size()-1; i >= 0 ; --i)
|
||||||
{
|
{
|
||||||
@ -122,29 +130,19 @@ void Panel::OnMouseClick(int localx, int localy, unsigned button)
|
|||||||
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
||||||
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
||||||
{
|
{
|
||||||
childclicked = true;
|
|
||||||
GetParentWindow()->FocusComponent(children[i]);
|
GetParentWindow()->FocusComponent(children[i]);
|
||||||
children[i]->OnMouseClick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
|
children[i]->MouseDownInside = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if a child wasn't clicked, send click to ourself
|
|
||||||
if(!childclicked)
|
|
||||||
{
|
|
||||||
XOnMouseClick(localx, localy, button);
|
|
||||||
GetParentWindow()->FocusComponent(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panel::OnMouseDown(int x, int y, unsigned button)
|
|
||||||
{
|
|
||||||
XOnMouseDown(x, y, button);
|
XOnMouseDown(x, y, button);
|
||||||
for (size_t i = 0; i < children.size(); ++i)
|
for (size_t i = 0; i < children.size(); ++i)
|
||||||
{
|
{
|
||||||
if(children[i]->Enabled)
|
if(children[i]->Enabled)
|
||||||
children[i]->OnMouseDown(x, y, button);
|
children[i]->OnMouseDown(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,12 +153,14 @@ void Panel::OnMouseHover(int localx, int localy)
|
|||||||
{
|
{
|
||||||
if (children[i]->Enabled)
|
if (children[i]->Enabled)
|
||||||
{
|
{
|
||||||
if( localx >= children[i]->Position.X &&
|
auto px = children[i]->Position.X + ViewportPosition.X;
|
||||||
localy >= children[i]->Position.Y &&
|
auto py = children[i]->Position.Y + ViewportPosition.Y;
|
||||||
localx < children[i]->Position.X + children[i]->Size.X &&
|
if( localx >= px &&
|
||||||
localy < children[i]->Position.Y + children[i]->Size.Y )
|
localy >= py &&
|
||||||
|
localx < px + children[i]->Size.X &&
|
||||||
|
localy < py + children[i]->Size.Y )
|
||||||
{
|
{
|
||||||
children[i]->OnMouseHover(localx - children[i]->Position.X, localy - children[i]->Position.Y);
|
children[i]->OnMouseHover(localx - px, localy - py);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,25 +170,26 @@ void Panel::OnMouseHover(int localx, int localy)
|
|||||||
XOnMouseHover(localx, localy);
|
XOnMouseHover(localx, localy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::OnMouseMoved(int localx, int localy, int dx, int dy)
|
void Panel::OnMouseMoved(int localx, int localy)
|
||||||
{
|
{
|
||||||
XOnMouseMoved(localx, localy, dx, dy);
|
PropagateMouseMove();
|
||||||
|
XOnMouseMoved(localx, localy);
|
||||||
for (size_t i = 0; i < children.size(); ++i)
|
for (size_t i = 0; i < children.size(); ++i)
|
||||||
{
|
{
|
||||||
if(children[i]->Enabled)
|
if(children[i]->Enabled)
|
||||||
children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
|
children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::OnMouseMovedInside(int localx, int localy, int dx, int dy)
|
void Panel::PropagateMouseMove()
|
||||||
{
|
{
|
||||||
mouseInside = true;
|
auto localx = ui::Engine::Ref().GetMouseX() - GetScreenPos().X;
|
||||||
|
auto localy = ui::Engine::Ref().GetMouseY() - GetScreenPos().Y;
|
||||||
for (size_t i = 0; i < children.size(); ++i)
|
for (size_t i = 0; i < children.size(); ++i)
|
||||||
{
|
{
|
||||||
if (children[i]->Enabled)
|
if (children[i]->Enabled)
|
||||||
{
|
{
|
||||||
Point local (localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y)
|
Point local (localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y);
|
||||||
, prevlocal (local.X - dx, local.Y - dy);
|
|
||||||
|
|
||||||
// mouse currently inside?
|
// mouse currently inside?
|
||||||
if( local.X >= 0 &&
|
if( local.X >= 0 &&
|
||||||
@ -196,14 +197,12 @@ void Panel::OnMouseMovedInside(int localx, int localy, int dx, int dy)
|
|||||||
local.X < children[i]->Size.X &&
|
local.X < children[i]->Size.X &&
|
||||||
local.Y < children[i]->Size.Y )
|
local.Y < children[i]->Size.Y )
|
||||||
{
|
{
|
||||||
children[i]->OnMouseMovedInside(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
|
children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y);
|
||||||
|
|
||||||
// was the mouse outside?
|
// was the mouse outside?
|
||||||
if(!(prevlocal.X >= 0 &&
|
if (!children[i]->MouseInside)
|
||||||
prevlocal.Y >= 0 &&
|
|
||||||
prevlocal.X < children[i]->Size.X &&
|
|
||||||
prevlocal.Y < children[i]->Size.Y ) )
|
|
||||||
{
|
{
|
||||||
|
children[i]->MouseInside = true;
|
||||||
children[i]->OnMouseEnter(local.X, local.Y);
|
children[i]->OnMouseEnter(local.X, local.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,71 +210,59 @@ void Panel::OnMouseMovedInside(int localx, int localy, int dx, int dy)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// was the mouse inside?
|
// was the mouse inside?
|
||||||
if( prevlocal.X >= 0 &&
|
if (children[i]->MouseInside)
|
||||||
prevlocal.Y >= 0 &&
|
|
||||||
prevlocal.X < children[i]->Size.X &&
|
|
||||||
prevlocal.Y < children[i]->Size.Y )
|
|
||||||
{
|
{
|
||||||
|
children[i]->MouseInside = false;
|
||||||
children[i]->OnMouseLeave(local.X, local.Y);
|
children[i]->OnMouseLeave(local.X, local.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always allow hover on parent (?)
|
|
||||||
XOnMouseMovedInside(localx, localy, dx, dy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::OnMouseEnter(int localx, int localy)
|
void Panel::OnMouseEnter(int localx, int localy)
|
||||||
{
|
{
|
||||||
mouseInside = true;
|
|
||||||
XOnMouseEnter(localx, localy);
|
XOnMouseEnter(localx, localy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::OnMouseLeave(int localx, int localy)
|
void Panel::OnMouseLeave(int localx, int localy)
|
||||||
{
|
{
|
||||||
mouseInside = false;
|
|
||||||
XOnMouseLeave(localx, localy);
|
XOnMouseLeave(localx, localy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::OnMouseUnclick(int localx, int localy, unsigned button)
|
|
||||||
{
|
|
||||||
bool childunclicked = false;
|
|
||||||
|
|
||||||
//check if clicked a child
|
|
||||||
for(int i = children.size()-1; i >= 0 ; --i)
|
|
||||||
{
|
|
||||||
//child must be unlocked
|
|
||||||
if(children[i]->Enabled)
|
|
||||||
{
|
|
||||||
//is mouse inside?
|
|
||||||
if( localx >= children[i]->Position.X + ViewportPosition.X &&
|
|
||||||
localy >= children[i]->Position.Y + ViewportPosition.Y &&
|
|
||||||
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
|
||||||
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
|
||||||
{
|
|
||||||
childunclicked = true;
|
|
||||||
children[i]->OnMouseUnclick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if a child wasn't clicked, send click to ourself
|
|
||||||
if (!childunclicked)
|
|
||||||
{
|
|
||||||
XOnMouseUnclick(localx, localy, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panel::OnMouseUp(int x, int y, unsigned button)
|
void Panel::OnMouseUp(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
|
auto localx = x - Position.X;
|
||||||
|
auto localy = y - Position.Y;
|
||||||
|
//check if clicked a child
|
||||||
|
for(int i = children.size()-1; i >= 0 ; --i)
|
||||||
|
{
|
||||||
|
//child must be enabled
|
||||||
|
if(children[i]->Enabled)
|
||||||
|
{
|
||||||
|
//is mouse inside?
|
||||||
|
if( children[i]->MouseDownInside &&
|
||||||
|
localx >= children[i]->Position.X + ViewportPosition.X &&
|
||||||
|
localy >= children[i]->Position.Y + ViewportPosition.Y &&
|
||||||
|
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
||||||
|
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
||||||
|
{
|
||||||
|
children[i]->OnMouseClick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto *child : children)
|
||||||
|
{
|
||||||
|
child->MouseDownInside = false;
|
||||||
|
}
|
||||||
|
|
||||||
XOnMouseUp(x, y, button);
|
XOnMouseUp(x, y, button);
|
||||||
for (size_t i = 0; i < children.size(); ++i)
|
for (size_t i = 0; i < children.size(); ++i)
|
||||||
{
|
{
|
||||||
if (children[i]->Enabled)
|
if (children[i]->Enabled)
|
||||||
children[i]->OnMouseUp(x, y, button);
|
children[i]->OnMouseUp(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,11 +329,7 @@ void Panel::XOnMouseHover(int localx, int localy)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::XOnMouseMoved(int localx, int localy, int dx, int dy)
|
void Panel::XOnMouseMoved(int localx, int localy)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panel::XOnMouseMovedInside(int localx, int localy, int dx, int dy)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,10 +341,6 @@ void Panel::XOnMouseLeave(int localx, int localy)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::XOnMouseUnclick(int localx, int localy, unsigned button)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panel::XOnMouseUp(int x, int y, unsigned button)
|
void Panel::XOnMouseUp(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -51,14 +51,12 @@ namespace ui
|
|||||||
void Draw(const Point& screenPos) override;
|
void Draw(const Point& screenPos) override;
|
||||||
|
|
||||||
void OnMouseHover(int localx, int localy) override;
|
void OnMouseHover(int localx, int localy) override;
|
||||||
void OnMouseMoved(int localx, int localy, int dx, int dy) override;
|
void OnMouseMoved(int localx, int localy) override;
|
||||||
void OnMouseMovedInside(int localx, int localy, int dx, int dy) override;
|
|
||||||
void OnMouseEnter(int localx, int localy) override;
|
void OnMouseEnter(int localx, int localy) override;
|
||||||
void OnMouseLeave(int localx, int localy) override;
|
void OnMouseLeave(int localx, int localy) override;
|
||||||
void OnMouseDown(int x, int y, unsigned button) override;
|
void OnMouseDown(int x, int y, unsigned button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned button) override;
|
void OnMouseUp(int x, int y, unsigned button) override;
|
||||||
void OnMouseClick(int localx, int localy, unsigned button) override;
|
void OnMouseClick(int localx, int localy, unsigned button) override;
|
||||||
void OnMouseUnclick(int localx, int localy, unsigned button) override;
|
|
||||||
void OnMouseWheel(int localx, int localy, int d) override;
|
void OnMouseWheel(int localx, int localy, int d) override;
|
||||||
void OnMouseWheelInside(int localx, int localy, int d) override;
|
void OnMouseWheelInside(int localx, int localy, int d) override;
|
||||||
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
||||||
@ -67,7 +65,6 @@ namespace ui
|
|||||||
protected:
|
protected:
|
||||||
// child components
|
// child components
|
||||||
std::vector<ui::Component*> children;
|
std::vector<ui::Component*> children;
|
||||||
bool mouseInside;
|
|
||||||
|
|
||||||
// Overridable. Called by XComponent::Tick()
|
// Overridable. Called by XComponent::Tick()
|
||||||
virtual void XTick(float dt);
|
virtual void XTick(float dt);
|
||||||
@ -80,10 +77,7 @@ namespace ui
|
|||||||
virtual void XOnMouseHover(int localx, int localy);
|
virtual void XOnMouseHover(int localx, int localy);
|
||||||
|
|
||||||
// Overridable. Called by XComponent::OnMouseMoved()
|
// Overridable. Called by XComponent::OnMouseMoved()
|
||||||
virtual void XOnMouseMoved(int localx, int localy, int dx, int dy);
|
virtual void XOnMouseMoved(int localx, int localy);
|
||||||
|
|
||||||
// Overridable. Called by XComponent::OnMouseMovedInside()
|
|
||||||
virtual void XOnMouseMovedInside(int localx, int localy, int dx, int dy);
|
|
||||||
|
|
||||||
// Overridable. Called by XComponent::OnMouseEnter()
|
// Overridable. Called by XComponent::OnMouseEnter()
|
||||||
virtual void XOnMouseEnter(int localx, int localy);
|
virtual void XOnMouseEnter(int localx, int localy);
|
||||||
@ -100,9 +94,6 @@ namespace ui
|
|||||||
// Overridable. Called by XComponent::OnMouseClick()
|
// Overridable. Called by XComponent::OnMouseClick()
|
||||||
virtual void XOnMouseClick(int localx, int localy, unsigned button);
|
virtual void XOnMouseClick(int localx, int localy, unsigned button);
|
||||||
|
|
||||||
// Overridable. Called by XComponent::OnMouseUnclick()
|
|
||||||
virtual void XOnMouseUnclick(int localx, int localy, unsigned button);
|
|
||||||
|
|
||||||
// Overridable. Called by XComponent::OnMouseWheel()
|
// Overridable. Called by XComponent::OnMouseWheel()
|
||||||
virtual void XOnMouseWheel(int localx, int localy, int d);
|
virtual void XOnMouseWheel(int localx, int localy, int d);
|
||||||
|
|
||||||
@ -114,6 +105,8 @@ namespace ui
|
|||||||
|
|
||||||
// Overridable. Called by XComponent::OnKeyRelease()
|
// Overridable. Called by XComponent::OnKeyRelease()
|
||||||
virtual void XOnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
virtual void XOnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
|
|
||||||
|
void PropagateMouseMove();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,11 @@ void RichLabel::SetText(String newText)
|
|||||||
regions = newRegions;
|
regions = newRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichLabel::OnMouseClick(int x, int y, unsigned button)
|
void RichLabel::OnMouseDown(int x, int y, unsigned button)
|
||||||
{
|
{
|
||||||
int cursorPosition = displayTextWrapper.Point2Index(x - textPosition.X, y - textPosition.Y).raw_index;
|
if (MouseDownInside)
|
||||||
|
{
|
||||||
|
int cursorPosition = displayTextWrapper.Point2Index(x - Position.X - textPosition.X, y - Position.Y - textPosition.Y).raw_index;
|
||||||
for (auto const ®ion : regions)
|
for (auto const ®ion : regions)
|
||||||
{
|
{
|
||||||
if (region.begin <= cursorPosition && region.end > cursorPosition)
|
if (region.begin <= cursorPosition && region.end > cursorPosition)
|
||||||
@ -78,5 +80,6 @@ void RichLabel::OnMouseClick(int x, int y, unsigned button)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Label::OnMouseClick(x, y, button);
|
}
|
||||||
|
Label::OnMouseDown(x, y, button);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,6 @@ namespace ui
|
|||||||
RichLabel(Point position, Point size, String text);
|
RichLabel(Point position, Point size, String text);
|
||||||
|
|
||||||
void SetText(String newText) override;
|
void SetText(String newText) override;
|
||||||
void OnMouseClick(int x, int y, unsigned button) override;
|
void OnMouseDown(int x, int y, unsigned button) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ void SaveButton::Draw(const Point& screenPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveButton::OnMouseUnclick(int x, int y, unsigned int button)
|
void SaveButton::OnMouseClick(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
if(button != 1)
|
if(button != 1)
|
||||||
{
|
{
|
||||||
@ -333,12 +333,14 @@ void SaveButton::OnContextMenuAction(int item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveButton::OnMouseClick(int x, int y, unsigned int button)
|
void SaveButton::OnMouseDown(int x, int y, unsigned int button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
if(button == SDL_BUTTON_RIGHT)
|
if(button == SDL_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
if(menu)
|
if(menu)
|
||||||
menu->Show(GetScreenPos() + ui::Point(x, y));
|
menu->Show(GetContainerPos() + ui::Point(x, y));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -351,18 +353,20 @@ void SaveButton::OnMouseClick(int x, int y, unsigned int button)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SaveButton::OnMouseMovedInside(int x, int y, int dx, int dy)
|
void SaveButton::OnMouseMoved(int x, int y)
|
||||||
|
{
|
||||||
|
isMouseInsideAuthor = false;
|
||||||
|
isMouseInsideHistory = false;
|
||||||
|
if (MouseInside)
|
||||||
{
|
{
|
||||||
if (y > Size.Y-11)
|
if (y > Size.Y-11)
|
||||||
isMouseInsideAuthor = true;
|
isMouseInsideAuthor = true;
|
||||||
else
|
|
||||||
isMouseInsideAuthor = false;
|
|
||||||
|
|
||||||
if(showVotes && y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9)
|
if (y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9)
|
||||||
isMouseInsideHistory = true;
|
isMouseInsideHistory = true;
|
||||||
else
|
}
|
||||||
isMouseInsideHistory = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveButton::OnMouseEnter(int x, int y)
|
void SaveButton::OnMouseEnter(int x, int y)
|
||||||
|
@ -48,12 +48,12 @@ public:
|
|||||||
virtual ~SaveButton();
|
virtual ~SaveButton();
|
||||||
|
|
||||||
void OnMouseClick(int x, int y, unsigned int button) override;
|
void OnMouseClick(int x, int y, unsigned int button) override;
|
||||||
void OnMouseUnclick(int x, int y, unsigned int button) override;
|
void OnMouseDown(int x, int y, unsigned int button) override;
|
||||||
|
|
||||||
void OnMouseEnter(int x, int y) override;
|
void OnMouseEnter(int x, int y) override;
|
||||||
void OnMouseLeave(int x, int y) override;
|
void OnMouseLeave(int x, int y) override;
|
||||||
|
|
||||||
void OnMouseMovedInside(int x, int y, int dx, int dy) override;
|
void OnMouseMoved(int x, int y) override;
|
||||||
|
|
||||||
void AddContextMenu(int menuType);
|
void AddContextMenu(int menuType);
|
||||||
void OnContextMenuAction(int item) override;
|
void OnContextMenuAction(int item) override;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "ScrollPanel.h"
|
#include "ScrollPanel.h"
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
|
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
|
#include "Misc.h"
|
||||||
|
#include "PowderToySDL.h"
|
||||||
|
#include "Window.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
@ -70,28 +71,56 @@ void ScrollPanel::Draw(const Point& screenPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollPanel::XOnMouseClick(int x, int y, unsigned int button)
|
void ScrollPanel::XOnMouseDown(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
|
{
|
||||||
|
CancelPanning();
|
||||||
if (isMouseInsideScrollbar)
|
if (isMouseInsideScrollbar)
|
||||||
{
|
{
|
||||||
scrollbarSelected = true;
|
scrollbarSelected = true;
|
||||||
scrollbarInitialYOffset = int(offsetY);
|
scrollbarInitialYOffset = int(offsetY);
|
||||||
}
|
}
|
||||||
scrollbarInitialYClick = y;
|
initialOffsetY = offsetY;
|
||||||
|
scrollbarInitialYClick = y - Position.Y;
|
||||||
scrollbarClickLocation = 100;
|
scrollbarClickLocation = 100;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollPanel::CancelPanning()
|
||||||
|
{
|
||||||
|
panning = false;
|
||||||
|
panHistory = {};
|
||||||
|
yScrollVel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button)
|
void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button)
|
||||||
{
|
{
|
||||||
scrollbarSelected = false;
|
scrollbarSelected = false;
|
||||||
|
auto oldPanHistory = panHistory;
|
||||||
|
CancelPanning();
|
||||||
|
{
|
||||||
|
auto it = oldPanHistory.end();
|
||||||
|
while (it != oldPanHistory.begin() && *(it - 1))
|
||||||
|
{
|
||||||
|
--it;
|
||||||
|
}
|
||||||
|
if (it < oldPanHistory.end())
|
||||||
|
{
|
||||||
|
auto offsetYDiff = oldPanHistory.back()->offsetY - (*it)->offsetY;
|
||||||
|
auto tickDiff = oldPanHistory.back()->ticks - (*it)->ticks;
|
||||||
|
yScrollVel += offsetYDiff / tickDiff * (1000.f / Engine::Ref().GetFps());
|
||||||
|
}
|
||||||
|
}
|
||||||
isMouseInsideScrollbarArea = false;
|
isMouseInsideScrollbarArea = false;
|
||||||
scrollbarClickLocation = 0;
|
scrollbarClickLocation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollPanel::XOnMouseMoved(int x, int y, int dx, int dy)
|
void ScrollPanel::XOnMouseMoved(int x, int y)
|
||||||
{
|
{
|
||||||
if(maxOffset.Y>0 && InnerSize.Y>0)
|
if(maxOffset.Y>0 && InnerSize.Y>0)
|
||||||
{
|
{
|
||||||
|
auto oldViewportPositionY = ViewportPosition.Y;
|
||||||
float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y));
|
float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y));
|
||||||
float scrollPos = 0;
|
float scrollPos = 0;
|
||||||
if (-ViewportPosition.Y>0)
|
if (-ViewportPosition.Y>0)
|
||||||
@ -113,6 +142,19 @@ void ScrollPanel::XOnMouseMoved(int x, int y, int dx, int dy)
|
|||||||
offsetY = float(scrollbarInitialYOffset);
|
offsetY = float(scrollbarInitialYOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (MouseDownInside)
|
||||||
|
{
|
||||||
|
Vec2<int> mouseAt{ x, y };
|
||||||
|
if (Engine::Ref().TouchUI && iabs(scrollbarInitialYClick - mouseAt.Y) > PanOffsetThreshold)
|
||||||
|
{
|
||||||
|
panning = true;
|
||||||
|
for (auto *child : children)
|
||||||
|
{
|
||||||
|
child->MouseDownInside = false;
|
||||||
|
}
|
||||||
|
GetParentWindow()->FocusComponent(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (x > (Size.X-scrollBarWidth) && x < (Size.X-scrollBarWidth)+scrollBarWidth)
|
if (x > (Size.X-scrollBarWidth) && x < (Size.X-scrollBarWidth)+scrollBarWidth)
|
||||||
{
|
{
|
||||||
@ -122,11 +164,31 @@ void ScrollPanel::XOnMouseMoved(int x, int y, int dx, int dy)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
isMouseInsideScrollbar = false;
|
isMouseInsideScrollbar = false;
|
||||||
|
|
||||||
|
if (oldViewportPositionY != ViewportPosition.Y)
|
||||||
|
{
|
||||||
|
PropagateMouseMove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollPanel::XTick(float dt)
|
void ScrollPanel::XTick(float dt)
|
||||||
{
|
{
|
||||||
|
auto oldViewportPositionY = ViewportPosition.Y;
|
||||||
|
|
||||||
|
if (panning)
|
||||||
|
{
|
||||||
|
auto scrollY = initialOffsetY + scrollbarInitialYClick - (Engine::Ref().GetMouseY() - GetScreenPos().Y);
|
||||||
|
ViewportPosition.Y = -scrollY;
|
||||||
|
offsetY = float(scrollY);
|
||||||
|
PanPoint p{ offsetY, GetTicks() };
|
||||||
|
if (!(panHistory.back() && panHistory.back()->ticks == p.ticks))
|
||||||
|
{
|
||||||
|
std::copy(panHistory.begin() + 1, panHistory.end(), panHistory.begin());
|
||||||
|
panHistory.back() = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (xScrollVel > 7.0f) xScrollVel = 7.0f;
|
if (xScrollVel > 7.0f) xScrollVel = 7.0f;
|
||||||
if (xScrollVel < -7.0f) xScrollVel = -7.0f;
|
if (xScrollVel < -7.0f) xScrollVel = -7.0f;
|
||||||
if (xScrollVel > -0.5f && xScrollVel < 0.5)
|
if (xScrollVel > -0.5f && xScrollVel < 0.5)
|
||||||
@ -183,9 +245,9 @@ void ScrollPanel::XTick(float dt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouseInside && scrollBarWidth < 6)
|
if (MouseInside && scrollBarWidth < 6)
|
||||||
scrollBarWidth++;
|
scrollBarWidth++;
|
||||||
else if (!mouseInside && scrollBarWidth > 0 && !scrollbarSelected)
|
else if (!MouseInside && scrollBarWidth > 0 && !scrollbarSelected)
|
||||||
scrollBarWidth--;
|
scrollBarWidth--;
|
||||||
|
|
||||||
if (isMouseInsideScrollbarArea && scrollbarClickLocation && !scrollbarSelected)
|
if (isMouseInsideScrollbarArea && scrollbarClickLocation && !scrollbarSelected)
|
||||||
@ -205,4 +267,9 @@ void ScrollPanel::XTick(float dt)
|
|||||||
offsetY += scrollbarClickLocation*scrollHeight/10;
|
offsetY += scrollbarClickLocation*scrollHeight/10;
|
||||||
ViewportPosition.Y -= int(scrollbarClickLocation*scrollHeight/10);
|
ViewportPosition.Y -= int(scrollbarClickLocation*scrollHeight/10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldViewportPositionY != ViewportPosition.Y)
|
||||||
|
{
|
||||||
|
PropagateMouseMove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Panel.h"
|
#include "Panel.h"
|
||||||
|
#include <optional>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
class ScrollPanel: public Panel
|
class ScrollPanel: public Panel
|
||||||
{
|
{
|
||||||
|
void CancelPanning();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int scrollBarWidth;
|
int scrollBarWidth;
|
||||||
Point maxOffset;
|
Point maxOffset;
|
||||||
@ -19,6 +22,16 @@ namespace ui
|
|||||||
int scrollbarInitialYOffset;
|
int scrollbarInitialYOffset;
|
||||||
int scrollbarInitialYClick;
|
int scrollbarInitialYClick;
|
||||||
int scrollbarClickLocation;
|
int scrollbarClickLocation;
|
||||||
|
int initialOffsetY;
|
||||||
|
bool panning = false;
|
||||||
|
static constexpr int PanOffsetThreshold = 10;
|
||||||
|
static constexpr int PanHistorySize = 5;
|
||||||
|
struct PanPoint
|
||||||
|
{
|
||||||
|
float offsetY;
|
||||||
|
unsigned int ticks;
|
||||||
|
};
|
||||||
|
std::array<std::optional<PanPoint>, PanHistorySize> panHistory;
|
||||||
public:
|
public:
|
||||||
ScrollPanel(Point position, Point size);
|
ScrollPanel(Point position, Point size);
|
||||||
|
|
||||||
@ -28,8 +41,8 @@ namespace ui
|
|||||||
void Draw(const Point& screenPos) override;
|
void Draw(const Point& screenPos) override;
|
||||||
void XTick(float dt) override;
|
void XTick(float dt) override;
|
||||||
void XOnMouseWheelInside(int localx, int localy, int d) override;
|
void XOnMouseWheelInside(int localx, int localy, int d) override;
|
||||||
void XOnMouseClick(int localx, int localy, unsigned int button) override;
|
void XOnMouseDown(int localx, int localy, unsigned int button) override;
|
||||||
void XOnMouseUp(int x, int y, unsigned int button) override;
|
void XOnMouseUp(int x, int y, unsigned int button) override;
|
||||||
void XOnMouseMoved(int localx, int localy, int dx, int dy) override;
|
void XOnMouseMoved(int localx, int localy) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ void Slider::updatePosition(int position)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slider::OnMouseMoved(int x, int y, int dx, int dy)
|
void Slider::OnMouseMoved(int x, int y)
|
||||||
{
|
{
|
||||||
if(isMouseDown)
|
if(isMouseDown)
|
||||||
{
|
{
|
||||||
@ -48,10 +48,13 @@ void Slider::OnMouseMoved(int x, int y, int dx, int dy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slider::OnMouseClick(int x, int y, unsigned button)
|
void Slider::OnMouseDown(int x, int y, unsigned button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
isMouseDown = true;
|
isMouseDown = true;
|
||||||
updatePosition(x);
|
updatePosition(x - Position.X);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slider::OnMouseUp(int x, int y, unsigned button)
|
void Slider::OnMouseUp(int x, int y, unsigned button)
|
||||||
|
@ -24,8 +24,8 @@ public:
|
|||||||
Slider(Point position, Point size, int steps);
|
Slider(Point position, Point size, int steps);
|
||||||
virtual ~Slider() = default;
|
virtual ~Slider() = default;
|
||||||
|
|
||||||
void OnMouseMoved(int x, int y, int dx, int dy) override;
|
void OnMouseMoved(int x, int y) override;
|
||||||
void OnMouseClick(int x, int y, unsigned button) override;
|
void OnMouseDown(int x, int y, unsigned button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned button) override;
|
void OnMouseUp(int x, int y, unsigned button) override;
|
||||||
void Draw(const Point& screenPos) override;
|
void Draw(const Point& screenPos) override;
|
||||||
void SetColour(Colour col1, Colour col2);
|
void SetColour(Colour col1, Colour col2);
|
||||||
|
@ -569,18 +569,21 @@ void Textbox::OnTextEditing(String text)
|
|||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::OnMouseClick(int x, int y, unsigned button)
|
void Textbox::OnMouseDown(int x, int y, unsigned button)
|
||||||
|
{
|
||||||
|
if (MouseDownInside)
|
||||||
{
|
{
|
||||||
if (button != SDL_BUTTON_RIGHT)
|
if (button != SDL_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
StopTextEditing();
|
StopTextEditing();
|
||||||
mouseDown = true;
|
mouseDown = true;
|
||||||
auto tp = textPosition - Vec2{ scrollX, 0 };
|
auto tp = textPosition - Vec2{ scrollX, 0 };
|
||||||
auto index = textWrapper.Point2Index(x-tp.X, y-tp.Y);
|
auto index = textWrapper.Point2Index(x-Position.X-tp.X, y-Position.Y-tp.Y);
|
||||||
cursor = index.raw_index;
|
cursor = index.raw_index;
|
||||||
resetCursorPosition();
|
resetCursorPosition();
|
||||||
}
|
}
|
||||||
Label::OnMouseClick(x, y, button);
|
}
|
||||||
|
Label::OnMouseDown(x, y, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::OnMouseUp(int x, int y, unsigned button)
|
void Textbox::OnMouseUp(int x, int y, unsigned button)
|
||||||
@ -589,7 +592,7 @@ void Textbox::OnMouseUp(int x, int y, unsigned button)
|
|||||||
Label::OnMouseUp(x, y, button);
|
Label::OnMouseUp(x, y, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
|
void Textbox::OnMouseMoved(int localx, int localy)
|
||||||
{
|
{
|
||||||
if(mouseDown)
|
if(mouseDown)
|
||||||
{
|
{
|
||||||
@ -598,7 +601,7 @@ void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
|
|||||||
cursor = index.raw_index;
|
cursor = index.raw_index;
|
||||||
resetCursorPosition();
|
resetCursorPosition();
|
||||||
}
|
}
|
||||||
Label::OnMouseMoved(localx, localy, dx, dy);
|
Label::OnMouseMoved(localx, localy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Textbox::OnDefocus()
|
void Textbox::OnDefocus()
|
||||||
|
@ -53,9 +53,9 @@ public:
|
|||||||
|
|
||||||
void Tick(float dt) override;
|
void Tick(float dt) override;
|
||||||
void OnContextMenuAction(int item) override;
|
void OnContextMenuAction(int item) override;
|
||||||
void OnMouseClick(int x, int y, unsigned button) override;
|
void OnMouseDown(int x, int y, unsigned button) override;
|
||||||
void OnMouseUp(int x, int y, unsigned button) override;
|
void OnMouseUp(int x, int y, unsigned button) override;
|
||||||
void OnMouseMoved(int localx, int localy, int dx, int dy) override;
|
void OnMouseMoved(int localx, int localy) override;
|
||||||
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
||||||
void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
|
||||||
void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
|
||||||
|
@ -43,12 +43,17 @@ void Window::AddComponent(Component* c)
|
|||||||
if (c->GetParentWindow() == NULL)
|
if (c->GetParentWindow() == NULL)
|
||||||
{
|
{
|
||||||
c->SetParentWindow(this);
|
c->SetParentWindow(this);
|
||||||
|
c->MouseInside = false;
|
||||||
|
c->MouseDownInside = false;
|
||||||
Components.push_back(c);
|
Components.push_back(c);
|
||||||
|
|
||||||
if (Engine::Ref().GetMouseX() > Position.X + c->Position.X && Engine::Ref().GetMouseX() < Position.X + c->Position.X + c->Size.X &&
|
if (Engine::Ref().GetMouseX() > Position.X + c->Position.X && Engine::Ref().GetMouseX() < Position.X + c->Position.X + c->Size.X &&
|
||||||
Engine::Ref().GetMouseY() > Position.Y + c->Position.Y && Engine::Ref().GetMouseY() < Position.Y + c->Position.Y + c->Size.Y)
|
Engine::Ref().GetMouseY() > Position.Y + c->Position.Y && Engine::Ref().GetMouseY() < Position.Y + c->Position.Y + c->Size.Y)
|
||||||
|
{
|
||||||
|
c->MouseInside = true;
|
||||||
c->OnMouseEnter(Engine::Ref().GetMouseX() - (Position.X + c->Position.X), Engine::Ref().GetMouseY() - (Position.Y + c->Position.Y));
|
c->OnMouseEnter(Engine::Ref().GetMouseX() - (Position.X + c->Position.X), Engine::Ref().GetMouseY() - (Position.Y + c->Position.Y));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Component already in a window
|
//Component already in a window
|
||||||
@ -440,7 +445,7 @@ void Window::DoMouseDown(int x_, int y_, unsigned button)
|
|||||||
FocusComponent(Components[i]);
|
FocusComponent(Components[i]);
|
||||||
if (!DEBUG || !debugMode)
|
if (!DEBUG || !debugMode)
|
||||||
{
|
{
|
||||||
Components[i]->OnMouseClick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
|
Components[i]->MouseDownInside = true;
|
||||||
}
|
}
|
||||||
clickState = true;
|
clickState = true;
|
||||||
break;
|
break;
|
||||||
@ -485,21 +490,17 @@ void Window::DoMouseMove(int x_, int y_, int dx, int dy)
|
|||||||
Point local(x - Components[i]->Position.X, y - Components[i]->Position.Y);
|
Point local(x - Components[i]->Position.X, y - Components[i]->Position.Y);
|
||||||
Point a(local.X - dx, local.Y - dy);
|
Point a(local.X - dx, local.Y - dy);
|
||||||
|
|
||||||
Components[i]->OnMouseMoved(local.X, local.Y, dx, dy);
|
Components[i]->OnMouseMoved(local.X, local.Y);
|
||||||
|
|
||||||
if (local.X >= 0 &&
|
if (local.X >= 0 &&
|
||||||
local.Y >= 0 &&
|
local.Y >= 0 &&
|
||||||
local.X < Components[i]->Size.X &&
|
local.X < Components[i]->Size.X &&
|
||||||
local.Y < Components[i]->Size.Y && !halt)
|
local.Y < Components[i]->Size.Y && !halt)
|
||||||
{
|
{
|
||||||
Components[i]->OnMouseMovedInside(local.X, local.Y, dx, dy);
|
|
||||||
|
|
||||||
// entering?
|
// entering?
|
||||||
if (!(a.X >= 0 &&
|
if (!Components[i]->MouseInside)
|
||||||
a.Y >= 0 &&
|
|
||||||
a.X < Components[i]->Size.X &&
|
|
||||||
a.Y < Components[i]->Size.Y ))
|
|
||||||
{
|
{
|
||||||
|
Components[i]->MouseInside = true;
|
||||||
Components[i]->OnMouseEnter(local.X, local.Y);
|
Components[i]->OnMouseEnter(local.X, local.Y);
|
||||||
}
|
}
|
||||||
if (Components[i]->Enabled)
|
if (Components[i]->Enabled)
|
||||||
@ -508,11 +509,9 @@ void Window::DoMouseMove(int x_, int y_, int dx, int dy)
|
|||||||
else if (!halt)
|
else if (!halt)
|
||||||
{
|
{
|
||||||
// leaving?
|
// leaving?
|
||||||
if (a.X >= 0 &&
|
if (Components[i]->MouseInside)
|
||||||
a.Y >= 0 &&
|
|
||||||
a.X < Components[i]->Size.X &&
|
|
||||||
a.Y < Components[i]->Size.Y )
|
|
||||||
{
|
{
|
||||||
|
Components[i]->MouseInside = false;
|
||||||
Components[i]->OnMouseLeave(local.X, local.Y);
|
Components[i]->OnMouseLeave(local.X, local.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,13 +536,17 @@ void Window::DoMouseUp(int x_, int y_, unsigned button)
|
|||||||
{
|
{
|
||||||
if (Components[i]->Enabled && Components[i]->Visible)
|
if (Components[i]->Enabled && Components[i]->Visible)
|
||||||
{
|
{
|
||||||
if (x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
|
if (Components[i]->MouseDownInside && x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
|
||||||
{
|
{
|
||||||
Components[i]->OnMouseUnclick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
|
Components[i]->OnMouseClick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto *component : Components)
|
||||||
|
{
|
||||||
|
component->MouseDownInside = false;
|
||||||
|
}
|
||||||
|
|
||||||
//on mouse up
|
//on mouse up
|
||||||
for (int i = Components.size() - 1; i >= 0 && !halt; --i)
|
for (int i = Components.size() - 1; i >= 0 && !halt; --i)
|
||||||
|
@ -59,6 +59,8 @@ void LocalBrowserModel::OpenSave(int index)
|
|||||||
{
|
{
|
||||||
stamp = std::move(savesList[index]);
|
stamp = std::move(savesList[index]);
|
||||||
savesList.clear();
|
savesList.clear();
|
||||||
|
notifyPageChanged();
|
||||||
|
notifySavesListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocalBrowserModel::GetMoveToFront()
|
bool LocalBrowserModel::GetMoveToFront()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "LoginModel.h"
|
#include "LoginModel.h"
|
||||||
#include "LoginView.h"
|
#include "LoginView.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "client/Client.h"
|
#include "client/Client.h"
|
||||||
#include "client/http/LoginRequest.h"
|
#include "client/http/LoginRequest.h"
|
||||||
#include "client/http/LogoutRequest.h"
|
#include "client/http/LogoutRequest.h"
|
||||||
@ -8,7 +9,7 @@ void LoginModel::Login(ByteString username, ByteString password)
|
|||||||
{
|
{
|
||||||
if (username.Contains("@"))
|
if (username.Contains("@"))
|
||||||
{
|
{
|
||||||
statusText = "Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at https://powdertoy.co.uk/Register.html";
|
statusText = String::Build("Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at https://", SERVER, "/Register.html");
|
||||||
loginStatus = loginIdle;
|
loginStatus = loginIdle;
|
||||||
notifyStatusChanged();
|
notifyStatusChanged();
|
||||||
return;
|
return;
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
#include "OptionsController.h"
|
#include "OptionsController.h"
|
||||||
#include "OptionsModel.h"
|
#include "OptionsModel.h"
|
||||||
|
#include "common/clipboard/Clipboard.h"
|
||||||
#include "common/platform/Platform.h"
|
#include "common/platform/Platform.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "graphics/Renderer.h"
|
#include "graphics/Renderer.h"
|
||||||
#include "gui/Style.h"
|
#include "gui/Style.h"
|
||||||
#include "simulation/ElementDefs.h"
|
#include "simulation/ElementDefs.h"
|
||||||
|
#include "simulation/SimulationData.h"
|
||||||
#include "client/Client.h"
|
#include "client/Client.h"
|
||||||
#include "gui/dialogues/ConfirmPrompt.h"
|
#include "gui/dialogues/ConfirmPrompt.h"
|
||||||
#include "gui/dialogues/InformationMessage.h"
|
#include "gui/dialogues/InformationMessage.h"
|
||||||
@ -59,22 +61,28 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
AddComponent(scrollPanel);
|
AddComponent(scrollPanel);
|
||||||
|
|
||||||
int currentY = 8;
|
int currentY = 8;
|
||||||
auto addCheckbox = [this, ¤tY, &autoWidth](int indent, String text, String info, std::function<void ()> action) {
|
auto addLabel = [this, ¤tY, &autoWidth](int indent, String text) {
|
||||||
auto *checkbox = new ui::Checkbox(ui::Point(8 + indent * 15, currentY), ui::Point(1, 16), text, "");
|
auto *label = new ui::Label(ui::Point(22 + indent * 15, currentY), ui::Point(1, 16), "");
|
||||||
autoWidth(checkbox, 0);
|
|
||||||
checkbox->SetActionCallback({ action });
|
|
||||||
scrollPanel->AddChild(checkbox);
|
|
||||||
currentY += 14;
|
|
||||||
if (info.size())
|
|
||||||
{
|
|
||||||
auto *label = new ui::Label(ui::Point(22 + indent * 15, currentY), ui::Point(1, 16), "\bg" + info);
|
|
||||||
autoWidth(label, 0);
|
autoWidth(label, 0);
|
||||||
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
|
label->SetMultiline(true);
|
||||||
|
label->SetText("\bg" + text); // stupid hack because autoWidth just changes Size.X and that doesn't update the text wrapper
|
||||||
|
label->AutoHeight();
|
||||||
scrollPanel->AddChild(label);
|
scrollPanel->AddChild(label);
|
||||||
|
currentY += label->Size.Y - 1;
|
||||||
|
};
|
||||||
|
auto addCheckbox = [this, ¤tY, &autoWidth, &addLabel](int indent, String text, String info, std::function<void ()> action) {
|
||||||
|
auto *checkbox = new ui::Checkbox(ui::Point(8 + indent * 15, currentY), ui::Point(1, 16), text, "");
|
||||||
|
autoWidth(checkbox, 0);
|
||||||
|
checkbox->SetActionCallback({ action });
|
||||||
currentY += 14;
|
currentY += 14;
|
||||||
|
if (info.size())
|
||||||
|
{
|
||||||
|
addLabel(indent, info);
|
||||||
}
|
}
|
||||||
currentY += 4;
|
currentY += 4;
|
||||||
|
scrollPanel->AddChild(checkbox);
|
||||||
return checkbox;
|
return checkbox;
|
||||||
};
|
};
|
||||||
auto addDropDown = [this, ¤tY, &autoWidth](String info, std::vector<std::pair<String, int>> options, std::function<void ()> action) {
|
auto addDropDown = [this, ¤tY, &autoWidth](String info, std::vector<std::pair<String, int>> options, std::function<void ()> action) {
|
||||||
@ -113,11 +121,11 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
c->SetWaterEqualisation(waterEqualisation->GetChecked());
|
c->SetWaterEqualisation(waterEqualisation->GetChecked());
|
||||||
});
|
});
|
||||||
airMode = addDropDown("Air simulation mode", {
|
airMode = addDropDown("Air simulation mode", {
|
||||||
{ "On", 0 },
|
{ "On", AIR_ON },
|
||||||
{ "Pressure off", 1 },
|
{ "Pressure off", AIR_PRESSUREOFF },
|
||||||
{ "Velocity off", 2 },
|
{ "Velocity off", AIR_VELOCITYOFF },
|
||||||
{ "Off", 3 },
|
{ "Off", AIR_OFF },
|
||||||
{ "No update", 4 },
|
{ "No update", AIR_NOUPDATE },
|
||||||
}, [this] {
|
}, [this] {
|
||||||
c->SetAirMode(airMode->GetOption().second);
|
c->SetAirMode(airMode->GetOption().second);
|
||||||
});
|
});
|
||||||
@ -129,10 +137,11 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
ambientAirTemp->SetDefocusCallback({ [this] {
|
ambientAirTemp->SetDefocusCallback({ [this] {
|
||||||
UpdateAirTemp(ambientAirTemp->GetText(), true);
|
UpdateAirTemp(ambientAirTemp->GetText(), true);
|
||||||
}});
|
}});
|
||||||
|
ambientAirTemp->SetLimit(9);
|
||||||
scrollPanel->AddChild(ambientAirTemp);
|
scrollPanel->AddChild(ambientAirTemp);
|
||||||
ambientAirTempPreview = new ui::Button(ui::Point(Size.X-31, currentY), ui::Point(16, 16), "", "Preview");
|
ambientAirTempPreview = new ui::Button(ui::Point(Size.X-31, currentY), ui::Point(16, 16), "", "Preview");
|
||||||
scrollPanel->AddChild(ambientAirTempPreview);
|
scrollPanel->AddChild(ambientAirTempPreview);
|
||||||
auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Ambient air temperature");
|
auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-105, 16), "Ambient air temperature");
|
||||||
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
scrollPanel->AddChild(label);
|
scrollPanel->AddChild(label);
|
||||||
@ -203,10 +212,10 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
gravityMode = addDropDown("Gravity simulation mode", {
|
gravityMode = addDropDown("Gravity simulation mode", {
|
||||||
{ "Vertical", 0 },
|
{ "Vertical", GRAV_VERTICAL },
|
||||||
{ "Off", 1 },
|
{ "Off", GRAV_OFF },
|
||||||
{ "Radial", 2 },
|
{ "Radial", GRAV_RADIAL },
|
||||||
{ "Custom", 3 },
|
{ "Custom", GRAV_CUSTOM },
|
||||||
}, [this] {
|
}, [this] {
|
||||||
c->SetGravityMode(gravityMode->GetOption().second);
|
c->SetGravityMode(gravityMode->GetOption().second);
|
||||||
if (gravityMode->GetOption().second == 3)
|
if (gravityMode->GetOption().second == 3)
|
||||||
@ -215,9 +224,9 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
edgeMode = addDropDown("Edge mode", {
|
edgeMode = addDropDown("Edge mode", {
|
||||||
{ "Void", 0 },
|
{ "Void", EDGE_VOID },
|
||||||
{ "Solid", 1 },
|
{ "Solid", EDGE_SOLID },
|
||||||
{ "Loop", 2 },
|
{ "Loop", EDGE_LOOP },
|
||||||
}, [this] {
|
}, [this] {
|
||||||
c->SetEdgeMode(edgeMode->GetOption().second);
|
c->SetEdgeMode(edgeMode->GetOption().second);
|
||||||
});
|
});
|
||||||
@ -298,15 +307,22 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
|||||||
});
|
});
|
||||||
if constexpr (PLATFORM_CLIPBOARD)
|
if constexpr (PLATFORM_CLIPBOARD)
|
||||||
{
|
{
|
||||||
nativeClipoard = addCheckbox(0, "Use platform clipboard", "Allows copying and pasting across TPT instances", [this] {
|
auto indent = 0;
|
||||||
|
nativeClipoard = addCheckbox(indent, "Use platform clipboard", "Allows copying and pasting across TPT instances", [this] {
|
||||||
c->SetNativeClipoard(nativeClipoard->GetChecked());
|
c->SetNativeClipoard(nativeClipoard->GetChecked());
|
||||||
});
|
});
|
||||||
|
currentY -= 4; // temporarily undo the currentY += 4 at the end of addCheckbox
|
||||||
|
if (auto extra = Clipboard::Explanation())
|
||||||
|
{
|
||||||
|
addLabel(indent, "\bg" + *extra);
|
||||||
|
}
|
||||||
|
currentY += 4; // and then undo the undo
|
||||||
}
|
}
|
||||||
decoSpace = addDropDown("Colour space used by decoration tools", {
|
decoSpace = addDropDown("Colour space used by decoration tools", {
|
||||||
{ "sRGB", 0 },
|
{ "sRGB", DECOSPACE_SRGB },
|
||||||
{ "Linear", 1 },
|
{ "Linear", DECOSPACE_LINEAR },
|
||||||
{ "Gamma 2.2", 2 },
|
{ "Gamma 2.2", DECOSPACE_GAMMA22 },
|
||||||
{ "Gamma 1.8", 3 },
|
{ "Gamma 1.8", DECOSPACE_GAMMA18 },
|
||||||
}, [this] {
|
}, [this] {
|
||||||
c->SetDecoSpace(decoSpace->GetOption().second);
|
c->SetDecoSpace(decoSpace->GetOption().second);
|
||||||
});
|
});
|
||||||
|
@ -147,7 +147,7 @@ void PreviewModel::OnSaveReady()
|
|||||||
{
|
{
|
||||||
auto gameSave = std::make_unique<GameSave>(*saveData);
|
auto gameSave = std::make_unique<GameSave>(*saveData);
|
||||||
if (gameSave->fromNewerVersion)
|
if (gameSave->fromNewerVersion)
|
||||||
new ErrorMessage("This save is from a newer version", "Please update TPT in game or at https://powdertoy.co.uk");
|
new ErrorMessage("This save is from a newer version", String::Build("Please update TPT in game or at https://", SERVER));
|
||||||
saveInfo->SetGameSave(std::move(gameSave));
|
saveInfo->SetGameSave(std::move(gameSave));
|
||||||
}
|
}
|
||||||
catch(ParseException &e)
|
catch(ParseException &e)
|
||||||
|
@ -111,9 +111,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
|||||||
AddComponent(missingElementsButton);
|
AddComponent(missingElementsButton);
|
||||||
|
|
||||||
if(showAvatars)
|
if(showAvatars)
|
||||||
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(180, 16), "");
|
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(265, 16), "");
|
||||||
else
|
else
|
||||||
saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(200, 16), "");
|
saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(300, 16), "");
|
||||||
saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
AddComponent(saveNameLabel);
|
AddComponent(saveNameLabel);
|
||||||
@ -129,9 +129,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
|||||||
AddComponent(saveDescriptionLabel);
|
AddComponent(saveDescriptionLabel);
|
||||||
|
|
||||||
if(showAvatars)
|
if(showAvatars)
|
||||||
authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(180, 16), "");
|
authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(200, 16), "");
|
||||||
else
|
else
|
||||||
authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(200, 16), "");
|
authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(220, 16), "");
|
||||||
authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
AddComponent(authorDateLabel);
|
AddComponent(authorDateLabel);
|
||||||
@ -148,7 +148,7 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
|||||||
AddComponent(avatarButton);
|
AddComponent(avatarButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewsLabel = new ui::Label(ui::Point((XRES/2)-80, (YRES/2)+4+15), ui::Point(80, 16), "");
|
viewsLabel = new ui::Label(ui::Point((XRES/2)-88, (YRES/2)+4+15), ui::Point(88, 16), "");
|
||||||
viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
|
viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
|
||||||
viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
AddComponent(viewsLabel);
|
AddComponent(viewsLabel);
|
||||||
@ -644,6 +644,7 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
|
|||||||
} });
|
} });
|
||||||
addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
addCommentBox->SetMultiline(true);
|
addCommentBox->SetMultiline(true);
|
||||||
|
addCommentBox->SetLimit(1000);
|
||||||
AddComponent(addCommentBox);
|
AddComponent(addCommentBox);
|
||||||
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit");
|
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit");
|
||||||
submitCommentButton->SetActionCallback({ [this] { submitComment(); } });
|
submitCommentButton->SetActionCallback({ [this] { submitComment(); } });
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user