summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/cmake-tag.yml23
-rw-r--r--.github/workflows/cmake.yml34
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt24
-rw-r--r--README.md26
-rw-r--r--anim-crop-tool/main.cpp4
-rw-r--r--bench/critter.cpp4
-rw-r--r--cmake/msvc.cmake4
-rw-r--r--compat/array-size.hpp8
-rw-r--r--compat/assert.cpp38
-rw-r--r--compat/assert.hpp61
-rw-r--r--compat/borrowed-ptr-fwd.hpp8
-rw-r--r--compat/borrowed-ptr.cpp2
-rw-r--r--compat/borrowed-ptr.hpp8
-rw-r--r--compat/borrowed-ptr.inl23
-rw-r--r--compat/format.hpp10
-rw-r--r--compat/fpu.hpp4
-rw-r--r--compat/function2.hpp4
-rw-r--r--compat/heap.hpp48
-rw-r--r--compat/intrusive-ptr.hpp8
-rw-r--r--compat/unroll.hpp13
-rw-r--r--contrib/all.sh15
-rw-r--r--doc/render-wall-holes.pdnbin0 -> 162726 bytes
-rw-r--r--draw/ground.cpp2
-rw-r--r--draw/wall.cpp3
-rw-r--r--editor/app.hpp14
-rw-r--r--editor/camera.cpp8
-rw-r--r--editor/draw.cpp12
-rw-r--r--editor/events.cpp152
-rw-r--r--editor/imgui-editors.cpp4
-rw-r--r--editor/imgui-raii.cpp1
-rw-r--r--editor/imgui.cpp10
-rw-r--r--editor/inspect-draw.cpp2
-rw-r--r--editor/inspect-types.cpp2
-rw-r--r--editor/inspect.cpp3
-rw-r--r--editor/scenery-editor.cpp9
-rw-r--r--editor/tests/hole-test.cpp2
-rw-r--r--editor/tests/raycast-test.cpp4
-rw-r--r--editor/vobj-editor.cpp14
-rw-r--r--entity/accessor.hpp13
-rw-r--r--entity/concepts.hpp1
-rw-r--r--entity/constraints.hpp7
-rw-r--r--entity/erased-constraints.cpp12
-rw-r--r--entity/erased-constraints.hpp3
-rw-r--r--entity/field-status.hpp7
-rw-r--r--entity/field.hpp163
-rw-r--r--entity/metadata.hpp196
-rw-r--r--external/CMakeLists.txt18
m---------external/benchmark0
m---------external/corrade0
m---------external/fmt0
m---------external/imgui0
m---------external/luajit0
m---------external/magnum0
m---------external/magnum-integration0
m---------external/magnum-plugins0
m---------external/robin-map0
m---------external/sdl20
-rw-r--r--floormat/app.hpp9
-rw-r--r--floormat/events.hpp11
-rw-r--r--hash/xxhash.cpp2
-rw-r--r--main/events.cpp100
-rw-r--r--main/main-impl.hpp9
-rw-r--r--main/sdl-fwd.hpp11
-rw-r--r--main/sdl-fwd.inl15
-rw-r--r--run-show-coverage.sh3
-rw-r--r--shaders/shader.hpp4
-rw-r--r--src/RTree-fwd.h7
-rw-r--r--src/RTree.cpp3
-rw-r--r--src/RTree.h6
-rw-r--r--src/anim-atlas.cpp8
-rw-r--r--src/anim.cpp1
-rw-r--r--src/chunk-collision.cpp90
-rw-r--r--src/chunk-region.cpp4
-rw-r--r--src/chunk-render.cpp8
-rw-r--r--src/chunk-scenery.cpp21
-rw-r--r--src/chunk-walls.cpp533
-rw-r--r--src/chunk.cpp18
-rw-r--r--src/chunk.hpp19
-rw-r--r--src/collision.hpp6
-rw-r--r--src/critter-script-walk.cpp1
-rw-r--r--src/critter.cpp103
-rw-r--r--src/hole-cut.cpp89
-rw-r--r--src/hole-cut.hpp25
-rw-r--r--src/hole.hpp16
-rw-r--r--src/object.cpp2
-rw-r--r--src/object.hpp1
-rw-r--r--src/point.hpp4
-rw-r--r--src/raycast.cpp6
-rw-r--r--src/script.cpp10
-rw-r--r--src/search.cpp2
-rw-r--r--src/tile-bbox.hpp28
-rw-r--r--src/wall-atlas.hpp10
-rw-r--r--src/wall-defs.hpp2
-rw-r--r--src/world.cpp7
-rw-r--r--src/world.hpp2
-rw-r--r--test/app.cpp1
-rw-r--r--test/app.hpp1
-rw-r--r--test/bptr.cpp64
-rw-r--r--test/critter.cpp4
-rw-r--r--test/entity.cpp6
-rw-r--r--test/hole.cpp43
-rw-r--r--test/save.cpp1
-rw-r--r--test/util.cpp45
-rw-r--r--userconfig-sthalik@Windows-Clang.cmake25
-rw-r--r--userconfig-sthalik@Windows-GNU.cmake28
106 files changed, 1459 insertions, 989 deletions
diff --git a/.github/workflows/cmake-tag.yml b/.github/workflows/cmake-tag.yml
index 84809590..8b8aaf97 100644
--- a/.github/workflows/cmake-tag.yml
+++ b/.github/workflows/cmake-tag.yml
@@ -15,14 +15,14 @@ jobs:
strategy:
fail-fast: true
matrix:
- os: [ubuntu-22.04, windows-latest, macos-12]
+ os: [ubuntu-latest, windows-latest, macos-latest]
include:
- - os: ubuntu-22.04
- cmake: /usr/bin/env CC=gcc-13 CXX=g++-13 cmake
- - os: macos-12
- cmake: /usr/bin/env CC="$(brew --prefix llvm@17)/bin/clang" CXX="$(brew --prefix llvm@17)/bin/clang++" cmake
+ - os: ubuntu-latest
+ cmake: /usr/bin/env CC=gcc-14 CXX=g++-14 cmake
- os: windows-latest
cmake: .\.github\workflows\build-windows.bat cmake
+ - os: macos-latest
+ cmake: /usr/bin/env CC="$(brew --prefix llvm)/bin/clang" CXX="$(brew --prefix llvm)/bin/clang++" cmake
steps:
- uses: actions/checkout@v3
@@ -32,21 +32,21 @@ jobs:
- uses: abdes/gha-setup-ninja@master
with:
version: 1.11.1
- if: matrix.os != 'ubuntu-22.04'
+ if: matrix.os != 'ubuntu-latest'
- name: Install Linux dependencies
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt -q=2 update
- sudo apt install g++-13 gdb ninja-build libbenchmark-dev
+ sudo apt install g++-14 gdb ninja-build libbenchmark-dev
sudo apt -q install libgl1-mesa-dri libgl-dev libglx-dev xorg-dev xvfb libopencv-dev
sudo apt -q install libsdl2-dev
- if: matrix.os == 'ubuntu-22.04'
+ if: matrix.os == 'ubuntu-latest'
- name: Install OSX dependencies
run: |
- brew install SDL2 llvm@17
- if: matrix.os == 'macos-12'
+ brew install SDL2 llvm lld
+ if: matrix.os == 'macos-latest'
- name: Configure
run: ${{matrix.cmake}} -G "Ninja" -S ${{github.workspace}}/ -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
@@ -57,11 +57,12 @@ jobs:
- name: Test
run: |
cd ${{github.workspace}}/build/install
+ export MAGNUM_LOG=default
export LD_LIBRARY_PATH="$PWD/lib" ASAN_OPTIONS="detect_leaks=0:abort_on_error=1"
set -e
xvfb-run gdb -q -batch -x ../../.github/gdbscript.py --args bin/floormat-test
xvfb-run gdb -q -batch -x ../../.github/gdbscript.py --args bin/floormat-benchmark
- if: matrix.os == 'ubuntu-22.04'
+ if: matrix.os == 'ubuntu-latest'
# - name: Upload build
# uses: actions/upload-artifact@v2.2.4
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index b18fff28..a790a869 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -15,39 +15,24 @@ jobs:
strategy:
fail-fast: true
matrix:
- #os: [ubuntu-22.04, windows-latest, macos-12]
- os: [ubuntu-22.04]
+ os: [ubuntu-latest]
include:
- - os: ubuntu-22.04
- cmake: /usr/bin/env CC=gcc-13 CXX=g++-13 cmake
- #- os: macos-12
- # cmake: /usr/bin/env CC="$(brew --prefix llvm@16)/bin/clang" CXX="$(brew --prefix llvm@16)/bin/clang++" cmake
- #- os: windows-latest
- # cmake: .\.github\workflows\build-windows.bat cmake
+ - os: ubuntu-latest
+ cmake: /usr/bin/env CC=gcc-14 CXX=g++-14 cmake
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- - uses: abdes/gha-setup-ninja@master
- with:
- version: 1.11.1
- if: matrix.os != 'ubuntu-22.04'
-
- name: Install Linux dependencies
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt -q=2 update
- sudo apt install g++-13 gdb ninja-build libbenchmark-dev
+ sudo apt install g++-14 gdb ninja-build libbenchmark-dev
sudo apt -q install libgl1-mesa-dri libgl-dev libglx-dev xorg-dev xvfb libopencv-dev
sudo apt -q install libsdl2-dev
- if: matrix.os == 'ubuntu-22.04'
-
- - name: Install OSX dependencies
- run: |
- brew install SDL2 llvm@16
- if: matrix.os == 'macos-12'
+ if: matrix.os == 'ubuntu-latest'
- name: Configure
run: ${{matrix.cmake}} -G "Ninja" -S ${{github.workspace}}/ -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
@@ -58,14 +43,9 @@ jobs:
- name: Test
run: |
cd ${{github.workspace}}/build/install
+ export MAGNUM_LOG=default
export LD_LIBRARY_PATH="$PWD/lib" ASAN_OPTIONS="detect_leaks=0:abort_on_error=1"
set -e
xvfb-run gdb -q -batch -x ../../.github/gdbscript.py --args bin/floormat-test
xvfb-run gdb -q -batch -x ../../.github/gdbscript.py --args bin/floormat-benchmark
- if: matrix.os == 'ubuntu-22.04'
-
-# - name: Upload build
-# uses: actions/upload-artifact@v2.2.4
-# with:
-# name: buildoutput
-# path: ${{github.workspace}}/build/
+ if: matrix.os == 'ubuntu-24.04'
diff --git a/.gitmodules b/.gitmodules
index 1b59229d..b4537dd2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -22,9 +22,6 @@
[submodule "fmt"]
path = external/fmt
url = https://github.com/fmtlib/fmt.git
-[submodule "luajit"]
- path = external/luajit
- url = https://github.com/sthalik/luajit.git
[submodule "robin-map"]
path = external/robin-map
url = https://github.com/Tessil/robin-map.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c09dd5df..54840a58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,13 +151,26 @@ if(MSVC)
add_link_options(-HIGHENTROPYVA)
endif()
else()
+ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
+ add_definitions(-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
+ add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-ambiguous-reversed-operator>)
+ add_compile_options(-Wno-reserved-macro-identifier)
+ #add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:_LIBCPP_ENABLE_ASSERTIONS>>)
+ else()
+ #add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:-D_GLIBCXX_ASSERTIONS>>)
+ #add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:-D_GLIBCXX_DEBUG>>)
+ #add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:-D_GLIBCXX_DEBUG_PEDANTIC>>)
+ endif()
+
+ add_compile_options(-Wstrict-aliasing -Werror=strict-aliasing)
add_compile_options(-Wno-float-equal)
- if(NOT WIN32)
+
+ if(NOT APPLE)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fuse-cxa-atexit>)
endif()
if(WIN32)
add_link_options(-Wl,--nxcompat -Wl,--dynamicbase)
- if(CMAKE_SIZEOF_VOID_P GREATER_EQUAL 8)
+ if(CMAKE_SIZEOF_VOID_P GREATER 4)
add_link_options(-Wl,--high-entropy-va)
else()
add_link_options(-Wl,--large-address-aware)
@@ -165,12 +178,6 @@ else()
endif()
endif()
-if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
- add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:_LIBCPP_ENABLE_ASSERTIONS>>)
- add_compile_options(-Wno-reserved-macro-identifier)
- add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-ambiguous-reversed-operator>)
-endif()
-
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS OFF)
set_directory_properties(PROPERTIES CORRADE_CXX_STANDARD ${CMAKE_CXX_STANDARD})
set_directory_properties(PROPERTIES INTERFACE_CORRADE_CXX_STANDARD ${CMAKE_CXX_STANDARD})
@@ -223,7 +230,6 @@ if(CMAKE_COMPILER_IS_GNUCXX)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
- add_definitions(-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
add_compile_options(-Wno-shift-op-parentheses)
add_compile_options(-Wno-c99-compat)
elseif(CMAKE_COMPILER_IS_GNUCXX)
diff --git a/README.md b/README.md
index 64ac0ad6..da8e618a 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,29 @@
[![commit](https://github.com/sthalik/floormat/actions/workflows/cmake.yml/badge.svg)](https://github.com/sthalik/floormat/actions/workflows/cmake.yml)
-### floormat
+# floormat
Game project in early development.
-### Build
+## Build
-Should build cleanly on Clang 17+, GCC 13.2+ and MSVC 17.7. Just make sure to check it out with submodules.
+Should build cleanly on Clang 17+, GCC 13.2+ and MSVC 17.7+.
-### License
+### Debian/Ubuntu dependencies
+`xorg-dev` `libsdl2-dev` `build-essential` `ninja-build` `cmake-curses-gui`
-ISC
+### Windows dependencies
+
+Only the compiler (MSVC, GCC, Clang) is needed.
+
+### Building
+```console
+git clone https://github.com/sthalik/floormat.git
+cd floormat
+git submodule update --init
+mkdir build
+cd build
+cmake -GNinja ../
+ninja install
+ln -s ../doc/saves ./save
+install/bin/floormat-editor
+```
diff --git a/anim-crop-tool/main.cpp b/anim-crop-tool/main.cpp
index 7ba31b6e..8d88eab6 100644
--- a/anim-crop-tool/main.cpp
+++ b/anim-crop-tool/main.cpp
@@ -149,7 +149,7 @@ bool load_directory(anim_group& group, options& opts, anim_atlas_& atlas)
for (max = 1; max <= 9999; max++)
{
char filename[9];
- sprintf(filename, "%04d.png", max);
+ sprintf(filename, "%04u.png", max);
if (!Path::exists(Path::join(input_dir, filename)))
break;
}
@@ -176,7 +176,7 @@ bool load_directory(anim_group& group, options& opts, anim_atlas_& atlas)
for (unsigned i = 1; i < max; i++)
{
char filename[9];
- sprintf(filename, "%04d.png", i);
+ sprintf(filename, "%04u.png", i);
if (!load_file(group, opts, atlas, Path::join(input_dir, filename)))
return false;
}
diff --git a/bench/critter.cpp b/bench/critter.cpp
index 418a4f9e..d8548452 100644
--- a/bench/critter.cpp
+++ b/bench/critter.cpp
@@ -1,4 +1,5 @@
#include "compat/debug.hpp"
+#include "compat/assert.hpp"
#include "compat/function2.hpp"
#include "src/critter.hpp"
#include "src/world.hpp"
@@ -15,6 +16,7 @@ namespace floormat {
namespace {
+namespace fm_debug = floormat::debug::detail;
using enum rotation;
using fu2::function_view;
using Function = function_view<Ns() const>;
@@ -137,7 +139,7 @@ bool run(world& w, const function_view<Ns() const>& make_dt,
if (b) [[likely]]
return false;
else
- fm_emit_assert_fail("false", file, line);
+ fm_debug::emit_abort(file, line, "false");
};
for (i = 0; true; i++)
diff --git a/cmake/msvc.cmake b/cmake/msvc.cmake
index e21e17d7..5154c296 100644
--- a/cmake/msvc.cmake
+++ b/cmake/msvc.cmake
@@ -43,12 +43,12 @@ SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
#add_compile_options(-Qvec-report:2)
#add_compile_options(-d2cgsummary -Bt)
-add_compile_options(-QIntel-jcc-erratum)
+#add_compile_options(-QIntel-jcc-erratum)
add_definitions(-D_HAS_EXCEPTIONS=0)
if(DEFINED CMAKE_TOOLCHAIN_FILE)
# ignore cmake warning: Manually-specified variable not used by the project
- set(CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}}")
+ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}")
endif()
#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
diff --git a/compat/array-size.hpp b/compat/array-size.hpp
index 15eb66ab..98da4d1e 100644
--- a/compat/array-size.hpp
+++ b/compat/array-size.hpp
@@ -5,15 +5,19 @@ namespace floormat::detail {
template<typename T> struct array_size_;
template<typename T, size_t N> struct array_size_<T(&)[N]> : std::integral_constant<size_t, N> {};
+template<typename T, size_t N> struct array_size_<T(*)[N]> : std::integral_constant<size_t, N> {};
template<typename T, size_t N> struct array_size_<T[N]> : std::integral_constant<size_t, N> {};
template<typename T, size_t N> struct array_size_<std::array<T, N>> : std::integral_constant<size_t, N> {};
template<typename T, size_t N> struct array_size_<StaticArray<N, T>> : std::integral_constant<size_t, N> {};
+template<typename C, typename T> struct array_size_<T C::*> : std::integral_constant<size_t, array_size_<std::remove_cvref_t<T>>::value> {};
+//template<typename T, typename U, size_t N> struct array_size_< T(U::*)[N] > : std::integral_constant<size_t, N> {}; // should be redundant
+
} // namespace floormat::detail
namespace floormat {
-template<typename T> constexpr inline size_t static_array_size = detail::array_size_<T>::value;
-template<typename T> constexpr inline size_t array_size(const T&) noexcept { return detail::array_size_<T>::value; }
+template<typename T> constexpr inline size_t static_array_size = detail::array_size_<std::remove_cvref_t<T>>::value;
+template<typename T> constexpr inline size_t array_size(const T&) noexcept { return detail::array_size_<std::remove_cvref_t<T>>::value; }
} // namespace floormat
diff --git a/compat/assert.cpp b/compat/assert.cpp
index cd6e9af3..3f030b6b 100644
--- a/compat/assert.cpp
+++ b/compat/assert.cpp
@@ -1,4 +1,5 @@
#include "assert.hpp"
+#include "exception.hpp"
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
@@ -7,13 +8,15 @@
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
-namespace floormat {
+namespace floormat::debug::detail {
namespace {
+bool do_soft_assert = false;
+
template<bool DoPrefix, bool DoSourceLocation>
CORRADE_NEVER_INLINE
-void fm_emit_debug_(const char* prefix, const char* file, int line, const char* fmt, va_list arg_ptr)
+void emit_debug_(const char* prefix, const char* file, int line, const char* fmt, va_list arg_ptr)
{
std::fflush(stdout);
std::fflush(stderr);
@@ -29,31 +32,31 @@ void fm_emit_debug_(const char* prefix, const char* file, int line, const char*
} // namespace
-void fm_emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...)
+void emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...)
{
va_list arg_ptr;
va_start(arg_ptr, fmt);
- fm_emit_debug_<true, false>(prefix, nullptr, 0, fmt, arg_ptr);
+ emit_debug_<true, false>(prefix, nullptr, 0, fmt, arg_ptr);
va_end(arg_ptr);
}
-void fm_emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...)
+void emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...)
{
va_list arg_ptr;
va_start(arg_ptr, fmt);
- fm_emit_debug_<false, false>(nullptr, nullptr, 0, fmt, arg_ptr);
+ emit_debug_<false, false>(nullptr, nullptr, 0, fmt, arg_ptr);
va_end(arg_ptr);
}
-void CORRADE_NEVER_INLINE fm_emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...)
+void CORRADE_NEVER_INLINE emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...)
{
va_list arg_ptr;
va_start(arg_ptr, fmt);
- fm_emit_debug_<true, true>(prefix, file, line, fmt, arg_ptr);
+ emit_debug_<true, true>(prefix, file, line, fmt, arg_ptr);
va_end(arg_ptr);
}
-void fm_emit_assert_fail(const char* expr, const char* file, int line)
+void emit_assert_fail(const char* expr, const char* file, int line)
{
std::fflush(stdout);
std::fflush(stderr);
@@ -62,20 +65,29 @@ void fm_emit_assert_fail(const char* expr, const char* file, int line)
std::abort();
}
-void fm_emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...)
+void emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...)
{
va_list arg_ptr;
va_start(arg_ptr, fmt);
- fm_emit_debug_<true, true>("fatal: ", file, line, fmt, arg_ptr);
+ emit_debug_<true, true>("fatal: ", file, line, fmt, arg_ptr);
va_end(arg_ptr);
std::abort();
}
-void fm_emit_abort()
+void emit_abort()
{
std::fflush(stdout);
std::fflush(stderr);
std::abort();
}
-} // namespace floormat
+} // namespace floormat::debug::detail
+
+using namespace floormat::debug::detail;
+
+namespace floormat::debug {
+
+void set_soft_assert_mode(bool value) { do_soft_assert = value; }
+bool soft_assert_mode() { return detail::do_soft_assert; }
+
+} // namespace floormat::debug
diff --git a/compat/assert.hpp b/compat/assert.hpp
index 8c882b0e..1333c6a6 100644
--- a/compat/assert.hpp
+++ b/compat/assert.hpp
@@ -12,16 +12,29 @@
#define fm_FORMAT_ARG_MSVC
#endif
-namespace floormat {
+namespace floormat::debug::detail {
+
+void emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(2);
+void emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(1);
+void emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(4);
+void emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3);
+
+[[noreturn]] CORRADE_NEVER_INLINE void emit_assert_fail(const char* expr, const char* file, int line);
+[[noreturn]] CORRADE_NEVER_INLINE void emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3);
+[[noreturn]] CORRADE_NEVER_INLINE void emit_abort();
+
+} // namespace floormat::debug::detail
+
+
+namespace floormat::debug {
+
+void set_soft_assert_mode(bool value);
+bool soft_assert_mode();
-void fm_emit_debug(const char* prefix, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(2);
-void fm_emit_debug0(fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(1);
-void fm_emit_debug_loc(const char* prefix, const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(4);
-void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3);
+} // namespace floormat::debug
-[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_assert_fail(const char* expr, const char* file, int line);
-[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_abort(const char* file, int line, fm_FORMAT_ARG_MSVC const char* fmt, ...) fm_FORMAT_ARG(3);
-[[noreturn]] CORRADE_NEVER_INLINE void fm_emit_abort();
+
+namespace floormat {
} // namespace floormat
@@ -30,19 +43,29 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha
#pragma GCC diagnostic ignored "-Wunused-macros"
#endif
-#define fm_assert(...) ((__VA_ARGS__) ? void() : ::floormat::fm_emit_assert_fail(#__VA_ARGS__, __FILE__, __LINE__))
-#define fm_abort(...) (::floormat::fm_emit_abort(__FILE__, __LINE__, __VA_ARGS__))
-#define fm_warn(...) (::floormat::fm_emit_debug("warning: ", __VA_ARGS__))
-#define fm_error(...) (::floormat::fm_emit_debug("error: ", __VA_ARGS__))
-#define fm_log(...) (::floormat::fm_emit_debug0(__VA_ARGS__))
-#define fm_debug(...) (::floormat::fm_emit_debug0(__VA_ARGS__))
-#define fm_debug_loc(pfx, ...) (::floormat::fm_emit_debug_loc(pfx, __FILE__, __LINE__,__VA_ARGS__))
-#define fm_debug_loc0(...) (::floormat::fm_emit_debug_loc0(__FILE__, __LINE__,__VA_ARGS__))
+#define fm_assert(...) ((__VA_ARGS__) ? void() : ::floormat::debug::detail::emit_assert_fail(#__VA_ARGS__, __FILE__, __LINE__))
+#define fm_abort(...) (::floormat::debug::detail::emit_abort(__FILE__, __LINE__, __VA_ARGS__))
+#define fm_warn(...) (::floormat::debug::detail::emit_debug("warning: ", __VA_ARGS__))
+#define fm_error(...) (::floormat::debug::detail::emit_debug("error: ", __VA_ARGS__))
+#define fm_log(...) (::floormat::debug::detail::emit_debug0(__VA_ARGS__))
+#define fm_debug(...) (::floormat::debug::detail::emit_debug0(__VA_ARGS__))
+#define fm_debug_loc(pfx, ...) (::floormat::debug::detail::emit_debug_loc(pfx, __FILE__, __LINE__,__VA_ARGS__))
+#define fm_debug_loc0(...) (::floormat::debug::detail::emit_debug_loc0(__FILE__, __LINE__,__VA_ARGS__))
+
+#if defined FM_NO_DEBUG && !defined FM_NO_DEBUG2
+#define FM_NO_DEBUG2
+#endif
#ifndef FM_NO_DEBUG
#define fm_debug_assert(...) fm_assert(__VA_ARGS__)
#else
-#define fm_debug_assert(...) void()
+#define fm_debug_assert(...) (void())
+#endif
+
+#ifndef FM_NO_DEBUG2
+#define fm_debug2_assert(...) fm_assert(__VA_ARGS__)
+#else
+#define fm_debug2_assert(...) (void())
#endif
#define fm_warn_once(...) do { \
@@ -66,7 +89,7 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha
ERR_nospace << #__VA_ARGS__; \
ERR_nospace << " expected: " << a; \
ERR_nospace << " actual: " << b; \
- fm_emit_abort(); \
+ ::floormat::debug::detail::emit_abort(); \
} \
})(__VA_ARGS__)
@@ -83,7 +106,7 @@ void fm_emit_debug_loc0(const char* file, int line, fm_FORMAT_ARG_MSVC const cha
ERR_nospace << #__VA_ARGS__; \
ERR_nospace << "not expected: " << a; \
ERR_nospace << " actual: " << b; \
- fm_emit_abort(); \
+ ::floormat::debug::detail::emit_abort(); \
} \
})(__VA_ARGS__)
diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp
index 8fcc5dde..48c3e141 100644
--- a/compat/borrowed-ptr-fwd.hpp
+++ b/compat/borrowed-ptr-fwd.hpp
@@ -2,12 +2,18 @@
namespace floormat {
+#define FM_BPTR_DEBUG
+//#define FM_NO_WEAK_BPTR
+
struct bptr_base;
template<typename T> class bptr;
template<typename T> class weak_bptr;
template<typename T> bptr(T* ptr) -> bptr<T>;
-template<typename T> bptr(const T* ptr) -> bptr<const T>;
+
+#ifndef FM_NO_WEAK_BPTR
+template<typename T> weak_bptr(const bptr<T>& ptr) -> weak_bptr<T>;
+#endif
} // namespace floormat
diff --git a/compat/borrowed-ptr.cpp b/compat/borrowed-ptr.cpp
index 1dded12a..e64468d5 100644
--- a/compat/borrowed-ptr.cpp
+++ b/compat/borrowed-ptr.cpp
@@ -4,6 +4,8 @@ namespace floormat::detail_bptr {
void control_block::decrement(control_block*& blk) noexcept
{
+ if (!blk)
+ return;
auto c2 = --blk->_hard_count;
fm_bptr_assert(c2 != (uint32_t)-1);
if (c2 == 0)
diff --git a/compat/borrowed-ptr.hpp b/compat/borrowed-ptr.hpp
index 6a4e79f1..b818154c 100644
--- a/compat/borrowed-ptr.hpp
+++ b/compat/borrowed-ptr.hpp
@@ -1,9 +1,5 @@
#pragma once
#include "borrowed-ptr-fwd.hpp"
-#include <compare>
-
-#define FM_BPTR_DEBUG
-#define FM_NO_WEAK_BPTR
#ifdef __CLION_IDE__
#define fm_bptr_assert(...) (void(__VA_ARGS__))
@@ -113,10 +109,6 @@ public:
bool operator==(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>);
bool operator==(const std::nullptr_t& other) const noexcept;
- std::strong_ordering operator<=>(const bptr<const T>& other) const noexcept;
- std::strong_ordering operator<=>(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>);
- std::strong_ordering operator<=>(const std::nullptr_t&) const noexcept;
-
template<typename U> friend class bptr;
template<typename U> friend class weak_bptr;
diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl
index e1a5f591..d8c561a5 100644
--- a/compat/borrowed-ptr.inl
+++ b/compat/borrowed-ptr.inl
@@ -9,7 +9,7 @@
namespace floormat {
-template<typename T> bptr<T>::~bptr() noexcept { if (blk) detail_bptr::control_block::decrement(blk); }
+template<typename T> bptr<T>::~bptr() noexcept { detail_bptr::control_block::decrement(blk); }
template<typename T> bptr<T>::bptr(const bptr<std::remove_const_t<T>>& ptr) noexcept requires std::is_const_v<T>: bptr{ptr, nullptr} {}
template<typename T> bptr<T>::bptr(bptr<std::remove_const_t<T>>&& ptr) noexcept requires std::is_const_v<T>: bptr{move(ptr), nullptr} {}
@@ -41,14 +41,13 @@ template<detail_bptr::DerivedFrom<T> Y>
bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept
{ return _move_assign(move(other)); }
-template<typename T> void bptr<T>::reset() noexcept { if (blk) detail_bptr::control_block::decrement(blk); }
+template<typename T> void bptr<T>::reset() noexcept { detail_bptr::control_block::decrement(blk); }
template<typename T>
template<detail_bptr::DerivedFrom<T> Y>
void bptr<T>::reset(Y* ptr) noexcept
{
- if (blk)
- detail_bptr::control_block::decrement(blk);
+ detail_bptr::control_block::decrement(blk);
blk = ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1,
#ifndef FM_NO_WEAK_BPTR
1,
@@ -95,8 +94,7 @@ bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& other) noexcept
{
if (blk != other.blk)
{
- if (blk)
- detail_bptr::control_block::decrement(blk);
+ detail_bptr::control_block::decrement(blk);
blk = other.blk;
if (blk)
{
@@ -113,8 +111,7 @@ template<typename T>
template<typename Y>
bptr<T>& bptr<T>::_move_assign(bptr<Y>&& other) noexcept
{
- if (blk)
- detail_bptr::control_block::decrement(blk);
+ detail_bptr::control_block::decrement(blk);
blk = other.blk;
other.blk = nullptr;
return *this;
@@ -151,16 +148,6 @@ template<typename T> bool bptr<T>::operator==(const bptr<T>& other) const noexce
template<typename T> bool bptr<T>::operator==(const std::nullptr_t&) const noexcept { return !blk || !blk->_ptr; }
-template<typename T>
-std::strong_ordering bptr<T>::operator<=>(const bptr<const T>& other) const noexcept
-{ return get() <=> other.get(); }
-
-template<typename T> std::strong_ordering bptr<T>::operator<=>(const bptr<T>& other) const noexcept requires (!std::is_const_v<T>)
-{ return get() <=> other.get(); }
-
-template<typename T> std::strong_ordering bptr<T>::operator<=>(const std::nullptr_t&) const noexcept
-{ return get() <=> (T*)nullptr; }
-
template<typename T> void bptr<T>::swap(bptr& other) noexcept { floormat::swap(blk, other.blk); }
template<typename T>
diff --git a/compat/format.hpp b/compat/format.hpp
index 1cb4f365..800bce5a 100644
--- a/compat/format.hpp
+++ b/compat/format.hpp
@@ -9,12 +9,12 @@ namespace fmt {
template<> struct formatter<Corrade::Containers::StringView> {
template<typename ParseContext> static constexpr auto parse(ParseContext& ctx) { return ctx.begin(); }
- template<typename FormatContext> auto format(Corrade::Containers::StringView const& s, FormatContext& ctx);
+ template<typename FormatContext> auto format(Corrade::Containers::StringView const& s, FormatContext& ctx) const;
};
template<> struct formatter<Corrade::Containers::String> {
template<typename ParseContext> static constexpr auto parse(ParseContext& ctx) { return ctx.begin(); }
- template<typename FormatContext> auto format(Corrade::Containers::String const& s, FormatContext& ctx);
+ template<typename FormatContext> auto format(Corrade::Containers::String const& s, FormatContext& ctx) const;
};
} // namespace fmt
@@ -42,7 +42,7 @@ consteval auto operator""_cf() noexcept
return FMT_COMPILE(s.data);
}
#else
-using namespace fmt::literals;
+using fmt::literals::operator""_cf;
#endif
namespace floormat {
@@ -66,11 +66,11 @@ size_t snformat(char(&buf)[N], Fmt&& fmt, Xs&&... args)
} // namespace floormat
template<typename FormatContext>
-auto fmt::formatter<Corrade::Containers::StringView>::format(Corrade::Containers::StringView const& s, FormatContext& ctx) {
+auto fmt::formatter<Corrade::Containers::StringView>::format(Corrade::Containers::StringView const& s, FormatContext& ctx) const {
return fmt::format_to(ctx.out(), "{}"_cf, basic_string_view<char>{s.data(), s.size()});
}
template<typename FormatContext>
-auto fmt::formatter<Corrade::Containers::String>::format(Corrade::Containers::String const& s, FormatContext& ctx) {
+auto fmt::formatter<Corrade::Containers::String>::format(Corrade::Containers::String const& s, FormatContext& ctx) const {
return fmt::format_to(ctx.out(), "{}"_cf, basic_string_view<char>{s.data(), s.size()});
}
diff --git a/compat/fpu.hpp b/compat/fpu.hpp
index 9433648a..e72e8fdd 100644
--- a/compat/fpu.hpp
+++ b/compat/fpu.hpp
@@ -19,7 +19,11 @@ static inline void set_fp_mask()
#endif
#ifdef __APPLE__
+#if defined __386__ || defined __x86_64__
fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);
+#elif defined __arm64__
+ fesetenv(FE_DFL_DISABLE_DENORMS_ENV);
+#endif
#endif
#ifdef _WIN32
diff --git a/compat/function2.hpp b/compat/function2.hpp
index 9e6b9b50..f53dcf7f 100644
--- a/compat/function2.hpp
+++ b/compat/function2.hpp
@@ -1082,8 +1082,8 @@ struct internal_capacity {
/// Tag to access the structure in a type-safe way
data_accessor accessor_;
/// The internal capacity we use to allocate in-place
- struct {
- alignas(Capacity::alignment) unsigned char data[Capacity::capacity];
+ struct alignas(Capacity::alignment) {
+ unsigned char data[Capacity::capacity];
} capacity_;
} type;
};
diff --git a/compat/heap.hpp b/compat/heap.hpp
index 3d901755..665d11e3 100644
--- a/compat/heap.hpp
+++ b/compat/heap.hpp
@@ -1,6 +1,54 @@
#pragma once
#if defined __GLIBCXX__ && defined _GLIBCXX_DEBUG
+// Heap implementation -*- C++ -*-
+
+// Copyright (C) 2001-2024 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * Copyright (c) 1997
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
#include <utility>
#include <iterator>
// regular STL implementation stripped of debug code
diff --git a/compat/intrusive-ptr.hpp b/compat/intrusive-ptr.hpp
index 8e9b3d6c..c8cf6ff3 100644
--- a/compat/intrusive-ptr.hpp
+++ b/compat/intrusive-ptr.hpp
@@ -41,10 +41,10 @@ struct refcount_ops
using Tref = T*;
#endif
- static constexpr inline auto incr(T* ptr) noexcept -> size_type; // todo! remove constexpr from everywhere, then move everything to .inl
- static constexpr inline auto decr(Tref ptr) noexcept -> size_type;
- static constexpr inline auto count(T* ptr) noexcept -> size_type;
- static constexpr inline void init_to_1(T* ptr) noexcept;
+ static constexpr auto incr(T* ptr) noexcept -> size_type; // todo! remove constexpr from everywhere, then move everything to .inl
+ static constexpr auto decr(Tref ptr) noexcept -> size_type;
+ static constexpr auto count(T* ptr) noexcept -> size_type;
+ static constexpr void init_to_1(T* ptr) noexcept;
};
template<typename Tag, typename T>
diff --git a/compat/unroll.hpp b/compat/unroll.hpp
new file mode 100644
index 00000000..2b74ed1a
--- /dev/null
+++ b/compat/unroll.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace floormat {
+
+template<uint32_t Max, typename F>
+constexpr CORRADE_ALWAYS_INLINE void unroll(F&& fn)
+{
+ [&]<size_t... Is>(std::index_sequence<Is...>) {
+ (..., fn(std::integral_constant<size_t, Is>{}));
+ }(std::make_index_sequence<Max>());
+}
+
+} // namespace floormat
diff --git a/contrib/all.sh b/contrib/all.sh
index e7bdd720..abab457e 100644
--- a/contrib/all.sh
+++ b/contrib/all.sh
@@ -32,19 +32,18 @@ run_test() {
fi
}
-#cd "$(dirname -- "$0" || exit $?)"
-cd f:/build/floormat
+cd "$(dirname -- "$0" || exit $?)"
+#cd f:/build/floormat
#set -x
configurations='
-clang64 clang
-mingw64 gcc
-msvc64 msvc-debug
clang64 clang-asan
-
+msvc64 msvc-debug
+mingw64 gcc-debug
clang64 clang-release
-msvc64 msvc
+msvc64 msvc-release
mingw64 gcc-release
+clang64 clang-debug
'
printf "%s\\n" "$configurations" |
@@ -53,7 +52,7 @@ while read wrapper configs; do
(
cd $i
bprintf -- "***** Entering directory %s\\n" "$i"
- "$wrapper" cmake c:/repos/floormat >/dev/null
+ "$wrapper" cmake ../.. >/dev/null
if test $# -eq 0; then
printf -- "> Running ninja for %s\\n" "$i"
else
diff --git a/doc/render-wall-holes.pdn b/doc/render-wall-holes.pdn
new file mode 100644
index 00000000..eaf4ac8b
--- /dev/null
+++ b/doc/render-wall-holes.pdn
Binary files differ
diff --git a/draw/ground.cpp b/draw/ground.cpp
index 515729b1..b049f96d 100644
--- a/draw/ground.cpp
+++ b/draw/ground.cpp
@@ -13,6 +13,8 @@ void ground_mesh::draw(tile_shader& shader, chunk& c)
{
constexpr int quad_index_count = 6;
const auto [mesh_, ids, size] = c.ensure_ground_mesh();
+ if (size == 0)
+ return;
struct {
ground_atlas* atlas = nullptr; size_t pos = 0; } last;
GL::MeshView mesh{mesh_};
diff --git a/draw/wall.cpp b/draw/wall.cpp
index 1c9c80cc..cbe90b23 100644
--- a/draw/wall.cpp
+++ b/draw/wall.cpp
@@ -16,6 +16,9 @@ wall_mesh::wall_mesh() = default;
void wall_mesh::draw(tile_shader& shader, chunk& c)
{
const auto [mesh_, ids, size] = c.ensure_wall_mesh();
+ if (size == 0)
+ return;
+
struct { wall_atlas* atlas = nullptr; size_t pos = 0; } last;
GL::MeshView mesh{mesh_};
[[maybe_unused]] size_t draw_count = 0;
diff --git a/editor/app.hpp b/editor/app.hpp
index b04da7dc..800d3d10 100644
--- a/editor/app.hpp
+++ b/editor/app.hpp
@@ -108,11 +108,15 @@ private:
void draw() override;
- void on_mouse_move(const mouse_move_event& event) noexcept override;
- void on_mouse_up_down(const mouse_button_event& event, bool is_down) noexcept override;
- void on_mouse_scroll(const mouse_scroll_event& event) noexcept override;
- void on_key_up_down(const key_event& event, bool is_down) noexcept override;
- std::tuple<key, int> resolve_keybinding(int k, int mods);
+ [[nodiscard]] bool do_imgui_key(const sdl2::EvKey& ev, bool is_down);
+ [[nodiscard]] bool do_imgui_click(const sdl2::EvClick& ev, bool is_down);
+ [[nodiscard]] bool do_tests_key(const key_event& ev, bool is_down);
+
+ void on_mouse_move(const mouse_move_event& event, const sdl2::EvMove& ev) noexcept override;
+ void on_mouse_up_down(const mouse_button_event& event, bool is_down, const sdl2::EvClick& ev) noexcept override;
+ void on_mouse_scroll(const mouse_scroll_event& event, const sdl2::EvScroll& ev) noexcept override;
+ void on_key_up_down(const key_event& event, bool is_down, const sdl2::EvKey& ev) noexcept override;
+ Pair<key, int> resolve_keybinding(int k, int mods);
void on_text_input_event(const text_input_event& event) noexcept override;
//bool on_text_editing_event(const text_editing_event& event) noexcept override;
void on_viewport_event(const Magnum::Math::Vector2<int>& size) noexcept override;
diff --git a/editor/camera.cpp b/editor/camera.cpp
index 89147946..dfe985b4 100644
--- a/editor/camera.cpp
+++ b/editor/camera.cpp
@@ -102,15 +102,15 @@ object_id app::get_object_colliding_with_cursor()
object_id ret = 0;
rtree->Search(t0.data(), t1.data(), [&](uint64_t data, const rect_type& rect) {
[[maybe_unused]] auto x = std::bit_cast<collision_data>(data);
- if (x.tag == (uint64_t)collision_type::geometry)
+ if (x.type == (uint64_t)collision_type::geometry)
return true;
- Vector2 min(rect.m_min[0], rect.m_min[1]), max(rect.m_max[0], rect.m_max[1]);
+ Vector2 min{rect.m_min}, max{rect.m_max};
if (t0 >= min && t0 <= max)
{
- if (auto e_ = world.find_object(x.data);
+ if (auto e_ = world.find_object(x.id);
e_ && Vector2ui(e_->bbox_size).product() != 0)
{
- ret = x.data;
+ ret = x.id;
return false;
}
}
diff --git a/editor/draw.cpp b/editor/draw.cpp
index f5a906d2..b366deaa 100644
--- a/editor/draw.cpp
+++ b/editor/draw.cpp
@@ -139,11 +139,11 @@ void app::draw_collision_boxes()
if (x.tag == (uint64_t)collision_type::geometry)
return true;
#endif
- if (x.tag == (uint64_t)collision_type::geometry)
+ if (x.type == (uint64_t)collision_type::geometry)
if (x.pass == (uint64_t)pass_mode::pass)
- if (x.data < TILE_COUNT*2+1)
+ if (x.id < TILE_COUNT*2+1)
return true;
- Vector2 start(rect.m_min[0], rect.m_min[1]), end(rect.m_max[0], rect.m_max[1]);
+ Vector2 start{rect.m_min}, end{rect.m_max};
auto size = (end - start);
auto center = Vector3(start + size*.5f, 0.f);
shader.set_tint(x.pass == (uint64_t)pass_mode::pass ? pass_tint : tint);
@@ -186,11 +186,11 @@ void app::draw_collision_boxes()
if (x.tag == (uint64_t)collision_type::geometry)
return true;
#endif
- if (x.tag == (uint64_t)collision_type::geometry)
+ if (x.type == (uint64_t)collision_type::geometry)
if (x.pass == (uint64_t)pass_mode::pass)
- if (x.data < TILE_COUNT*2+1)
+ if (x.id < TILE_COUNT*2+1)
return true;
- Vector2 start(rect.m_min[0], rect.m_min[1]), end(rect.m_max[0], rect.m_max[1]);
+ Vector2 start{rect.m_min}, end{rect.m_max};
auto size = end - start;
auto center = Vector3(start + size*.5f, 0.f);
_wireframe->rect.draw(shader, { center, size, 3 });
diff --git a/editor/events.cpp b/editor/events.cpp
index 1a259d0e..6aaf1e70 100644
--- a/editor/events.cpp
+++ b/editor/events.cpp
@@ -2,29 +2,26 @@
#include "floormat/main.hpp"
#include "floormat/events.hpp"
+#include "main/sdl-fwd.inl"
#include "src/world.hpp"
#include "keys.hpp"
#include "editor.hpp"
#include "compat/enum-bitset.hpp"
-#include <tuple>
+#include <Corrade/Containers/Pair.h>
+#include <Corrade/Containers/StructuredBindings.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/ImGuiIntegration/Context.hpp>
namespace floormat {
-void app::on_focus_in() noexcept {}
-void app::on_mouse_enter() noexcept {}
-void app::on_any_event(const any_event&) noexcept {}
-
-#define accessor(type, name) \
- type m_##name = {}; auto name() const noexcept { return m_##name; }
+namespace {
-static constexpr int fixup_mods_(int mods, int value, int mask)
+constexpr int fixup_mods_(int mods, int value, int mask)
{
return !!(mods & mask) * value;
}
-static constexpr int fixup_mods(int mods)
+constexpr int fixup_mods(int mods)
{
int ret = 0;
ret |= fixup_mods_(mods, kmod_ctrl, KMOD_CTRL);
@@ -34,11 +31,49 @@ static constexpr int fixup_mods(int mods)
return ret;
}
+} // namespace
+
+
+using PointerButtons = Platform::Sdl2Application::Pointer;
+using PointerEvent = Platform::Sdl2Application::PointerEvent;
+using PointerMoveEvent = Platform::Sdl2Application::PointerMoveEvent;
+
+void app::on_focus_in() noexcept {}
+void app::on_mouse_enter() noexcept {}
+void app::on_any_event(const any_event&) noexcept {}
+
+#define accessor(type, name) \
+ type m_##name = {}; auto name() const noexcept { return m_##name; }
+
+bool app::do_imgui_key(const sdl2::EvKey& ev, bool is_down)
+{
+ if (is_down)
+ return _imgui->handleKeyPressEvent(ev.val);
+ else
+ return _imgui->handleKeyReleaseEvent(ev.val);
+}
+
+bool app::do_imgui_click(const sdl2::EvClick& ev, bool is_down)
+{
+ if (is_down)
+ return _imgui->handlePointerPressEvent(ev.val);
+ else
+ return _imgui->handlePointerReleaseEvent(ev.val);
+}
+
+bool app::do_tests_key(const key_event& ev, bool is_down)
+{
+ bool ret = _editor->mode() == editor_mode::tests;
+ if (ret)
+ return tests_handle_key(ev, is_down);
+ return ret;
+}
+
void app::clear_keys(key min_inclusive, key max_exclusive)
{
auto& keys = *keys_;
using key_type = std::decay_t<decltype(keys)>::value_type;
- for (key_type i = key_type(min_inclusive); i < key_type(max_exclusive); i++)
+ for (auto i = key_type(min_inclusive); i < key_type(max_exclusive); i++)
{
const auto idx = key(i);
keys[idx] = false;
@@ -52,61 +87,62 @@ void app::clear_keys()
key_modifiers = {};
}
-void app::on_mouse_move(const mouse_move_event& event) noexcept
+void app::on_mouse_move(const mouse_move_event& event, const sdl2::EvMove& ev) noexcept
{
- if (!(event.position >= Vector2i() && event.position < M->window_size()))
- return;
+ do
+ {
+ cursor.in_imgui = _imgui->handlePointerMoveEvent(ev.val);
+ if (cursor.in_imgui)
+ break;
+ if (_editor->mode() == editor_mode::tests)
+ {
+ (void)tests_handle_mouse_move(event);
+ break;
+ }
+ }
+ while (false);
- struct {
- accessor(Vector2i, position)
- } e = {event.position};
-
- if ((cursor.in_imgui = _imgui->handleMouseMoveEvent(e)))
- void();
- else if (_editor->mode() == editor_mode::tests && tests_handle_mouse_move(event))
- void();
- update_cursor_tile(event.position);
+ update_cursor_tile(Vector2i(event.position));
do_mouse_move(fixup_mods(event.mods));
}
-void app::on_mouse_up_down(const mouse_button_event& event, bool is_down) noexcept
+void app::on_mouse_up_down(const mouse_button_event& event, bool is_down, const sdl2::EvClick& ev) noexcept
{
- if (!(event.position >= Vector2i() && event.position < M->window_size()))
+ const auto p = Vector2i(event.position);
+
+ if (!(p >= Vector2i{} && p < M->window_size()))
return;
- struct ev {
- enum class Button : std::underlying_type_t<mouse_button> {
- Left = mouse_button_left,
- Right = mouse_button_right,
- Middle = mouse_button_middle,
- };
- accessor(Vector2i, position)
- accessor(Button, button)
- } e = {event.position, ev::Button(event.button)};
-
- if ((cursor.in_imgui = is_down ? _imgui->handleMousePressEvent(e) : _imgui->handleMouseReleaseEvent(e)))
- void();
- else if (_editor->mode() == editor_mode::tests && tests_handle_mouse_click(event, is_down))
- void();
- else
+ do
+ {
+ cursor.in_imgui = do_imgui_click(ev, is_down);
+ if (cursor.in_imgui)
+ break;
+ if (_editor->mode() == editor_mode::tests)
+ if (tests_handle_mouse_click(event, is_down))
+ break;
do_mouse_up_down(event.button, is_down, fixup_mods(event.mods));
+ }
+ while(false);
}
-void app::on_mouse_scroll(const mouse_scroll_event& event) noexcept
+void app::on_mouse_scroll(const mouse_scroll_event& event, const sdl2::EvScroll& ev) noexcept
{
- if (!(event.position >= Vector2i() && event.position < M->window_size()))
- return;
+ const auto p = Vector2i(event.position);
- struct {
- accessor(Vector2, offset)
- accessor(Vector2i, position)
- } e = {event.offset, event.position};
-
- if (!(cursor.in_imgui = _imgui->handleMouseScrollEvent(e)))
- do_mouse_scroll((int)e.offset()[1]);
+ do
+ {
+ if (p >= Vector2i() && p < M->window_size())
+ break;
+ cursor.in_imgui = _imgui->handleScrollEvent(ev.val);
+ if (cursor.in_imgui)
+ break;
+ do_mouse_scroll((int)ev.val.offset()[1]);
+ }
+ while (false);
}
-auto app::resolve_keybinding(int k_, int mods_) -> std::tuple<key, int>
+auto app::resolve_keybinding(int k_, int mods_) -> Pair<key, int>
{
[[maybe_unused]] constexpr int CTRL = kmod_ctrl;
[[maybe_unused]] constexpr int SHIFT = kmod_shift;
@@ -190,23 +226,13 @@ auto app::resolve_keybinding(int k_, int mods_) -> std::tuple<key, int>
void app::clear_non_global_keys() { clear_keys(key_MIN, key_GLOBAL); }
void app::clear_non_repeated_keys() { clear_keys(key_NO_REPEAT, key_COUNT); }
-void app::on_key_up_down(const key_event& event, bool is_down) noexcept
+void app::on_key_up_down(const key_event& event, bool is_down, const sdl2::EvKey& ev) noexcept
{
- using KeyEvent = Platform::Sdl2Application::KeyEvent;
- struct Ev
- {
- using Key = KeyEvent::Key;
- using Modifier = KeyEvent::Modifier;
- using Modifiers = KeyEvent::Modifiers;
- accessor(Key, key)
- accessor(Modifiers, modifiers)
- } e = {Ev::Key(event.key), Ev::Modifier(event.mods)};
-
auto [x, mods] = resolve_keybinding(event.key, event.mods);
static_assert(key_GLOBAL >= key_NO_REPEAT);
- if ((x == key_COUNT || x < key_GLOBAL) && (is_down ? _imgui->handleKeyPressEvent(e) : _imgui->handleKeyReleaseEvent(e)) ||
- (x == key_COUNT || x == key_escape) && _editor->mode() == editor_mode::tests && tests_handle_key(event, is_down))
+ if ((x == key_COUNT || x < key_GLOBAL) && do_imgui_key(ev, is_down) ||
+ (x == key_COUNT || x == key_escape) && do_tests_key(event, is_down))
clear_non_global_keys();
else if (x >= key_NO_REPEAT)
is_down && !event.is_repeated ? do_key(x, mods, event.key & ~SDLK_SCANCODE_MASK) : void();
diff --git a/editor/imgui-editors.cpp b/editor/imgui-editors.cpp
index 4e331bcf..1dfc18fc 100644
--- a/editor/imgui-editors.cpp
+++ b/editor/imgui-editors.cpp
@@ -114,7 +114,7 @@ void draw_editor_tile_pane_atlas(ground_editor& ed, StringView name, const bptr<
snformat(buf, "##item_{}"_cf, i);
const auto uv = atlas->texcoords_for_id(i);
constexpr ImVec2 size_2 = { TILE_SIZE[0]*.5f, TILE_SIZE[1]*.5f };
- ImGui::ImageButton(buf, (void*)&atlas->texture(), ImVec2(size_2.x * dpi[0], size_2.y * dpi[1]),
+ ImGui::ImageButton(buf, atlas->texture().id(), ImVec2(size_2.x * dpi[0], size_2.y * dpi[1]),
{ uv[3][0], uv[3][1] }, { uv[0][0], uv[0][1] });
if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
ed.select_tile(atlas, i);
@@ -181,7 +181,7 @@ void impl_draw_editor_scenery_pane(T& ed, Vector2 dpi)
const ImVec2 uv0 {texcoords[3][0], texcoords[3][1]}, uv1 {texcoords[0][0], texcoords[0][1]};
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + std::max(0.f, .5f*(thumbnail_width - img_size.x)));
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + .5f*std::max(0.f, row_height - img_size.y));
- ImGui::Image((void*)&atlas.texture(), img_size, uv0, uv1);
+ ImGui::Image(atlas.texture().id(), img_size, uv0, uv1);
click_event();
}
if (ImGui::TableSetColumnIndex(1))
diff --git a/editor/imgui-raii.cpp b/editor/imgui-raii.cpp
index dd341e2e..7c0ccb8c 100644
--- a/editor/imgui-raii.cpp
+++ b/editor/imgui-raii.cpp
@@ -1,6 +1,7 @@
#include "imgui-raii.hpp"
#include "compat/assert.hpp"
#include <cstdio>
+#include <utility>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Color.h>
diff --git a/editor/imgui.cpp b/editor/imgui.cpp
index 2923c3ea..e25edb1f 100644
--- a/editor/imgui.cpp
+++ b/editor/imgui.cpp
@@ -107,7 +107,7 @@ float app::draw_main_menu()
do_key(key_render_all_z_levels);
}
- main_menu_height = ImGui::GetContentRegionMax().y;
+ main_menu_height = ImGui::GetContentRegionAvail().y;
}
return main_menu_height;
}
@@ -312,7 +312,7 @@ void app::draw_lightmap_test(float main_menu_height)
if (ImGui::Begin("Lightmap", &is_open, flags))
{
- ImGui::Image(&shader.accum_texture(), preview_size, {0, 0}, {1, 1});
+ ImGui::Image(shader.accum_texture().id(), preview_size, {0, 0}, {1, 1});
ImGui::End();
}
else
@@ -338,7 +338,7 @@ void app::do_popup_menu()
{
const auto [id, target] = _popup_target;
auto& w = M->world();
- const auto eʹ = w.find_object(id);
+ auto eʹ = w.find_object(id);
if (target == popup_target_type::none || !eʹ)
{
@@ -372,7 +372,7 @@ void app::do_popup_menu()
if (!exists)
add_inspector(std::exchange(_popup_target, {}));
{
- char buf2[10], buf3[128], buf[sizeof buf2 + sizeof buf3 - 1];
+ char buf2[10], buf3[128], buf[sizeof buf2 + sizeof buf3 + 3 - 1];
entity_inspector_name(buf2, e.id);
entity_friendly_name(buf3, sizeof buf3, e);
std::snprintf(buf, sizeof buf, "%s###%s", buf3, buf2);
@@ -393,7 +393,7 @@ void app::do_popup_menu()
e.destroy_script_pre(eʹ, script_destroy_reason::kill);
e.chunk().remove_object(e.index());
e.destroy_script_post();
- e.gone = true;
+ eʹ.destroy();
}
}
else
diff --git a/editor/inspect-draw.cpp b/editor/inspect-draw.cpp
index d5474b8b..ce1e3396 100644
--- a/editor/inspect-draw.cpp
+++ b/editor/inspect-draw.cpp
@@ -33,7 +33,7 @@ void app::draw_inspector()
}
auto& e = *eʹ;
- char buf2[10], buf3[128], buf[sizeof buf2 + sizeof buf3 - 1];
+ char buf2[10], buf3[128], buf[sizeof buf2 + sizeof buf3 + 3 - 1];
ImGui::SetNextWindowSize({375*dpi[0], 0});
entity_inspector_name(buf2, e.id);
entity_friendly_name(buf3, sizeof buf3, e);
diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp
index da5a8c9f..ad621cd3 100644
--- a/editor/inspect-types.cpp
+++ b/editor/inspect-types.cpp
@@ -155,13 +155,11 @@ template<> struct entity_accessors<hole, inspect_intent_t>
E::type<uint8_t>::field{"height"_s,
&hole::height,
&hole::set_height,
- [](const hole& x) { return x.flags.is_wall ? st::enabled : st::readonly; },
constantly(constraints::range<uint8_t>{0, tile_size_z}),
},
E::type<uint8_t>::field{"z-offset"_s,
&hole::z_offset,
&hole::set_z_offset,
- [](const hole& x) { return x.flags.is_wall ? st::enabled : st::readonly; },
constantly(constraints::range<uint8_t>{0, tile_size_z}),
},
E::type<bool>::field{ "enabled"_s,
diff --git a/editor/inspect.cpp b/editor/inspect.cpp
index ab177fda..f6fcf980 100644
--- a/editor/inspect.cpp
+++ b/editor/inspect.cpp
@@ -5,6 +5,7 @@
#include "imgui-raii.hpp"
#include <cstdio>
#include <utility>
+#include <Corrade/Containers/StructuredBindings.h>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/String.h>
#include <Magnum/Math/Functions.h>
@@ -186,7 +187,7 @@ bool do_inspect_field(void* datum, const erased_accessor& accessor, field_repr r
{
auto* state = ImGui::GetInputTextState(GImGui->ActiveId);
if (state)
- state->ReloadUserBuf = true;
+ state->WantReloadUserBuf = true;
}
return true;
}
diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp
index 778a0275..7b95df9e 100644
--- a/editor/scenery-editor.cpp
+++ b/editor/scenery-editor.cpp
@@ -93,12 +93,13 @@ start:
while (auto id = a.get_object_colliding_with_cursor())
{
for (auto i = 0uz; i < sz; i++)
- if (const auto eʹ = es[i]; eʹ->id == id)
+ if (auto eʹ = es[i]; eʹ->id == id)
{
- eʹ->destroy_script_pre(eʹ, script_destroy_reason::kill);
+ auto& e = *eʹ;
+ e.destroy_script_pre(eʹ, script_destroy_reason::kill);
c.remove_object(i);
- eʹ->destroy_script_post();
- eʹ->gone = true;
+ e.destroy_script_post();
+ eʹ.destroy();
goto start;
}
break;
diff --git a/editor/tests/hole-test.cpp b/editor/tests/hole-test.cpp
index b419f7e8..06624b01 100644
--- a/editor/tests/hole-test.cpp
+++ b/editor/tests/hole-test.cpp
@@ -131,7 +131,7 @@ void hole_test::draw_ui(app&, float)
}
{
label_left("found", buf, label_width);
- ImGui::Text("%s", res.found ? "true" : "false");
+ ImGui::Text("%s", res.found() ? "true" : "false");
}
ImGui::Unindent(style.FramePadding.x);
diff --git a/editor/tests/raycast-test.cpp b/editor/tests/raycast-test.cpp
index 07b44eaf..a8902145 100644
--- a/editor/tests/raycast-test.cpp
+++ b/editor/tests/raycast-test.cpp
@@ -181,7 +181,7 @@ struct raycast_test final : base_test
{
const char* type;
- switch ((collision_type)result.collider.tag)
+ switch ((collision_type)result.collider.type)
{
using enum collision_type;
default: type = "unknown?!"; break;
@@ -199,7 +199,7 @@ struct raycast_test final : base_test
do_column("collider");
std::snprintf(buf, array_size(buf), "%s @ %" PRIu64,
- type, uint64_t{result.collider.data});
+ type, uint64_t{result.collider.id});
{ auto b = push_style_color(ImGuiCol_Text, 0xffff00ff_rgbaf);
text(buf);
}
diff --git a/editor/vobj-editor.cpp b/editor/vobj-editor.cpp
index 6dc8c907..7e7dde15 100644
--- a/editor/vobj-editor.cpp
+++ b/editor/vobj-editor.cpp
@@ -48,18 +48,20 @@ void vobj_editor::place_tile(world& w, global_coords pos, const vobj_* x, struct
if (!x)
{
auto [c, t] = w[pos];
+start:
const auto& es = c.objects();
-start: while (auto id = a.get_object_colliding_with_cursor())
+ while (auto id = a.get_object_colliding_with_cursor())
{
for (auto i = (int)(es.size()-1); i >= 0; i--)
{
- const auto eʹ = es[i];
- if (eʹ->id == id && eʹ->is_virtual())
+ auto eʹ = es[i];
+ auto& e = *eʹ;
+ if (e.id == id && eʹ->is_virtual())
{
- eʹ->destroy_script_pre(eʹ, script_destroy_reason::kill);
+ e.destroy_script_pre(eʹ, script_destroy_reason::kill);
c.remove_object((unsigned)i);
- eʹ->destroy_script_post();
- eʹ->gone = true;
+ e.destroy_script_post();
+ eʹ.destroy();
goto start;
}
}
diff --git a/entity/accessor.hpp b/entity/accessor.hpp
index 9dd9c3b6..22bef6e3 100644
--- a/entity/accessor.hpp
+++ b/entity/accessor.hpp
@@ -2,21 +2,11 @@
#include "util.hpp"
#include "erased-constraints.hpp"
#include "name-of.hpp"
-#include <type_traits>
+#include "field-status.hpp"
#include <Corrade/Containers/StringView.h>
-namespace floormat::erased_constraints {
-
-struct range;
-struct max_length;
-struct group;
-
-} // namespace floormat::erased_constraints
-
namespace floormat::entities {
-enum class field_status : unsigned char { hidden, readonly, enabled, COUNT, };
-
struct erased_accessor final {
using reader_t = void;
using writer_t = void;
@@ -40,7 +30,6 @@ struct erased_accessor final {
erased_constraints::max_length(*length_fun)(const Object*, const c_length_t*) = nullptr;
explicit constexpr erased_accessor() noexcept = default;
- constexpr erased_accessor(const erased_accessor&) = default;
constexpr erased_accessor(const reader_t* reader, const writer_t* writer, const predicate_t* predicate,
const c_range_t* range, const c_length_t* length,
StringView field_name, StringView object_name, StringView field_type_name,
diff --git a/entity/concepts.hpp b/entity/concepts.hpp
index 5e01fcda..6c13299c 100644
--- a/entity/concepts.hpp
+++ b/entity/concepts.hpp
@@ -3,7 +3,6 @@
#include "compat/function2.hpp"
#include "compat/assert.hpp"
#include <concepts>
-#include <type_traits>
namespace floormat::entities {
diff --git a/entity/constraints.hpp b/entity/constraints.hpp
index 6a5587d5..0bfc2f15 100644
--- a/entity/constraints.hpp
+++ b/entity/constraints.hpp
@@ -1,8 +1,7 @@
#pragma once
#include "compat/limits.hpp"
#include "erased-constraints.hpp"
-#include <type_traits>
-#include <utility>
+#include <cr/Pair.h>
#include <mg/Vector.h>
namespace floormat::entities::limit_detail {
@@ -52,7 +51,7 @@ template<typename T> struct range
T max = limit_detail::limit_traits<T>::max();
constexpr operator erased_constraints::range() const noexcept;
- constexpr operator std::pair<T, T>() const noexcept;
+ constexpr operator Pair<T, T>() const noexcept;
constexpr bool operator==(const range&) const noexcept = default;
};
@@ -125,7 +124,7 @@ template<typename T>
constexpr range<T>::operator erased_constraints::range() const noexcept
{ return erased_range_from_range(min, max); }
-template<typename T> constexpr range<T>::operator std::pair<T, T>() const noexcept { return { min, max }; }
+template<typename T> constexpr range<T>::operator Pair<T, T>() const noexcept { return { min, max }; }
template<> struct range<String> { constexpr operator erased_constraints::range() const noexcept { return {}; } };
template<> struct range<StringView> { constexpr operator erased_constraints::range() const noexcept { return {}; } };
diff --git a/entity/erased-constraints.cpp b/entity/erased-constraints.cpp
index 6e81820a..4cb915dc 100644
--- a/entity/erased-constraints.cpp
+++ b/entity/erased-constraints.cpp
@@ -2,17 +2,17 @@
#include "compat/assert.hpp"
#include <cmath>
#include <limits>
-#include <Magnum/Magnum.h>
-#include <Magnum/Math/Vector2.h>
-#include <Magnum/Math/Vector3.h>
-#include <Magnum/Math/Vector4.h>
+#include <cr/Pair.h>
+#include <mg/Vector2.h>
+#include <mg/Vector3.h>
+#include <mg/Vector4.h>
namespace floormat::entities::erased_constraints {
static_assert(sizeof(size_t) == sizeof(uintptr_t));
static_assert(sizeof(size_t) == sizeof(ptrdiff_t));
-template<typename T> std::pair<T, T> range::convert() const
+template<typename T> Pair<T, T> range::convert() const
{
static_assert(sizeof(T) <= sizeof(min));
@@ -103,7 +103,7 @@ template<typename T> std::pair<T, T> range::convert() const
}
}
-template<typename T> using pair2 = std::pair<T, T>;
+template<typename T> using pair2 = Pair<T, T>;
template pair2<uint8_t> range::convert() const;
template pair2<uint16_t> range::convert() const;
diff --git a/entity/erased-constraints.hpp b/entity/erased-constraints.hpp
index af050bd6..64b469a3 100644
--- a/entity/erased-constraints.hpp
+++ b/entity/erased-constraints.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include <utility>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Math/Vector4.h>
@@ -25,7 +26,7 @@ struct range final
element min, max;
type_ type = type_none;
- template<typename T> std::pair<T, T> convert() const;
+ template<typename T> Pair<T, T> convert() const;
friend bool operator==(const range& a, const range& b);
};
diff --git a/entity/field-status.hpp b/entity/field-status.hpp
new file mode 100644
index 00000000..f95d54ed
--- /dev/null
+++ b/entity/field-status.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace floormat::entities {
+
+enum class field_status : unsigned char { hidden, readonly, enabled, COUNT, };
+
+} // namespace floormat::entities
diff --git a/entity/field.hpp b/entity/field.hpp
new file mode 100644
index 00000000..02782651
--- /dev/null
+++ b/entity/field.hpp
@@ -0,0 +1,163 @@
+#pragma once
+
+#include "constraints.hpp"
+#include "concepts.hpp"
+#include "accessor.hpp"
+#include "field-status.hpp"
+#include "compat/defs.hpp"
+
+namespace floormat::entities::detail {
+template<typename Obj, typename Type, typename Default, size_t I, typename... Fs> struct find_reader;
+
+template<typename Obj, typename Type, typename Default, size_t I> struct find_reader<Obj, Type, Default, I> {
+ using type = Default;
+ static constexpr size_t index = I;
+};
+
+template<typename Obj, typename Type, typename Default, size_t I, typename F, typename... Fs>
+struct find_reader<Obj, Type, Default, I, F, Fs...> {
+ using type = typename find_reader<Obj, Type, Default, I+1, Fs...>::type;
+ static constexpr size_t index = find_reader<Obj, Type, Default, I+1, Fs...>::index;
+};
+
+template<typename Obj, typename Type, typename Default, size_t I, typename F, typename... Fs>
+requires FieldReader<F, Obj, Type>
+struct find_reader<Obj, Type, Default, I, F, Fs...> { using type = F; static constexpr size_t index = I; };
+
+} // namespace floormat::entities::detail
+
+namespace floormat::entities {
+
+constexpr auto constantly(const auto& x) noexcept {
+ return [x]<typename... Ts> (const Ts&...) constexpr -> const auto& { return x; };
+}
+
+template<typename Obj, typename Type> struct entity_field_base {};
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+struct entity_field : entity_field_base<Obj, Type> {
+private:
+ static constexpr auto default_predicate = constantly(field_status::enabled);
+ static constexpr auto default_c_range = constantly(constraints::range<Type>{});
+ static constexpr auto default_c_length = constantly(constraints::max_length{size_t(-1)});
+ using default_predicate_t = std::decay_t<decltype(default_predicate)>;
+ using default_c_range_t = std::decay_t<decltype(default_c_range)>;
+ using default_c_length_t = std::decay_t<decltype(default_c_length)>;
+ using c_predicate = detail::find_reader<Obj, field_status, default_predicate_t, 0, Ts...>;
+ using c_range = detail::find_reader<Obj, constraints::range<Type>, default_c_range_t, 0, Ts...>;
+ using c_length = detail::find_reader<Obj, constraints::max_length, default_c_length_t, 0, Ts...>;
+ static constexpr size_t good_arguments =
+ unsigned(c_predicate::index != sizeof...(Ts)) +
+ unsigned(c_range::index != sizeof...(Ts)) +
+ unsigned(c_length::index != sizeof...(Ts));
+ static_assert(sizeof...(Ts) == good_arguments, "ignored arguments");
+
+public:
+ using ObjectType = Obj;
+ using FieldType = Type;
+ using Reader = R;
+ using Writer = W;
+ using Predicate = typename c_predicate::type;
+ using Range = typename c_range::type;
+ using Length = typename c_length::type;
+
+ StringView name;
+ [[fm_no_unique_address]] R reader;
+ [[fm_no_unique_address]] W writer;
+ [[fm_no_unique_address]] Predicate predicate;
+ [[fm_no_unique_address]] Range range;
+ [[fm_no_unique_address]] Length length;
+
+ fm_DECLARE_DEFAULT_MOVE_COPY_ASSIGNMENTS(entity_field);
+
+ static constexpr decltype(auto) read(const R& reader, const Obj& x) { return detail::read_field<Obj, Type, R>::read(x, reader); }
+ static constexpr void write(const W& writer, Obj& x, Type v);
+ constexpr decltype(auto) read(const Obj& x) const { return read(reader, x); }
+ constexpr void write(Obj& x, Type value) const { write(writer, x, move(value)); }
+ static constexpr bool can_write = !std::is_same_v<std::nullptr_t, decltype(entity_field<Obj, Type, R, W, Ts...>::writer)>;
+
+ static constexpr field_status is_enabled(const Predicate & p, const Obj& x);
+ constexpr field_status is_enabled(const Obj& x) const { return is_enabled(predicate, x); }
+
+ static constexpr constraints::range<Type> get_range(const Range& r, const Obj& x);
+ constexpr constraints::range<Type> get_range(const Obj& x) const { return get_range(range, x); }
+ static constexpr constraints::max_length get_max_length(const Length& l, const Obj& x);
+ constexpr constraints::max_length get_max_length(const Obj& x) const { return get_max_length(length, x); }
+
+ constexpr entity_field(StringView name, R r, W w, Ts&&... ts) noexcept :
+ name{name}, reader{r}, writer{w},
+ predicate { std::get<c_predicate::index>(std::forward_as_tuple(ts..., default_predicate)) },
+ range { std::get<c_range::index> (std::forward_as_tuple(ts..., default_c_range)) },
+ length { std::get<c_length::index> (std::forward_as_tuple(ts..., default_c_length)) }
+ {}
+ constexpr erased_accessor erased() const;
+};
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr void entity_field<Obj, Type, R, W, Ts...>::write(const W& writer, Obj& x, Type v)
+{
+ static_assert(can_write); detail::write_field<Obj, Type, W>::write(x, writer, move(v));
+}
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr erased_accessor entity_field<Obj, Type, R, W, Ts...>::erased() const
+{
+ using reader_t = typename erased_accessor::reader_t;
+ using writer_t = typename erased_accessor::writer_t;
+ using predicate_t = typename erased_accessor::predicate_t;
+ using c_range_t = typename erased_accessor::c_range_t;
+ using c_length_t = typename erased_accessor::c_length_t;
+ constexpr auto obj_name = name_of<Obj>, field_name = name_of<Type>;
+
+ constexpr auto reader_fn = [](const void* obj, const reader_t* reader, void* value) {
+ const auto& obj_ = *static_cast<const Obj*>(obj);
+ const auto& reader_ = *static_cast<const R*>(reader);
+ auto& value_ = *static_cast<Type*>(value);
+ value_ = read(reader_, obj_);
+ };
+ constexpr auto writer_fn = [](void* obj, const writer_t* writer, void* value) {
+ auto& obj_ = *static_cast<Obj*>(obj);
+ const auto& writer_ = *static_cast<const W*>(writer);
+ Type value_ = move(*static_cast<Type*>(value));
+ write(writer_, obj_, move(value_));
+ };
+ constexpr auto predicate_fn = [](const void* obj, const predicate_t* predicate) {
+ const auto& obj_ = *static_cast<const Obj*>(obj);
+ const auto& predicate_ = *static_cast<const Predicate*>(predicate);
+ return is_enabled(predicate_, obj_);
+ };
+ constexpr auto writer_stub_fn = [](void*, const writer_t*, void*) {
+ fm_abort("no writer for this accessor");
+ };
+ constexpr bool has_writer = !std::is_same_v<std::decay_t<decltype(writer)>, std::nullptr_t>;
+
+ constexpr auto c_range_fn = [](const void* obj, const c_range_t* reader) -> erased_constraints::range {
+ return get_range(*static_cast<const Range*>(reader), *static_cast<const Obj*>(obj));
+ };
+ constexpr auto c_length_fn = [](const void* obj, const c_length_t* reader) -> erased_constraints::max_length {
+ return get_max_length(*static_cast<const Length*>(reader), *static_cast<const Obj*>(obj));
+ };
+ return erased_accessor {
+ (void*)&reader, has_writer ? (void*)&writer : nullptr,
+ (void*)&predicate,
+ (void*)&range, (void*)&length,
+ name, obj_name, field_name,
+ reader_fn, has_writer ? writer_fn : writer_stub_fn,
+ predicate_fn,
+ c_range_fn, c_length_fn,
+ };
+}
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr field_status entity_field<Obj, Type, R, W, Ts...>::is_enabled(const Predicate& p, const Obj& x)
+{ return detail::read_field<Obj, field_status, Predicate>::read(x, p); }
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr constraints::range<Type> entity_field<Obj, Type, R, W, Ts...>::get_range(const Range& r, const Obj& x)
+{ return detail::read_field<Obj, constraints::range<Type>, Range>::read(x, r); }
+
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr constraints::max_length entity_field<Obj, Type, R, W, Ts...>::get_max_length(const Length& l, const Obj& x)
+{ return detail::read_field<Obj, constraints::max_length , Length>::read(x, l); }
+
+} // namespace floormat::entities
diff --git a/entity/metadata.hpp b/entity/metadata.hpp
index 101af0df..8e3b41d3 100644
--- a/entity/metadata.hpp
+++ b/entity/metadata.hpp
@@ -1,28 +1,13 @@
#pragma once
#include "name-of.hpp"
#include "accessor.hpp"
-#include "constraints.hpp"
-#include "util.hpp"
+#include "field.hpp"
#include "concepts.hpp"
-#include "compat/defs.hpp"
-#include <type_traits>
-#include <concepts>
-#include <limits>
-#include <tuple>
+#include <utility>
#include <array>
#include <compat/function2.hpp>
#include <Corrade/Containers/StringView.h>
-namespace floormat::entities {
-
-struct inspect_intent_t {};
-struct serialize_intent_t {};
-struct report_intent_t {};
-
-template<typename T, typename Intent> struct entity_accessors;
-
-} // namespace floormat::entities
-
namespace floormat::entities::detail {
template<typename F, typename Tuple, size_t N>
@@ -55,158 +40,33 @@ template<typename T> struct decay_tuple_;
template<typename... Ts> struct decay_tuple_<std::tuple<Ts...>> { using type = std::tuple<std::decay_t<Ts>...>; };
template<typename T> using decay_tuple = typename decay_tuple_<T>::type;
-template<typename Obj, typename Type, typename Default, size_t I, typename... Fs> struct find_reader;
-
-template<typename Obj, typename Type, typename Default, size_t I> struct find_reader<Obj, Type, Default, I> {
- using type = Default;
- static constexpr size_t index = I;
-};
-
-template<typename Obj, typename Type, typename Default, size_t I, typename F, typename... Fs>
-struct find_reader<Obj, Type, Default, I, F, Fs...> {
- using type = typename find_reader<Obj, Type, Default, I+1, Fs...>::type;
- static constexpr size_t index = find_reader<Obj, Type, Default, I+1, Fs...>::index;
-};
-
-template<typename Obj, typename Type, typename Default, size_t I, typename F, typename... Fs>
-requires FieldReader<F, Obj, Type>
-struct find_reader<Obj, Type, Default, I, F, Fs...> { using type = F; static constexpr size_t index = I; };
-
} // namespace floormat::entities::detail
namespace floormat::entities {
-constexpr auto constantly(const auto& x) noexcept {
- return [x]<typename... Ts> (const Ts&...) constexpr -> const auto& { return x; };
-}
-
-template<typename Obj, typename Type> struct entity_field_base {};
-
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-struct entity_field : entity_field_base<Obj, Type> {
-private:
- static constexpr auto default_predicate = constantly(field_status::enabled);
- static constexpr auto default_c_range = constantly(constraints::range<Type>{});
- static constexpr auto default_c_length = constantly(constraints::max_length{size_t(-1)});
- using default_predicate_t = std::decay_t<decltype(default_predicate)>;
- using default_c_range_t = std::decay_t<decltype(default_c_range)>;
- using default_c_length_t = std::decay_t<decltype(default_c_length)>;
- using c_predicate = detail::find_reader<Obj, field_status, default_predicate_t, 0, Ts...>;
- using c_range = detail::find_reader<Obj, constraints::range<Type>, default_c_range_t, 0, Ts...>;
- using c_length = detail::find_reader<Obj, constraints::max_length, default_c_length_t, 0, Ts...>;
- static constexpr size_t good_arguments =
- unsigned(c_predicate::index != sizeof...(Ts)) +
- unsigned(c_range::index != sizeof...(Ts)) +
- unsigned(c_length::index != sizeof...(Ts));
- static_assert(sizeof...(Ts) == good_arguments, "ignored arguments");
-
-public:
- using ObjectType = Obj;
- using FieldType = Type;
- using Reader = R;
- using Writer = W;
- using Predicate = typename c_predicate::type;
- using Range = typename c_range::type;
- using Length = typename c_length::type;
-
- StringView name;
- [[fm_no_unique_address]] R reader;
- [[fm_no_unique_address]] W writer;
- [[fm_no_unique_address]] Predicate predicate;
- [[fm_no_unique_address]] Range range;
- [[fm_no_unique_address]] Length length;
-
- fm_DECLARE_DEFAULT_MOVE_COPY_ASSIGNMENTS(entity_field);
-
- static constexpr decltype(auto) read(const R& reader, const Obj& x) { return detail::read_field<Obj, Type, R>::read(x, reader); }
- static constexpr void write(const W& writer, Obj& x, Type v);
- constexpr decltype(auto) read(const Obj& x) const { return read(reader, x); }
- constexpr void write(Obj& x, Type value) const { write(writer, x, move(value)); }
- static constexpr bool can_write = !std::is_same_v<std::nullptr_t, decltype(entity_field<Obj, Type, R, W, Ts...>::writer)>;
-
- static constexpr field_status is_enabled(const Predicate & p, const Obj& x);
- constexpr field_status is_enabled(const Obj& x) const { return is_enabled(predicate, x); }
-
- static constexpr constraints::range<Type> get_range(const Range& r, const Obj& x);
- constexpr constraints::range<Type> get_range(const Obj& x) const { return get_range(range, x); }
- static constexpr constraints::max_length get_max_length(const Length& l, const Obj& x);
- constexpr constraints::max_length get_max_length(const Obj& x) const { return get_max_length(length, x); }
-
- constexpr entity_field(StringView name, R r, W w, Ts&&... ts) noexcept :
- name{name}, reader{r}, writer{w},
- predicate { std::get<c_predicate::index>(std::forward_as_tuple(ts..., default_predicate)) },
- range { std::get<c_range::index> (std::forward_as_tuple(ts..., default_c_range)) },
- length { std::get<c_length::index> (std::forward_as_tuple(ts..., default_c_length)) }
- {}
- constexpr erased_accessor erased() const;
-};
-
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-constexpr void entity_field<Obj, Type, R, W, Ts...>::write(const W& writer, Obj& x, Type v)
+template<typename F, typename Tuple>
+constexpr void visit_tuple(F&& fun, Tuple&& tuple)
{
- static_assert(can_write); detail::write_field<Obj, Type, W>::write(x, writer, move(v));
+ using Size = std::tuple_size<std::decay_t<Tuple>>;
+ if constexpr(Size() > 0)
+ detail::visit_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
}
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-constexpr erased_accessor entity_field<Obj, Type, R, W, Ts...>::erased() const
+template<typename F, typename Tuple>
+constexpr bool find_in_tuple(F&& fun, Tuple&& tuple)
{
- using reader_t = typename erased_accessor::reader_t;
- using writer_t = typename erased_accessor::writer_t;
- using predicate_t = typename erased_accessor::predicate_t;
- using c_range_t = typename erased_accessor::c_range_t;
- using c_length_t = typename erased_accessor::c_length_t;
- constexpr auto obj_name = name_of<Obj>, field_name = name_of<Type>;
-
- constexpr auto reader_fn = [](const void* obj, const reader_t* reader, void* value) {
- const auto& obj_ = *static_cast<const Obj*>(obj);
- const auto& reader_ = *static_cast<const R*>(reader);
- auto& value_ = *static_cast<Type*>(value);
- value_ = read(reader_, obj_);
- };
- constexpr auto writer_fn = [](void* obj, const writer_t* writer, void* value) {
- auto& obj_ = *static_cast<Obj*>(obj);
- const auto& writer_ = *static_cast<const W*>(writer);
- Type value_ = move(*static_cast<Type*>(value));
- write(writer_, obj_, move(value_));
- };
- constexpr auto predicate_fn = [](const void* obj, const predicate_t* predicate) {
- const auto& obj_ = *static_cast<const Obj*>(obj);
- const auto& predicate_ = *static_cast<const Predicate*>(predicate);
- return is_enabled(predicate_, obj_);
- };
- constexpr auto writer_stub_fn = [](void*, const writer_t*, void*) {
- fm_abort("no writer for this accessor");
- };
- constexpr bool has_writer = !std::is_same_v<std::decay_t<decltype(writer)>, std::nullptr_t>;
-
- constexpr auto c_range_fn = [](const void* obj, const c_range_t* reader) -> erased_constraints::range {
- return get_range(*static_cast<const Range*>(reader), *reinterpret_cast<const Obj*>(obj));
- };
- constexpr auto c_length_fn = [](const void* obj, const c_length_t* reader) -> erased_constraints::max_length {
- return get_max_length(*static_cast<const Length*>(reader), *reinterpret_cast<const Obj*>(obj));
- };
- return erased_accessor {
- (void*)&reader, has_writer ? (void*)&writer : nullptr,
- (void*)&predicate,
- (void*)&range, (void*)&length,
- name, obj_name, field_name,
- reader_fn, has_writer ? writer_fn : writer_stub_fn,
- predicate_fn,
- c_range_fn, c_length_fn,
- };
+ using Size = std::tuple_size<std::decay_t<Tuple>>;
+ if constexpr(Size() > 0)
+ return detail::find_in_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
+ else
+ return false;
}
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-constexpr field_status entity_field<Obj, Type, R, W, Ts...>::is_enabled(const Predicate& p, const Obj& x)
-{ return detail::read_field<Obj, field_status, Predicate>::read(x, p); }
-
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-constexpr constraints::range<Type> entity_field<Obj, Type, R, W, Ts...>::get_range(const Range& r, const Obj& x)
-{ return detail::read_field<Obj, constraints::range<Type>, Range>::read(x, r); }
+struct inspect_intent_t {};
+struct serialize_intent_t {};
+struct report_intent_t {};
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
-constexpr constraints::max_length entity_field<Obj, Type, R, W, Ts...>::get_max_length(const Length& l, const Obj& x)
-{ return detail::read_field<Obj, constraints::max_length , Length>::read(x, l); }
+template<typename T, typename Intent> struct entity_accessors;
template<typename Obj>
struct Entity final {
@@ -228,24 +88,6 @@ struct Entity final {
};
};
-template<typename F, typename Tuple>
-constexpr void visit_tuple(F&& fun, Tuple&& tuple)
-{
- using Size = std::tuple_size<std::decay_t<Tuple>>;
- if constexpr(Size() > 0)
- detail::visit_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
-}
-
-template<typename F, typename Tuple>
-constexpr bool find_in_tuple(F&& fun, Tuple&& tuple)
-{
- using Size = std::tuple_size<std::decay_t<Tuple>>;
- if constexpr(Size() > 0)
- return detail::find_in_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
- else
- return false;
-}
-
constexpr inline auto ignored_write = []<typename O, typename T>(O&, T) {};
} // namespace floormat::entities
@@ -264,6 +106,8 @@ public:
static constexpr auto accessors = entities::entity_accessors<T, Intent>::accessors();
static constexpr size_t size = std::tuple_size_v<std::decay_t<decltype(accessors)>>;
static constexpr auto erased_accessors = erased_helper(accessors, std::make_index_sequence<size>{});
+
+ entity_metadata() = default;
};
template<typename T, typename Intent>
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index e258fa87..303afda2 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -237,9 +237,7 @@ set(system "")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25)
set(system "SYSTEM")
endif()
-if(NOT FLOORMAT_SUBMODULE-DEPENDENCIES OR NOT FLOORMAT_SUBMODULE-SDL2)
- add_subdirectory(sdl2 ${system})
-endif()
+
if(FLOORMAT_SUBMODULE-DEPENDENCIES)
sets(PATH IMGUI_DIR "${CMAKE_CURRENT_SOURCE_DIR}/imgui")
@@ -270,19 +268,6 @@ if(FLOORMAT_SUBMODULE-DEPENDENCIES)
install(TARGETS benchmark RUNTIME DESTINATION "bin")
endfunction()
- function(fm_add_luajit)
- set(CMAKE_C_STANDARD 11)
- set(CMAKE_C_EXTENSIONS 1)
- unset(CMAKE_C_VISIBILITY_PRESET)
- unset(CMAKE_VISIBILITY_INLINES_HIDDEN)
- if(CMAKE_COMPILER_IS_GNUCXX)
- # HACK
- add_compile_options(-fno-sanitize=all)
- add_link_options(-fno-sanitize=all)
- add_subdirectory(luajit ${system})
- endif()
- endfunction()
-
fm_run_hook(fm-userconfig-external)
function(fm_add_libs)
@@ -297,7 +282,6 @@ if(FLOORMAT_SUBMODULE-DEPENDENCIES)
fm_add_benchmark()
endif()
fm_add_sdl2()
- #fm_add_luajit()
if(MSVC)
add_compile_options(-GR-)
else()
diff --git a/external/benchmark b/external/benchmark
-Subproject b40db869451036d222d155bc8cd6420c2fb9527
+Subproject b884717437fc468929cd47ca6a374005357ff18
diff --git a/external/corrade b/external/corrade
-Subproject 1bc62dcd1430d93070343dc0d32b6a7db359ecb
+Subproject 76d9b27792c1b4ff948a84870b34f805be08da4
diff --git a/external/fmt b/external/fmt
-Subproject 6159e2b0ab58e6e22164272d22e929cbc9e34e2
+Subproject f2cec917dafffa45d5cb4573c68fdf706e2b541
diff --git a/external/imgui b/external/imgui
-Subproject c554c402d307e6fde50e895adad009e23343ed2
+Subproject 2d20e13746c05bfe36d4a57ac465e7a9fe9005d
diff --git a/external/luajit b/external/luajit
deleted file mode 160000
-Subproject 0a29d98f56c1efe1c731c3da22e871e6ccb79d2
diff --git a/external/magnum b/external/magnum
-Subproject 4dd86be6376275c0620d2470c2038f331462702
+Subproject 2af1aa24ab92b9fe92a79b8b2ba697ed20c668e
diff --git a/external/magnum-integration b/external/magnum-integration
-Subproject bf09698491f2061733dc263f375da1f02f41d8e
+Subproject ed2730d95836fdcbdbb659c5c070bcde2eb0717
diff --git a/external/magnum-plugins b/external/magnum-plugins
-Subproject 9a46ddaf4e7702954c76c12ff00cf9e15fc7b61
+Subproject 790d645741f4be0ce898691a8c9a99c2d9a5c8e
diff --git a/external/robin-map b/external/robin-map
-Subproject 3bf03fdc4f71f86b496bb73a4fda6034e44fdb8
+Subproject e662db269a48da97fdc480072519cd94b51ece4
diff --git a/external/sdl2 b/external/sdl2
-Subproject a29f37c14abc2ae418e770353657e872a70d90b
+Subproject 28472738857ff194b5b6b8778a1975cb605210a
diff --git a/floormat/app.hpp b/floormat/app.hpp
index 02f7d24c..9d1ac7e3 100644
--- a/floormat/app.hpp
+++ b/floormat/app.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include "main/sdl-fwd.hpp"
namespace Magnum::Math { template<typename T> class Vector2; template<class T> class Nanoseconds; }
@@ -35,10 +36,10 @@ struct floormat_app
virtual void draw() = 0;
virtual z_bounds get_z_bounds() = 0;
- virtual void on_mouse_move(const mouse_move_event& event) noexcept = 0;
- virtual void on_mouse_up_down(const mouse_button_event& event, bool is_down) noexcept = 0;
- virtual void on_mouse_scroll(const mouse_scroll_event& event) noexcept = 0;
- virtual void on_key_up_down(const key_event& event, bool is_down) noexcept = 0;
+ virtual void on_mouse_move(const mouse_move_event& event, const sdl2::EvMove& ev) noexcept = 0;
+ virtual void on_mouse_up_down(const mouse_button_event& event, bool is_down, const sdl2::EvClick& ev) noexcept = 0;
+ virtual void on_mouse_scroll(const mouse_scroll_event& event, const sdl2::EvScroll& ev) noexcept = 0;
+ virtual void on_key_up_down(const key_event& event, bool is_down, const sdl2::EvKey& ev) noexcept = 0;
virtual void on_text_input_event(const text_input_event& event) noexcept = 0;
//virtual bool on_text_editing_event(const text_editing_event& event) noexcept = 0;
virtual void on_viewport_event(const Magnum::Math::Vector2<int>& size) noexcept = 0;
diff --git a/floormat/events.hpp b/floormat/events.hpp
index 68c2bedd..af3e6248 100644
--- a/floormat/events.hpp
+++ b/floormat/events.hpp
@@ -14,22 +14,25 @@ enum mouse_button : unsigned char {
};
struct mouse_button_event final {
- Vector2i position;
+ Vector2 position;
int mods = 0;
mouse_button button = mouse_button_none;
uint8_t click_count = 0;
+ bool is_primary : 1 = false;
};
struct mouse_move_event final {
- Vector2i position;
- mouse_button buttons = mouse_button_none;
+ Vector2 position;
int mods = 0;
+ mouse_button buttons = mouse_button_none;
+ bool is_primary : 1 = false;
};
struct mouse_scroll_event final {
Magnum::Vector2 offset;
- Vector2i position;
+ Vector2 position;
int mods = 0;
+ bool is_primary : 1 = false;
};
struct text_input_event final {
diff --git a/hash/xxhash.cpp b/hash/xxhash.cpp
index 157232b9..59691baf 100644
--- a/hash/xxhash.cpp
+++ b/hash/xxhash.cpp
@@ -6,6 +6,8 @@
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
+#elif defined _MSC_VER
+#pragma warning(disable: 4310)
#endif
#include "xxhash.inl"
diff --git a/main/events.cpp b/main/events.cpp
index 1f1c81a2..59dfe28e 100644
--- a/main/events.cpp
+++ b/main/events.cpp
@@ -1,84 +1,102 @@
#include "main-impl.hpp"
#include "floormat/app.hpp"
#include "floormat/events.hpp"
+#include "sdl-fwd.inl"
#include <cstring>
#include <SDL_events.h>
#include <SDL_keyboard.h>
namespace floormat {
-void main_impl::viewportEvent(Platform::Sdl2Application::ViewportEvent& event)
+namespace {
+
+using Buttons = Platform::Sdl2Application::Pointers;
+
+mouse_button pointer_to_button_mask(Buttons b) { return mouse_button((uint8_t)b); }
+
+any_event make_any_event(const SDL_Event& e)
+{
+ static_assert(sizeof(SDL_Event) <= sizeof(any_event::buf));
+ any_event ret;
+ std::memcpy(&ret.buf, &e, sizeof(SDL_Event));
+ return ret;
+}
+
+} // namespace
+
+void main_impl::viewportEvent(ViewportEvent& event)
{
_framebuffer_size = event.framebufferSize();
recalc_viewport(event.framebufferSize(), event.windowSize());
app.on_viewport_event(event.framebufferSize());
}
-void main_impl::mousePressEvent(Platform::Sdl2Application::MouseEvent& event)
+void main_impl::pointerPressEvent(PointerEvent& ev)
{
- app.on_mouse_up_down({event.position() * _virtual_scale,
- (SDL_Keymod)(uint16_t)event.modifiers(),
- mouse_button(SDL_BUTTON((uint8_t)event.button())),
- uint8_t(std::min(255, event.clickCount()))},
- true);
+ app.on_mouse_up_down({
+ ev.position() * _virtual_scale,
+ (SDL_Keymod)(uint16_t)ev.modifiers(),
+ pointer_to_button_mask(ev.pointer()),
+ uint8_t(std::min(255, ev.clickCount())),
+ }, true, {ev});
}
-void main_impl::mouseReleaseEvent(Platform::Sdl2Application::MouseEvent& event)
+void main_impl::pointerReleaseEvent(PointerEvent& ev)
{
- app.on_mouse_up_down({event.position() * _virtual_scale,
- (SDL_Keymod)(uint16_t)event.modifiers(),
- mouse_button(SDL_BUTTON((uint8_t)event.button())),
- uint8_t(std::min(255, event.clickCount()))},
- false);
+ app.on_mouse_up_down({
+ ev.position() * _virtual_scale,
+ (SDL_Keymod)(uint16_t)ev.modifiers(),
+ pointer_to_button_mask(ev.pointer()),
+ uint8_t(std::min(255, ev.clickCount())),
+ }, false, {ev});
}
-void main_impl::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent& event)
+void main_impl::pointerMoveEvent(PointerMoveEvent& ev)
{
- app.on_mouse_move({event.position() * _virtual_scale,
- (mouse_button)(uint8_t)uint32_t{event.buttons()},
- (SDL_Keymod)(uint16_t)event.modifiers()});
+ app.on_mouse_move({
+ ev.position() * _virtual_scale,
+ (SDL_Keymod)(uint16_t)ev.modifiers(),
+ pointer_to_button_mask(ev.pointers()),
+ ev.isPrimary(),
+ }, {ev});
}
-void main_impl::mouseScrollEvent(Platform::Sdl2Application::MouseScrollEvent& event)
+void main_impl::scrollEvent(ScrollEvent& ev)
{
- app.on_mouse_scroll({event.offset(), event.position() * _virtual_scale,
- (SDL_Keymod)(uint16_t)event.modifiers()});
+ app.on_mouse_scroll({
+ ev.offset(), ev.position() * _virtual_scale,
+ (SDL_Keymod)(uint16_t)ev.modifiers(),
+ }, {ev});
}
-void main_impl::textInputEvent(Platform::Sdl2Application::TextInputEvent& event)
+void main_impl::textInputEvent(TextInputEvent& event)
{
app.on_text_input_event({event.text()});
}
#if 0
-void main_impl::textEditingEvent(Platform::Sdl2Application::TextEditingEvent& event)
+void main_impl::textEditingEvent(TextEditingEvent& event)
{
app.on_text_editing_event({event.text(), event.start(), event.length()})
}
#endif
-void main_impl::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
-{
- app.on_key_up_down({(SDL_Keycode)(uint32_t)event.key(),
- (SDL_Keymod)(uint16_t)event.modifiers(),
- event.isRepeated()},
- true);
-}
-
-void main_impl::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
+void main_impl::keyPressEvent(KeyEvent& event)
{
- app.on_key_up_down({(SDL_Keycode)(uint32_t)event.key(),
- (SDL_Keymod)(uint16_t)event.modifiers(),
- event.isRepeated()},
- false);
+ app.on_key_up_down({
+ (SDL_Keycode)(uint32_t)event.key(),
+ (SDL_Keymod)(uint16_t)event.modifiers(),
+ event.isRepeated()
+ }, true, {event});
}
-static any_event make_any_event(const SDL_Event& e)
+void main_impl::keyReleaseEvent(KeyEvent& event)
{
- static_assert(sizeof(SDL_Event) <= sizeof(any_event::buf));
- any_event ret;
- std::memcpy(&ret.buf, &e, sizeof(SDL_Event));
- return ret;
+ app.on_key_up_down({
+ (SDL_Keycode)(uint32_t)event.key(),
+ (SDL_Keymod)(uint16_t)event.modifiers(),
+ event.isRepeated()
+ }, false, {event});
}
void main_impl::anyEvent(SDL_Event& event)
@@ -108,7 +126,7 @@ void main_impl::anyEvent(SDL_Event& event)
int floormat_main::get_mods() noexcept
{
- return (int)SDL_GetModState();
+ return SDL_GetModState();
}
} // namespace floormat
diff --git a/main/main-impl.hpp b/main/main-impl.hpp
index 3fb8bac5..17aecc72 100644
--- a/main/main-impl.hpp
+++ b/main/main-impl.hpp
@@ -9,6 +9,7 @@
#include "shaders/texture-unit-cache.hpp"
#include "shaders/shader.hpp"
#include "shaders/lightmap.hpp"
+#include "main/sdl-fwd.hpp"
#include "main/clickable.hpp"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/String.h>
@@ -76,10 +77,10 @@ struct main_impl final : private Platform::Sdl2Application, public floormat_main
const Platform::Sdl2Application& application() const noexcept override;
[[maybe_unused]] void viewportEvent(ViewportEvent& event) override;
- [[maybe_unused]] void mousePressEvent(MouseEvent& event) override;
- [[maybe_unused]] void mouseReleaseEvent(MouseEvent& event) override;
- [[maybe_unused]] void mouseMoveEvent(MouseMoveEvent& event) override;
- [[maybe_unused]] void mouseScrollEvent(MouseScrollEvent& event) override;
+ [[maybe_unused]] void pointerPressEvent(PointerEvent& ev) override;
+ [[maybe_unused]] void pointerReleaseEvent(PointerEvent& ev) override;
+ [[maybe_unused]] void pointerMoveEvent(PointerMoveEvent& ev) override;
+ [[maybe_unused]] void scrollEvent(ScrollEvent& ev) override;
[[maybe_unused]] void textInputEvent(TextInputEvent& event) override;
//[[maybe_unused]] void textEditingEvent(TextEditingEvent& event) override;
[[maybe_unused]] void keyPressEvent(KeyEvent& event) override;
diff --git a/main/sdl-fwd.hpp b/main/sdl-fwd.hpp
new file mode 100644
index 00000000..776ec0a8
--- /dev/null
+++ b/main/sdl-fwd.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+namespace floormat::sdl2 {
+
+struct EvButtons;
+struct EvClick;
+struct EvMove;
+struct EvScroll;
+struct EvKey;
+
+} // namespace floormat::sdl2
diff --git a/main/sdl-fwd.inl b/main/sdl-fwd.inl
new file mode 100644
index 00000000..25bc45ee
--- /dev/null
+++ b/main/sdl-fwd.inl
@@ -0,0 +1,15 @@
+#pragma once
+#include "sdl-fwd.hpp"
+#include <Magnum/Platform/Sdl2Application.h>
+
+namespace floormat::sdl2 {
+
+using App = Platform::Sdl2Application;
+
+struct EvButtons { App::Pointer& val; };
+struct EvClick { App::PointerEvent& val; };
+struct EvMove { App::PointerMoveEvent& val; };
+struct EvScroll { App::ScrollEvent& val; };
+struct EvKey { App::KeyEvent& val; };
+
+} // namespace floormat::sdl2
diff --git a/run-show-coverage.sh b/run-show-coverage.sh
index 9b5f6974..f2fe844e 100644
--- a/run-show-coverage.sh
+++ b/run-show-coverage.sh
@@ -108,7 +108,8 @@ if test $run -gt 0; then
Windows_NT) profdir="$(cygpath -m -- "$PWD")" ;;
*) profdir="$PWD" ;;
esac
- LLVM_PROFILE_FILE="$profdir/${prof}.profraw" "$exe" --gpu-debug full --vsync on
+ LLVM_PROFILE_FILE="$profdir/${prof}.profraw" \
+ "$exe" --magnum-gpu-validation=full --vsync=1
fi
if test $generate -gt 0; then
diff --git a/shaders/shader.hpp b/shaders/shader.hpp
index 7f58e276..5eb384c5 100644
--- a/shaders/shader.hpp
+++ b/shaders/shader.hpp
@@ -37,7 +37,7 @@ struct tile_shader final : private GL::AbstractShaderProgram
template<typename T = float> static constexpr Math::Vector2<T> project(const Math::Vector3<T>& pt);
template<typename T = float> static constexpr Math::Vector2<T> unproject(const Math::Vector2<T>& px);
- template<typename T, typename... Xs> decltype(auto) draw(GL::AbstractTexture& tex, T&& mesh, Xs&&... xs);
+ template<typename T, typename... Xs> GL::AbstractShaderProgram& draw(GL::AbstractTexture& tex, T&& mesh, Xs&&... xs);
static constexpr Vector2s max_screen_tiles = {8, 8};
static constexpr float character_depth_offset = 1 + 2./64;
@@ -74,7 +74,7 @@ private:
};
template<typename T, typename... Xs>
-decltype(auto) tile_shader::draw(GL::AbstractTexture& tex, T&& mesh, Xs&&... xs)
+GL::AbstractShaderProgram& tile_shader::draw(GL::AbstractTexture& tex, T&& mesh, Xs&&... xs)
{
draw_pre(tex);
decltype(auto) ret = GL::AbstractShaderProgram::draw(forward<T>(mesh), forward<Xs>(xs)...);
diff --git a/src/RTree-fwd.h b/src/RTree-fwd.h
index a93ec168..e5bcb35e 100644
--- a/src/RTree-fwd.h
+++ b/src/RTree-fwd.h
@@ -1,5 +1,12 @@
#pragma once
+#include "object-id.hpp"
template<class DATATYPE, class ELEMTYPE, int NUMDIMS,
class ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2>
class RTree;
+
+namespace floormat {
+
+using Chunk_RTree = ::RTree<object_id, float, 2, float>;
+
+} // namespace floormat
diff --git a/src/RTree.cpp b/src/RTree.cpp
index f77d0697..fcefdbcf 100644
--- a/src/RTree.cpp
+++ b/src/RTree.cpp
@@ -64,8 +64,7 @@ template<typename T> T* rtree_pool<T>::construct()
template<typename T> void rtree_pool<T>::free(T* ptr)
{
ptr->~T();
- node_p p = {.ptr = ptr };
- node_u* n = p.data_ptr;
+ auto* n = reinterpret_cast<node_u*>(ptr);
n->next = free_list;
free_list = n;
}
diff --git a/src/RTree.h b/src/RTree.h
index 7b8eeb7c..bbf9a486 100644
--- a/src/RTree.h
+++ b/src/RTree.h
@@ -37,13 +37,9 @@ template<typename T> struct rtree_pool final
void free(T* pool);
union node_u {
- union { T data; };
+ union { T data; char _empty = {}; };
node_u* next;
};
- union node_p {
- T* ptr;
- node_u* data_ptr;
- };
private:
node_u* free_list = nullptr;
diff --git a/src/anim-atlas.cpp b/src/anim-atlas.cpp
index 43ba69b2..ee05987f 100644
--- a/src/anim-atlas.cpp
+++ b/src/anim-atlas.cpp
@@ -11,12 +11,14 @@
namespace floormat {
+namespace {
+constexpr inline char name_array[][3] = { "n", "ne", "e", "se", "s", "sw", "w", "nw", };
+constexpr inline auto rot_count = size_t(rotation_COUNT);
+} // namespace
+
template class bptr<anim_atlas>;
template class bptr<const anim_atlas>;
-static constexpr const char name_array[][3] = { "n", "ne", "e", "se", "s", "sw", "w", "nw", };
-static constexpr inline auto rot_count = size_t(rotation_COUNT);
-
static_assert(array_size(name_array) == rot_count);
static_assert(rot_count == 8);
diff --git a/src/anim.cpp b/src/anim.cpp
index 717b3ee6..db724154 100644
--- a/src/anim.cpp
+++ b/src/anim.cpp
@@ -1,6 +1,7 @@
#include "anim.hpp"
#include "compat/exception.hpp"
#include <cmath>
+#include <utility>
namespace floormat {
diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp
index ec6f4ff2..b0170755 100644
--- a/src/chunk-collision.cpp
+++ b/src/chunk-collision.cpp
@@ -10,6 +10,7 @@
#include "src/hole.hpp"
#include "src/wall-atlas.hpp"
#include <bit>
+#include <utility>
#include <Corrade/Containers/StructuredBindings.h>
#include <Corrade/Containers/Pair.h>
@@ -17,7 +18,7 @@ namespace floormat {
bool collision_data::operator==(const collision_data&) const noexcept = default;
bool chunk::bbox::operator==(const floormat::chunk::bbox& other) const noexcept = default;
-chunk::RTree* chunk::rtree() noexcept { ensure_passability(); return &*_rtree; }
+Chunk_RTree* chunk::rtree() noexcept { ensure_passability(); return &*_rtree; }
world& chunk::world() noexcept { return *_world; }
namespace {
@@ -34,7 +35,7 @@ constexpr object_id make_id(collision_type type, pass_mode p, object_id id)
}
template<bool IsNeighbor>
-bool add_holes_from_chunk(chunk::RTree& rtree, chunk& c, Vector2b chunk_offset)
+bool add_holes_from_chunk(Chunk_RTree& rtree, chunk& c, Vector2b chunk_offset)
{
bool has_holes = false;
constexpr auto chunk_size = iTILE_SIZE2 * TILE_MAX_DIM;
@@ -65,47 +66,22 @@ bool add_holes_from_chunk(chunk::RTree& rtree, chunk& c, Vector2b chunk_offset)
return has_holes;
}
-#if 1
-CORRADE_NEVER_INLINE
-bool find_hole_in_bbox(CutResult<float>::rect& hole, chunk::RTree& rtree, Vector2 min, Vector2 max)
-{
- bool ret = true;
- rtree.Search(min.data(), max.data(), [&](uint64_t data, const chunk::RTree::Rect& r) {
- auto x = std::bit_cast<collision_data>(data);
- if (x.pass == (uint64_t)pass_mode::pass && x.tag == (uint64_t)collision_type::none)
- {
- CutResult<float>::rect holeʹ {
- .min = { r.m_min[0], r.m_min[1] },
- .max = { r.m_max[0], r.m_max[1] },
- };
- if (rect_intersects(holeʹ.min, holeʹ.max, min, max))
- {
- hole = holeʹ;
- return ret = false;
- }
- }
- return true;
- });
- return ret;
-}
-
-CORRADE_NEVER_INLINE
-void filter_through_holes(chunk::RTree& rtree, object_id id, Vector2 min, Vector2 max, bool has_holes)
+void filter_through_holes(Chunk_RTree& rtree, object_id id, Vector2 min, Vector2 max, bool has_holes)
{
if (!has_holes)
return rtree.Insert(min.data(), max.data(), id);
start:
- fm_assert(min != max); // todo!
+ fm_assert(min != max);
CutResult<float>::rect hole;
- bool ret = find_hole_in_bbox(hole, rtree, min, max);
+ bool ret = chunk::find_hole_in_bbox(hole, rtree, min, max);
if (ret) [[likely]]
rtree.Insert(min.data(), max.data(), id);
else
{
auto res = CutResult<float>::cut(min, max, hole.min, hole.max);
- if (!res.found)
+ if (!res.found())
{
rtree.Insert(min.data(), max.data(), id);
}
@@ -117,19 +93,40 @@ start:
}
else
{
- for (auto i = 0uz; i < res.size; i++)
+ for (auto i = 0u; i < res.size; i++)
filter_through_holes(rtree, id, res.array[i].min, res.array[i].max, has_holes);
}
}
}
-#else
-void filter_through_holes(chunk::RTree& rtree, object_id id, Vector2 min, Vector2 max, bool)
+
+} // namespace
+
+#if 1
+bool chunk::find_hole_in_bbox(CutResult<float>::rect& hole, const Chunk_RTree& rtree, Vector2 min, Vector2 max)
{
- rtree.Insert(min.data(), max.data(), id);
+ bool ret = true;
+ rtree.Search(min.data(), max.data(), [&](uint64_t data, const Chunk_RTree::Rect& r) {
+ auto x = std::bit_cast<collision_data>(data);
+ if (x.pass == (uint64_t)pass_mode::pass && x.type == (uint64_t)collision_type::none)
+ {
+ CutResult<float>::rect holeʹ {
+ .min = { r.m_min[0], r.m_min[1] },
+ .max = { r.m_max[0], r.m_max[1] },
+ };
+ if (rect_intersects(holeʹ.min, holeʹ.max, min, max))
+ {
+ hole = holeʹ;
+ return ret = false;
+ }
+ }
+ return true;
+ });
+ return ret;
}
+#else
+bool chunk::find_hole_in_bbox(CutResult<float>::rect&, Chunk_RTree&, Vector2, Vector2) { return true; }
#endif
-
-} // namespace
+bool chunk::find_hole_in_bbox(CutResult<float>::rect& hole, Vector2 min, Vector2 max) { return find_hole_in_bbox(hole, *rtree(), min, max); }
void chunk::ensure_passability() noexcept
{
@@ -143,15 +140,16 @@ void chunk::ensure_passability() noexcept
//Debug{} << ".. reset passability" << _coord;
bool has_holes = false;
+ auto& rtree = *_rtree;
{
- has_holes |= add_holes_from_chunk<false>(*_rtree, *this, {});
+ has_holes |= add_holes_from_chunk<false>(rtree, *this, {});
const auto nbs = _world->neighbors(_coord);
for (auto i = 0u; i < 8; i++)
if (nbs[i])
- has_holes |= add_holes_from_chunk<true>(*_rtree, *nbs[i], world::neighbor_offsets[i]);
+ has_holes |= add_holes_from_chunk<true>(rtree, *nbs[i], world::neighbor_offsets[i]);
}
- for (auto i = 0uz; i < TILE_COUNT; i++)
+ for (auto i = 0u; i < TILE_COUNT; i++)
{
if (const auto* atlas = ground_atlas_at(i))
{
@@ -160,29 +158,29 @@ void chunk::ensure_passability() noexcept
if (pass == pass_mode::pass) [[likely]]
continue;
auto id = make_id(collision_type::geometry, pass, i+1);
- filter_through_holes(*_rtree, id, min, max, has_holes);
+ filter_through_holes(rtree, id, min, max, has_holes);
}
}
- for (auto i = 0uz; i < TILE_COUNT; i++)
+ for (auto i = 0u; i < TILE_COUNT; i++)
{
auto tile = operator[](i);
if (const auto* atlas = tile.wall_north_atlas().get())
{
auto [min, max] = wall_north(i, (float)atlas->info().depth);
auto id = make_id(collision_type::geometry, atlas->info().passability, TILE_COUNT+i+1);
- filter_through_holes(*_rtree, id, min, max, has_holes);
+ filter_through_holes(rtree, id, min, max, has_holes);
if (tile.wall_west_atlas())
{
auto [min, max] = wall_pillar(i, (float)atlas->info().depth);
- filter_through_holes(*_rtree, id, min, max, has_holes);
+ filter_through_holes(rtree, id, min, max, has_holes);
}
}
if (const auto* atlas = tile.wall_west_atlas().get())
{
auto [min, max] = wall_west(i, (float)atlas->info().depth);
auto id = make_id(collision_type::geometry, atlas->info().passability, TILE_COUNT*2+i+1);
- filter_through_holes(*_rtree, id, min, max, has_holes);
+ filter_through_holes(rtree, id, min, max, has_holes);
}
}
for (const bptr<object>& eʹ : objects())
@@ -193,7 +191,7 @@ void chunk::ensure_passability() noexcept
if (_bbox_for_scenery(*eʹ, bb))
{
if (!eʹ->is_dynamic())
- filter_through_holes(*_rtree, std::bit_cast<object_id>(bb.data), Vector2(bb.start), Vector2(bb.end), has_holes);
+ filter_through_holes(rtree, std::bit_cast<object_id>(bb.data), Vector2(bb.start), Vector2(bb.end), has_holes);
else
_add_bbox_dynamic(bb);
}
diff --git a/src/chunk-region.cpp b/src/chunk-region.cpp
index 3c5a8746..ed978c0f 100644
--- a/src/chunk-region.cpp
+++ b/src/chunk-region.cpp
@@ -119,10 +119,10 @@ auto default_region_predicate(chunk& c) noexcept
return [&c](collision_data data) {
auto x = std::bit_cast<collision_data>(data);
// XXX 'scenery' is used for all object types
- if (x.tag == (uint64_t)collision_type::scenery)
+ if (x.type == (uint64_t)collision_type::scenery)
{
auto& w = c.world();
- auto obj = w.find_object(x.data);
+ auto obj = w.find_object(x.id);
if (obj->type() == object_type::critter)
return path_search_continue::pass;
}
diff --git a/src/chunk-render.cpp b/src/chunk-render.cpp
index 529d4f64..0c5d5bc6 100644
--- a/src/chunk-render.cpp
+++ b/src/chunk-render.cpp
@@ -52,9 +52,15 @@ auto chunk::ensure_ground_mesh() noexcept -> ground_mesh_tuple
if (_ground->atlases[i])
_ground->indexes[count++] = uint8_t(i);
+ if (count == 0)
+ {
+ ground_mesh = GL::Mesh{NoCreate};
+ return { ground_mesh, {}, 0 };
+ }
+
std::sort(_ground->indexes.begin(), _ground->indexes.begin() + count,
[this](uint8_t a, uint8_t b) {
- return _ground->atlases[a] < _ground->atlases[b];
+ return _ground->atlases[a].get() < _ground->atlases[b].get();
});
float hack_offset = _coord.z <= 0 ? -16.f : 0.f; // XXX hack
diff --git a/src/chunk-scenery.cpp b/src/chunk-scenery.cpp
index 2e491d4d..e928abac 100644
--- a/src/chunk-scenery.cpp
+++ b/src/chunk-scenery.cpp
@@ -64,6 +64,8 @@ auto make_topo_sort_data(object& e, uint32_t mesh_idx) -> topo_sort_data
return data;
}
+// todo! switch to using a stack as in https://www.geeksforgeeks.org/topological-sorting/
+
void topo_dfs(Array<chunk::object_draw_order>& array, size_t& output, size_t i, size_t size) // NOLINT(misc-no-recursion)
{
using m = typename chunk::topo_sort_data::m;
@@ -177,13 +179,18 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce
i++;
}
- GL::Mesh mesh{GL::MeshPrimitive::Triangles};
- auto vert_view = ArrayView<const std::array<vertex, 4>>{scenery_vertexes, count};
- auto index_view = ArrayView<const std::array<UnsignedShort, 6>>{scenery_indexes, count};
- mesh.addVertexBuffer(GL::Buffer{vert_view}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{})
- .setIndexBuffer(GL::Buffer{index_view}, 0, GL::MeshIndexType::UnsignedShort)
- .setCount(int32_t(6 * count));
- scenery_mesh = move(mesh);
+ if (count == 0)
+ scenery_mesh = GL::Mesh{NoCreate};
+ else
+ {
+ GL::Mesh mesh{GL::MeshPrimitive::Triangles};
+ auto vert_view = ArrayView<const std::array<vertex, 4>>{scenery_vertexes, count};
+ auto index_view = ArrayView<const std::array<UnsignedShort, 6>>{scenery_indexes, count};
+ mesh.addVertexBuffer(GL::Buffer{vert_view}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{})
+ .setIndexBuffer(GL::Buffer{index_view}, 0, GL::MeshIndexType::UnsignedShort)
+ .setCount(int32_t(6 * count));
+ scenery_mesh = move(mesh);
+ }
}
const auto size = _objects.size();
diff --git a/src/chunk-walls.cpp b/src/chunk-walls.cpp
index fb4b6560..39faf0bd 100644
--- a/src/chunk-walls.cpp
+++ b/src/chunk-walls.cpp
@@ -2,11 +2,15 @@
#include "tile-bbox.hpp"
#include "quads.hpp"
#include "wall-atlas.hpp"
+#include "tile-bbox.hpp"
+#include "compat/unroll.hpp"
+#include "RTree-search.hpp"
#include "shaders/shader.hpp"
-#include <Corrade/Containers/ArrayViewStl.h>
-#include <Corrade/Containers/Pair.h>
-#include <Corrade/Containers/Optional.h>
+#include <cr/ArrayViewStl.h>
+#include <cr/GrowableArray.h>
+#include <cr/Optional.h>
#include <utility>
+#include <concepts>
#include <algorithm>
#include <ranges>
@@ -30,116 +34,232 @@ wall_atlas* chunk::wall_atlas_at(size_t i) const noexcept
namespace {
+using Wall::Group;
using Wall::Group_;
using Wall::Direction_;
+using Wall::Frame;
+
+template<typename T> using Vec2_ = VectorTypeFor<2, T>;
+template<typename T> using Vec3_ = VectorTypeFor<3, T>;
+
+template<typename F, size_t N>
+struct minmax_v
+{
+ VectorTypeFor<N, F> min, max;
+};
-constexpr Quads::quad get_quad(Direction_ D, Group_ G, float depth)
+struct quad_table_entry
{
- CORRADE_ASSUME(D < Direction_::COUNT);
- CORRADE_ASSUME(G < Group_::COUNT);
- constexpr Vector2 half_tile = TILE_SIZE2*.5f;
- constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z();
- const bool is_west = D == Wall::Direction_::W;
+ bool x : 1, y : 1, z : 1, dmx :1 = false, dmy : 1 = false, _fuzz : 3 = false;
+};
+static_assert(sizeof(quad_table_entry) == sizeof(uint8_t));
+template<bool IsWest>
+constexpr std::array<quad_table_entry, 4> make_quad_table_entry(Group_ G)
+{
fm_assert(G < Group_::COUNT);
+
+ constexpr bool x0 = false, x1 = true,
+ y0 = false, y1 = true,
+ z0 = false, z1 = true;
+ constexpr bool t = true, f = false;
+
switch (G)
{
using enum Group_;
case COUNT: std::unreachable();
case wall:
- if (!is_west)
+ if (!IsWest)
return {{
- { X, -Y, 0 },
- { X, -Y, Z },
- {-X, -Y, 0 },
- {-X, -Y, Z },
+ { x1, y0, z0 },
+ { x1, y0, z1 },
+ { x0, y0, z0 },
+ { x0, y0, z1 },
}};
else
return {{
- {-X, -Y, 0 },
- {-X, -Y, Z },
- {-X, Y, 0 },
- {-X, Y, Z },
+ { x0, y0, z0 },
+ { x0, y0, z1 },
+ { x0, y1, z0 },
+ { x0, y1, z1 },
}};
case side:
- if (!is_west)
+ if (!IsWest)
return {{
- { X, -Y - depth, 0 },
- { X, -Y - depth, Z },
- { X, -Y, 0 },
- { X, -Y, Z },
+ { x1, y0, z0, f, t },
+ { x1, y0, z1, f, t },
+ { x1, y0, z0 },
+ { x1, y0, z1 },
}};
else
return {{
- { -X, Y, 0 },
- { -X, Y, Z },
- { -X - depth, Y, 0 },
- { -X - depth, Y, Z },
+ { x0, y1, z0 },
+ { x0, y1, z1 },
+ { x0, y1, z0, t, f },
+ { x0, y1, z1, t, f },
}};
case top:
- if (!is_west)
+ if (!IsWest)
return {{
- { -X, -Y - depth, Z },
- { X, -Y - depth, Z },
- { -X, -Y, Z },
- { X, -Y, Z },
+ { x0, y0, z1, f, t },
+ { x1, y0, z1, f, t },
+ { x0, y0, z1 },
+ { x1, y0, z1 },
}};
else
return {{
- { -X, -Y, Z },
- { -X, Y, Z },
- { -X - depth, -Y, Z },
- { -X - depth, Y, Z },
+ { x0, y0, z1 },
+ { x0, y1, z1 },
+ { x0, y0, z1, t, f },
+ { x0, y1, z1, t, f },
}};
case corner:
- if (!is_west)
+ if (!IsWest)
return {{
- {-X, -Y, 0 },
- {-X, -Y, Z },
- {-X - depth, -Y, 0 },
- {-X - depth, -Y, Z },
+ { x0, y0, z0 },
+ { x0, y0, z1 },
+ { x0, y0, z0, t, f },
+ { x0, y0, z1, t, f },
}};
else
return {{
- {-X, -Y - depth, 0 },
- {-X, -Y - depth, Z },
- {-X, -Y, 0 },
- {-X, -Y, Z },
+ { x0, y0, z0, f, t },
+ { x0, y0, z1, f, t },
+ { x0, y0, z0 },
+ { x0, y0, z1 },
}};
}
std::unreachable();
}
-Array<Quads::indexes> make_indexes_()
+template<Group_ G, bool IsWest, typename F = float>
+constexpr auto get_quadʹ(minmax_v<F, 3> bounds, F d)
{
- auto array = Array<Quads::indexes>{NoInit, chunk::max_wall_quad_count };
- for (auto i = 0uz; i < chunk::max_wall_quad_count; i++)
- array[i] = Quads::quad_indexes(i);
+ F x[2] { bounds.min.x(), bounds.max.x() },
+ y[2] { bounds.min.y(), bounds.max.y() },
+ z[2] { bounds.min.z(), bounds.max.z() },
+ dmx[2] { 0, d },
+ dmy[2] { 0, d };
+
+ std::array<Vec3_<F>, 4> array = {};
+
+ unroll<static_array_size<decltype(array)>>([&]<typename Index>(Index) {
+ constexpr size_t i = Index::value;
+ constexpr auto table = make_quad_table_entry<IsWest>(G);
+ constexpr auto e = table[i];
+ array.data()[i] = { x[e.x] - dmx[e.dmx], y[e.y] - dmy[e.dmy], z[e.z], };
+ });
+
return array;
}
-ArrayView<const Quads::indexes> make_indexes(size_t max)
+template<Group_ G, bool IsWest, typename F = float>
+constexpr CORRADE_ALWAYS_INLINE auto get_quad(F d)
+{
+ constexpr auto half_tile = Vec2_<F>(TILE_SIZE2*.5f);
+ constexpr auto X = half_tile.x(), Y = half_tile.y(), Z = F(TILE_SIZE.z());
+
+ return get_quadʹ<G, IsWest, F>({ { -X, -Y, 0, }, { X, Y, Z, }, }, d);
+}
+
+template<bool IsWest>
+CutResult<Int>::rect get_wall_rect(local_coords tile)
{
- static const auto indexes = make_indexes_();
- fm_assert(max <= chunk::max_wall_quad_count);
- return indexes.prefix(max);
+ constexpr auto nʹ = wall_north<Int>(0, 0), wʹ = wall_west<Int>(0, 0);
+ constexpr auto t0 = !IsWest ? nʹ.first() : wʹ.first(),
+ t1 = !IsWest ? nʹ.second() : wʹ.second();
+ const auto offset = Vector2i{tile} * iTILE_SIZE2;
+ const auto min = offset + t0, max = offset + t1;
+ return { min, max };
}
-constexpr float depth_offset_for_group(Group_ G, bool is_west)
+template<bool IsWest, std::invocable<Vector2, Vector2> F>
+void cut_holes_in_wall(chunk& c, local_coords tile, Vector2i min, Vector2i max, F&& fun)
{
- CORRADE_ASSUME(G < Group_::COUNT);
- float p = is_west ? tile_shader::wall_west_offset : 0;
+ CutResult<float>::rect hole;
+
+ //constexpr auto eps = Vector2{.125f};
+ if (c.find_hole_in_bbox(hole, Vector2(min) /*- eps*/, Vector2(max) /*+ eps*/))
+ {
+ fun(min, max);
+ }
+ else
+ {
+ fm_assert(Vector2(Vector2i(hole.min)) == hole.min);
+ fm_assert(Vector2(Vector2i(hole.max)) == hole.max);
+ auto res = CutResult<Int>::cut(min, max, Vector2i(hole.min), Vector2i(hole.max));
+ if (!res.found())
+ {
+ fun(min, max);
+ }
+ else
+ {
+ for (auto i = 0u; i < res.size; i++)
+ {
+ const auto [min, max] = res.array[i];
+ cut_holes_in_wall<IsWest>(c, tile, min, max, fun);
+ }
+ }
+ }
+}
+
+struct quad_tuple
+{
+ Vector2ui tex_pos, tex_size;
+ Vector2i min, max;
+};
+
+template<bool IsWest>
+quad_tuple get_wall_quad_stuff(const CutResult<Int>::rect& geom, const CutResult<Int>::rect& orig,
+ Vector2ui orig_tex_pos, Vector2ui orig_tex_size)
+{
+ return {};
+}
+
+ArrayView<const Quads::indexes> make_indexes(uint32_t count)
+{
+ static auto arrayʹ = [] {
+ auto array = Array<Quads::indexes>{};
+ arrayReserve(array, 64);
+ return array;
+ }();
+ auto& array = arrayʹ;
+ auto i = (uint32_t)array.size();
+ if (count > i) [[unlikely]]
+ {
+ arrayResize(array, NoInit, count);
+ for (; i < count; i++)
+ array.data()[i] = Quads::quad_indexes(i);
+ }
+ return array.prefix(count);
+}
+
+Array<std::array<chunk::vertex, 4>>& make_vertexes()
+{
+ static auto array = [] {
+ Array<std::array<chunk::vertex, 4>> array;
+ arrayReserve(array, 32);
+ return array;
+ }();
+ return array;
+}
+
+template<Group_ G, bool IsWest>
+constexpr float depth_offset_for_group()
+{
+ static_assert(G < Group_::COUNT);
+ float p = IsWest ? tile_shader::wall_west_offset : 0;
switch (G)
{
default:
return tile_shader::wall_depth_offset + p;
- case Wall::Group_::corner:
- case Wall::Group_::side:
+ case Group_::corner:
+ case Group_::side:
return tile_shader::wall_side_offset + p;
}
}
-Wall::Frame variant_from_frame(ArrayView<const Wall::Frame> frames, global_coords coord, variant_t variant, bool is_west)
+Frame variant_from_frame(ArrayView<const Frame> frames, global_coords coord, variant_t variant, bool is_west)
{
auto sz = (unsigned)frames.size();
if (variant == (variant_t)-1)
@@ -148,168 +268,183 @@ Wall::Frame variant_from_frame(ArrayView<const Wall::Frame> frames, global_coord
return frames[variant];
}
-} // namespace
+constexpr std::array<chunk::vertex, 4>& alloc_wall_vertexes(uint32_t& N, auto& V, auto& M, uint32_t k)
+{
+ constexpr uint32_t reserve = 15, mask = ~reserve;
+ const auto i = N, sz = ++N + reserve & mask;
+ fm_assert(uint32_t{(UnsignedShort)sz} == sz);
+ arrayResize(V, NoInit, sz);
+ arrayResize(M, NoInit, sz);
+ M[i] = (uint16_t)k;
+ return V[i];
+};
-GL::Mesh chunk::make_wall_mesh()
+template<Group_ G, bool IsWest>
+void do_wall_part(const Group& group, wall_atlas& A, chunk& c, chunk::wall_stuff& W,
+ Array<std::array<chunk::vertex, 4>>& vertexes,
+ global_coords coord, uint32_t& N, uint32_t tile)
{
- fm_debug_assert(_walls);
- uint32_t N = 0;
+ if (!group.is_defined)
+ return;
- static auto vertexes = Array<std::array<vertex, 4>>{NoInit, max_wall_quad_count };
+ const uint32_t k = tile*2 + IsWest;
+ constexpr auto D = IsWest ? Direction_::W : Direction_::N;
+ const auto variant_2 = W.variants[k];
+ const auto pos = local_coords{tile};
+ const auto center = Vector3(pos) * TILE_SIZE;
+ const auto& dir = A.calc_direction(D);
+ const auto Depth = A.info().depth;
- for (uint32_t k = 0; k < 2*TILE_COUNT; k++)
+ if constexpr(G == Group_::side) [[unlikely]]
{
- const bool is_west = k & 1;
- const auto D = is_west ? Wall::Direction_::W : Wall::Direction_::N;
- const auto& atlas = _walls->atlases[k];
- if (!atlas)
- continue;
- const auto variant_2 = _walls->variants[k];
- const auto pos = local_coords{k / 2u};
- const auto center = Vector3(pos) * TILE_SIZE;
- const auto& dir = atlas->calc_direction(D);
- const auto coord = global_coords{_coord, pos};
- const auto Depth = atlas->info().depth;
-
- for (auto [s, member, G] : Wall::Direction::groups_for_draw)
- {
- CORRADE_ASSUME(G < Group_::COUNT);
-
- bool side_ok = G == Wall::Group_::side;
+ bool corner_ok = false, pillar_ok = false;
- if (!(dir.*member).is_defined)
- continue;
-
- if (G == Wall::Group_::side) [[unlikely]]
+ if constexpr(!IsWest)
+ {
+ if (auto t = c.at_offset(pos, {-1, 0}); !(t && t->wall_north_atlas()))
{
- bool corner_ok = false, pillar_ok = false;
-
- if (!is_west)
- {
- if (auto t = at_offset_(pos, {-1, 0}); !(t && t->wall_north_atlas()))
- {
- if (_walls->atlases[k+1]) // west on same tile
- pillar_ok = true;
- if (auto t = at_offset_(pos, {0, -1}); t && t->wall_west_atlas())
- corner_ok = true;
- }
- if (side_ok)
- if (auto t = at_offset_(pos, {1, -1}); t && t->wall_west_atlas())
- side_ok = false;
- if (side_ok)
- if (auto t = at_offset_(pos, {1, -1}); t && t->wall_west_atlas())
- side_ok = false;
- }
- else
- {
- if (auto t = at_offset_(pos, {0, -1}); !(t && t->wall_west_atlas()))
- if (auto t = at_offset_(pos, {-1, 0}); t && t->wall_north_atlas())
- corner_ok = true;
- if (side_ok)
- if (auto t = at_offset_(pos, {-1, 1}); t && t->wall_north_atlas())
- side_ok = false;
- }
-
- if (pillar_ok) [[unlikely]]
- {
- if (dir.top.is_defined)
- {
- const auto frames = atlas->frames(dir.top);
- const auto frame = variant_from_frame(frames, coord, variant_2, is_west);
- constexpr Vector2 half_tile = TILE_SIZE2*.5f;
- constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z();
- Quads::quad quad = {{
- { -X - Depth, -Y - Depth, Z },
- { -X, -Y - Depth, Z },
- { -X - Depth, -Y, Z },
- { -X, -Y, Z }
- }};
- fm_assert(frame.size.x() == Depth);
- fm_assert(frame.size.y() >= Depth);
- auto start = frame.offset + Vector2ui{0, frame.size.y()} - Vector2ui{0, Depth};
- const auto texcoords = Quads::texcoords_at(start, Vector2ui{Depth, Depth}, atlas->image_size());
- const auto i = N++;
- fm_assert(i < vertexes.size());
- _walls->mesh_indexes[i] = (uint16_t)k;
- const auto depth_offset = depth_offset_for_group(Group_::top, is_west);
- const auto depth = tile_shader::depth_value(pos, depth_offset);
- auto& v = vertexes[i];
- for (auto& v : quad)
- v += center;
- for (uint8_t j = 0; j < 4; j++)
- v[j] = { quad[j], texcoords[j], depth };
- }
- }
- if (corner_ok) [[unlikely]]
- {
- if (dir.corner.is_defined)
- {
- const auto frames = atlas->frames(dir.corner);
- const auto depth_offset = depth_offset_for_group(Group_::corner, is_west);
- const auto pos_x = !is_west ? (float)pos.x : (float)pos.x - 1;
- const auto depth = tile_shader::depth_value(pos_x, pos.y, depth_offset);
- const auto& frame = variant_from_frame(frames, coord, variant_2, is_west);
- const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size());
- const auto i = N++;
- fm_assert(i < vertexes.size());
- _walls->mesh_indexes[i] = (uint16_t)k;
- auto& v = vertexes[i];
- auto quad = get_quad(D, Group_::corner, (float)Depth);
- for (auto& v : quad)
- v += center;
- for (uint8_t j = 0; j < 4; j++)
- v[j] = { quad[j], texcoords[j], depth };
- }
- else if (dir.wall.is_defined) [[likely]]
- {
- const auto frames = atlas->frames(dir.wall);
- const auto depth_offset = depth_offset_for_group(Group_::corner, is_west);
- const auto depth = tile_shader::depth_value(!is_west ? (float)pos.x : (float)pos.x - 1, depth_offset);
- const auto frame = variant_from_frame(frames, coord, variant_2, is_west);
- fm_assert(frame.size.x() > Depth);
- auto start = frame.offset + Vector2ui{frame.size.x(), 0} - Vector2ui{Depth, 0};
- const auto texcoords = Quads::texcoords_at(start, {Depth, frame.size.y()}, atlas->image_size());
- const auto i = N++;
- fm_assert(i < vertexes.size());
- _walls->mesh_indexes[i] = (uint16_t)k;
- auto& v = vertexes[i];
- auto quad = get_quad(D, Group_::corner, (float)Depth);
- for (auto& v : quad)
- v += center;
- for (uint8_t j = 0; j < 4; j++)
- v[j] = { quad[j], texcoords[j], depth };
- }
- }
+ if (W.atlases[k + 1]) // west on same tile
+ pillar_ok = true;
+ if (auto t = c.at_offset(pos, {0, -1}); t && t->wall_west_atlas())
+ corner_ok = true;
}
+ }
+ else
+ {
+ if (auto t = c.at_offset(pos, {0, -1}); !(t && t->wall_west_atlas()))
+ if (auto t = c.at_offset(pos, {-1, 0}); t && t->wall_north_atlas())
+ corner_ok = true;
+ }
- if (G != Wall::Group_::side || side_ok) [[likely]]
+ if (pillar_ok) [[unlikely]]
+ {
+ if (dir.top.is_defined)
{
- const auto& group = dir.*member;
- const auto frames = atlas->frames(group);
-
- const auto i = N++;
- fm_assert(i < vertexes.size());
- _walls->mesh_indexes[i] = (uint16_t)k;
- const auto frame = variant_from_frame(frames, coord, variant_2, is_west);
- const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size());
- const auto depth_offset = depth_offset_for_group(G, is_west);
+ const auto frames = A.frames(dir.top);
+ const auto frame = variant_from_frame(frames, coord, variant_2, IsWest);
+ constexpr Vector2 half_tile = TILE_SIZE2 * .5f;
+ constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z();
+ const auto Depthʹ = (float)(int)Depth;
+ Quads::quad quad = {{
+ {-X - Depthʹ, -Y - Depthʹ, Z},
+ {-X, -Y - Depthʹ, Z},
+ {-X - Depthʹ, -Y, Z},
+ {-X, -Y, Z},
+ }};
+ fm_assert(frame.size.x() == Depth);
+ fm_assert(frame.size.y() >= Depth);
+ auto start = frame.offset + Vector2ui{0, frame.size.y()} - Vector2ui{0, Depth};
+ const auto texcoords = Quads::texcoords_at(start, Vector2ui{Depth, Depth}, A.image_size());
+ const auto depth_offset = depth_offset_for_group<Group_::top, IsWest>();
const auto depth = tile_shader::depth_value(pos, depth_offset);
- auto quad = get_quad(D, G, (float)Depth);
for (auto& v : quad)
v += center;
- auto& v = vertexes[i];
+ auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k);
for (uint8_t j = 0; j < 4; j++)
- v[j] = { quad[j], texcoords[j], depth };
+ v[j] = {quad[j], texcoords[j], depth};
}
}
+ if (corner_ok) [[unlikely]]
+ {
+ if (dir.corner.is_defined)
+ {
+ const auto frames = A.frames(dir.corner);
+ const auto depth_offset = depth_offset_for_group<Group_::corner, IsWest>();
+ const auto pos_x = !IsWest ? (float)pos.x : (float)pos.x - 1;
+ const auto depth = tile_shader::depth_value(pos_x, pos.y, depth_offset);
+ const auto& frame = variant_from_frame(frames, coord, variant_2, IsWest);
+ const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, A.image_size());
+ auto quad = get_quad<Group_::corner, IsWest>((float)Depth);
+ for (auto& v : quad)
+ v += center;
+ auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k);
+ for (uint8_t j = 0; j < 4; j++)
+ v[j] = {quad[j], texcoords[j], depth};
+ }
+ else if (dir.wall.is_defined) [[likely]]
+ {
+ const auto frames = A.frames(dir.wall);
+ const auto depth_offset = depth_offset_for_group<Group_::corner, IsWest>();
+ const auto depth = tile_shader::depth_value(!IsWest ? (float)pos.x : (float)pos.x - 1, (float)pos.y, depth_offset);
+ const auto frame = variant_from_frame(frames, coord, variant_2, IsWest);
+ fm_assert(frame.size.x() > Depth);
+ auto start = frame.offset + Vector2ui{frame.size.x(), 0} - Vector2ui{Depth, 0};
+ const auto texcoords = Quads::texcoords_at(start, {Depth, frame.size.y()}, A.image_size());
+ auto quad = get_quad<Group_::corner, IsWest>((float)Depth);
+ for (auto& v : quad)
+ v += center;
+ auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k);
+ for (uint8_t j = 0; j < 4; j++)
+ v[j] = {quad[j], texcoords[j], depth};
+ }
+ }
+ }
+
+ {
+ const auto frames = A.frames(group);
+ const auto frame = variant_from_frame(frames, coord, variant_2, IsWest);
+ const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, A.image_size());
+ const auto depth_offset = depth_offset_for_group<G, IsWest>();
+ const auto depth = tile_shader::depth_value(pos, depth_offset);
+ auto quad = get_quad<G, IsWest>((float)Depth);
+ for (auto& v : quad)
+ v += center;
+ auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k);
+ for (uint8_t j = 0; j < 4; j++)
+ v[j] = {quad[j], texcoords[j], depth};
+ }
+}
+
+} // namespace
+
+GL::Mesh chunk::make_wall_mesh()
+{
+ fm_debug_assert(_walls);
+
+ uint32_t N = 0;
+#ifdef __CLION_IDE__
+ extern const uint32_t _foo; N = _foo;
+#endif
+
+ auto& vertexes = make_vertexes();
+ auto& W = *_walls;
+
+ arrayResize(vertexes, 0);
+
+ for (uint32_t k = 0; k < TILE_COUNT; k++)
+ {
+ const auto coord = global_coords{_coord, local_coords{k}};
+
+ static_assert(Wall::Group_COUNT == /* 5 */ 4);
+ static_assert((int)Direction_::COUNT == 2);
+
+ if (auto* A_nʹ = W.atlases[k*2 + 0].get())
+ {
+ auto& A_n = *A_nʹ;
+ const auto& dir = A_n.calc_direction(Direction_::N);
+ do_wall_part<Group_::wall, false>(dir.wall, A_n, *this, W, vertexes, coord, N, k);
+ do_wall_part<Group_::side, false>(dir.side, A_n, *this, W, vertexes, coord, N, k);
+ do_wall_part<Group_::top, false>(dir.top, A_n, *this, W, vertexes, coord, N, k);
+ }
+ if (auto* A_wʹ = W.atlases[k*2 + 1].get())
+ {
+ auto& A_w = *A_wʹ;
+ const auto& dir = A_w.calc_direction(Direction_::W);
+ do_wall_part<Group_::wall, true>(dir.wall, A_w, *this, W, vertexes, coord, N, k);
+ do_wall_part<Group_::side, true>(dir.side, A_w, *this, W, vertexes, coord, N, k);
+ do_wall_part<Group_::top, true>(dir.top, A_w, *this, W, vertexes, coord, N, k);
+ }
}
+ if (N == 0)
+ return GL::Mesh{NoCreate};
+
ranges::sort(ranges::zip_view(vertexes.prefix(N),
- ArrayView<uint_fast16_t>{_walls->mesh_indexes.data(), N}),
+ ArrayView{_walls->mesh_indexes.data(), N}),
[&A = _walls->atlases](const auto& a, const auto& b) {
const auto& [av, ai] = a;
const auto& [bv, bi] = b;
- return A[ai] < A[bi];
+ return A[ai].get() < A[bi].get();
});
auto vertex_view = std::as_const(vertexes).prefix(N);
diff --git a/src/chunk.cpp b/src/chunk.cpp
index ac529090..a06d55c3 100644
--- a/src/chunk.cpp
+++ b/src/chunk.cpp
@@ -41,17 +41,7 @@ tile_proto chunk::operator[](local_coords xy) const noexcept { return operator[]
chunk_coords_ chunk::coord() const noexcept { return _coord; }
-tile_ref chunk::at_offset(local_coords pos, Vector2i off)
-{
- const auto coord = global_coords{_coord, pos};
- const auto coord2 = coord + off;
- if (coord.chunk() == coord2.chunk()) [[likely]]
- return operator[](coord2.local());
- else
- return (*_world)[coord2].t;
-}
-
-Optional<tile_ref> chunk::at_offset_(local_coords pos, Vector2i off)
+Optional<tile_ref> chunk::at_offset(local_coords pos, Vector2i off)
{
const auto coord = global_coords{_coord, pos};
const auto coord2 = coord + off;
@@ -66,8 +56,7 @@ Optional<tile_ref> chunk::at_offset_(local_coords pos, Vector2i off)
}
}
-tile_ref chunk::at_offset(tile_ref r, Vector2i off) { return at_offset(local_coords{r.index()}, off); }
-Optional<tile_ref> chunk::at_offset_(tile_ref r, Vector2i off) { return at_offset_(local_coords{r.index()}, off); }
+Optional<tile_ref> chunk::at_offset(tile_ref r, Vector2i off) { return at_offset(local_coords{r.index()}, off); }
void chunk::mark_ground_modified() noexcept
{
@@ -139,7 +128,6 @@ void chunk::sort_objects()
void chunk::add_object_pre(const bptr<object>& e)
{
- fm_assert(!e->gone);
fm_assert(&*e->c == this);
const auto dyn = e->is_dynamic(), upd = e->updates_passability();
if (!dyn)
@@ -191,7 +179,6 @@ void chunk::remove_object(size_t i)
{
auto& e = *eʹ;
fm_assert(e.c == this);
- fm_assert(!e.gone);
const auto dyn = e.is_dynamic(), upd = e.updates_passability();
if (!dyn)
@@ -207,7 +194,6 @@ void chunk::remove_object(size_t i)
}
arrayRemove(_objects, i);
- //eʹ.destroy();
}
ArrayView<const bptr<object>> chunk::objects() const
diff --git a/src/chunk.hpp b/src/chunk.hpp
index cf41a970..f49a9653 100644
--- a/src/chunk.hpp
+++ b/src/chunk.hpp
@@ -4,9 +4,8 @@
#include "local-coords.hpp"
#include "src/RTree-fwd.h"
#include "global-coords.hpp"
-#include "wall-defs.hpp"
#include "search-pred.hpp"
-#include <type_traits>
+#include "hole-cut.hpp"
#include <array>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pointer.h>
@@ -34,10 +33,8 @@ public:
tile_proto operator[](local_coords xy) const noexcept;
chunk_coords_ coord() const noexcept;
- tile_ref at_offset(local_coords pos, Vector2i off);
- tile_ref at_offset(tile_ref r, Vector2i off);
- Optional<tile_ref> at_offset_(local_coords pos, Vector2i off);
- Optional<tile_ref> at_offset_(tile_ref r, Vector2i off);
+ Optional<tile_ref> at_offset(local_coords pos, Vector2i off);
+ Optional<tile_ref> at_offset(tile_ref r, Vector2i off);
using iterator = tile_iterator;
using const_iterator = tile_const_iterator;
@@ -99,6 +96,8 @@ public:
class world& world() noexcept;
[[nodiscard]] bool can_place_object(const object_proto& proto, local_coords pos);
+ [[nodiscard]] bool find_hole_in_bbox(CutResult<float>::rect& hole, Vector2 min, Vector2 max);
+ [[nodiscard]] static bool find_hole_in_bbox(CutResult<float>::rect& hole, const Chunk_RTree& rtree, Vector2 min, Vector2 max);
void on_teardown();
bool is_teardown() const;
@@ -107,14 +106,9 @@ public:
void remove_object(size_t i);
void sort_objects();
- // for drawing only
- static constexpr size_t max_wall_quad_count =
- TILE_COUNT*Wall::Direction_COUNT*(Wall::Group_COUNT+4);
-
pass_region make_pass_region(bool debug = false, ArrayView<const Vector2i> positions = {});
pass_region make_pass_region(const Search::pred& f, bool debug = false, ArrayView<const Vector2i> positions = {});
-private:
struct ground_stuff
{
std::array<bptr<ground_atlas>, TILE_COUNT> atlases;
@@ -126,9 +120,10 @@ private:
{
std::array<bptr<wall_atlas>, 2*TILE_COUNT> atlases;
std::array<variant_t, 2*TILE_COUNT> variants;
- std::array<uint_fast16_t, max_wall_quad_count> mesh_indexes;
+ Array<uint_fast16_t> mesh_indexes;
};
+private:
Pointer<ground_stuff> _ground;
Pointer<wall_stuff> _walls;
Array<bptr<object>> _objects;
diff --git a/src/collision.hpp b/src/collision.hpp
index 914d6e1a..eef51d88 100644
--- a/src/collision.hpp
+++ b/src/collision.hpp
@@ -9,9 +9,9 @@ enum class collision_type : unsigned char {
constexpr inline size_t collision_data_BITS = 60;
struct collision_data final {
- uint64_t tag : 2;
- uint64_t pass : 2;
- uint64_t data : collision_data_BITS;
+ uint64_t type : 2;
+ uint64_t pass : 2;
+ uint64_t id : collision_data_BITS;
bool operator==(const collision_data&) const noexcept;
};
diff --git a/src/critter-script-walk.cpp b/src/critter-script-walk.cpp
index 2402fe74..c0e800e8 100644
--- a/src/critter-script-walk.cpp
+++ b/src/critter-script-walk.cpp
@@ -7,6 +7,7 @@
#include "search-result.hpp"
#include "search-astar.hpp"
#include "entity/name-of.hpp"
+#include <utility>
namespace floormat {
diff --git a/src/critter.cpp b/src/critter.cpp
index 32d1048b..e99eb3a4 100644
--- a/src/critter.cpp
+++ b/src/critter.cpp
@@ -55,15 +55,15 @@ constexpr rotation arrows_to_dir_from_mask(unsigned mask)
fm_assert(false);
}
-constexpr auto arrows_to_dir_array = map(arrows_to_dir_from_mask, iota_array<uint8_t, 16>);
-
constexpr auto arrows_to_dir(bool left, bool right, bool up, bool down)
{
+ constexpr auto table = map(arrows_to_dir_from_mask, iota_array<uint8_t, 16>);
constexpr uint8_t L = 1 << 3, R = 1 << 2, U = 1 << 1, D = 1 << 0;
- const uint8_t bits = left*L | right*R | up*U | down*D;
constexpr uint8_t mask = L|R|U|D;
+
+ const uint8_t bits = left*L | right*R | up*U | down*D;
CORRADE_ASSUME((bits & mask) == bits);
- return arrows_to_dir_array.data()[bits];
+ return table.data()[bits];
}
#if 0
@@ -118,26 +118,31 @@ constexpr auto rotation_to_similar_array = map(rotation_to_similar_, iota_array<
constexpr std::array<rotation, 3> rotation_to_similar(rotation r)
{
- CORRADE_ASSUME(r < rotation_COUNT);
return rotation_to_similar_array.data()[(uint8_t)r];
}
-template<rotation r> constexpr uint8_t get_length_axis()
+constexpr uint8_t get_length_axisʹ(rotation r)
{
- static_assert((int)r % 2 == 0);
using enum rotation;
- if constexpr(r == N || r == S)
+ if (r == N || r == S)
return 1;
- else if constexpr(r == W || r == E)
+ else if (r == W || r == E)
return 0;
- fm_assert(false);
+ else
+ return 0; // garbage in, garbage out
+}
+
+constexpr uint8_t get_length_axis(rotation r)
+{
+ constexpr auto table = map(get_length_axisʹ, iota_array<rotation, (size_t)rotation_COUNT>);
+ return table.data()[(size_t)r];
}
-template<rotation new_r, bool MultiStep>
-CORRADE_ALWAYS_INLINE
-bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t nsteps)
+template<bool MultiStep>
+CORRADE_NEVER_INLINE
+bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t nsteps, rotation new_r, rotation visible_r)
{
- constexpr auto vec = rotation_to_vec(new_r);
+ const auto vec = rotation_to_vec(new_r);
using Frac = decltype(critter::offset_frac);
constexpr auto frac = (float{limits<Frac>::max}+1)/2;
constexpr auto inv_frac = 1 / frac;
@@ -156,7 +161,7 @@ bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t n
C.offset_frac = Frac(rem * frac);
if (C.can_move_to(off_i))
{
- C.move_to(i, off_i, new_r);
+ C.move_to(i, off_i, visible_r);
if constexpr(MultiStep)
(C.frame += nsteps) %= info.nframes;
else
@@ -173,64 +178,60 @@ bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t n
return false;
}
-template<rotation r>
-CORRADE_ALWAYS_INLINE
-bool update_movement_3way(size_t& i, critter& C, const anim_def& info)
+bool update_movement_3way(size_t& i, critter& C, const anim_def& info, rotation new_r)
{
- constexpr auto rotations = rotation_to_similar(r);
- if (update_movement_body<rotations[0], false>(i, C, info, 0))
+ const auto rotations = rotation_to_similar(new_r);
+ if (update_movement_body<false>(i, C, info, 0, rotations.data()[0], new_r))
return true;
- if (update_movement_body<rotations[1], false>(i, C, info, 0))
+ if (update_movement_body<false>(i, C, info, 0, rotations.data()[1], new_r))
return true;
- if (update_movement_body<rotations[2], false>(i, C, info, 0))
+ if (update_movement_body<false>(i, C, info, 0, rotations.data()[2], new_r))
return true;
return false;
}
constexpr bool DoUnroll = true;
-template<rotation new_r>
-requires ((int)new_r % 2 != 0)
-CORRADE_ALWAYS_INLINE
-bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes)
+template<bool IsEven>
+requires (!IsEven)
+bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes, rotation new_r)
{
+ //Debug{} << "< nframes" << nframes;
if constexpr(DoUnroll)
{
- //Debug{} << "< nframes" << nframes;
while (nframes > 1)
{
auto len = (uint8_t)Math::min(nframes, (uint32_t)C.bbox_size.min());
if (len <= 1)
break;
- if (!update_movement_body<new_r, true>(i, C, info, len))
+ if (!update_movement_body<true>(i, C, info, len, new_r, new_r))
break;
//Debug{} << " " << len;
nframes -= len;
}
- //Debug{} << ">" << nframes;
}
+ //Debug{} << ">" << nframes;
for (auto k = 0u; k < nframes; k++)
- if (!update_movement_3way<new_r>(i, C, info))
+ if (!update_movement_3way(i, C, info, new_r))
return false;
return true;
}
-template<rotation new_r>
-requires (((int)new_r & 1) % 2 == 0)
-CORRADE_NEVER_INLINE
-bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes)
+template<bool IsEven>
+requires IsEven
+bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes, rotation new_r)
{
if constexpr(DoUnroll)
{
//Debug{} << "< nframes" << nframes;
while (nframes > 1)
{
- constexpr auto len_axis = get_length_axis<new_r>();
+ const auto len_axis = get_length_axis(new_r);
auto len = (uint8_t)Math::min(nframes, (uint32_t)C.bbox_size.data()[len_axis]);
if (len <= 1) [[unlikely]]
break;
- if (!update_movement_body<new_r, true>(i, C, info, len))
+ if (!update_movement_body<true>(i, C, info, len, new_r, new_r))
break;
//Debug{} << " " << len;
nframes -= len;
@@ -239,20 +240,11 @@ bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nfr
}
for (auto k = 0u; k < nframes; k++)
- if (!update_movement_body<new_r, false>(i, C, info, 0))
+ if (!update_movement_body<false>(i, C, info, 0, new_r, new_r))
return false;
return true;
}
-template bool update_movement_1<(rotation)0>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)1>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)2>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)3>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)4>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)5>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)6>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-template bool update_movement_1<(rotation)7>(critter& C, size_t& i, const anim_def& info, uint32_t nframes);
-
struct step_s
{
uint32_t count;
@@ -309,10 +301,10 @@ constexpr rotation dir_from_step_mask(uint8_t val)
}
}
-constexpr auto dir_from_step_array = map(dir_from_step_mask, iota_array<uint8_t, 1 << 4>);
-
constexpr rotation dir_from_step(step_s step)
{
+ constexpr auto table = map(dir_from_step_mask, iota_array<uint8_t, 1 << 4>);
+
if (step.direction.isZero()) [[unlikely]]
return rotation_COUNT;
@@ -320,7 +312,7 @@ constexpr rotation dir_from_step(step_s step)
auto y = uint8_t(step.direction.y() + 1);
//fm_debug_assert((x & 3) == x && (y & 3) == y);
auto val = uint8_t(x << 2 | y);
- return dir_from_step_array.data()[val];
+ return table.data()[val];
}
constexpr step_s next_step(point from, point to)
@@ -441,15 +433,12 @@ void critter::update_movement(size_t& i, const Ns& dt, rotation new_r)
switch (new_r)
{
+ using enum rotation;
default: std::unreachable();
- case (rotation)0: ret = update_movement_1<(rotation)0>(*this, i, info, nframes); break;
- case (rotation)1: ret = update_movement_1<(rotation)1>(*this, i, info, nframes); break;
- case (rotation)2: ret = update_movement_1<(rotation)2>(*this, i, info, nframes); break;
- case (rotation)3: ret = update_movement_1<(rotation)3>(*this, i, info, nframes); break;
- case (rotation)4: ret = update_movement_1<(rotation)4>(*this, i, info, nframes); break;
- case (rotation)5: ret = update_movement_1<(rotation)5>(*this, i, info, nframes); break;
- case (rotation)6: ret = update_movement_1<(rotation)6>(*this, i, info, nframes); break;
- case (rotation)7: ret = update_movement_1<(rotation)7>(*this, i, info, nframes); break;
+ case N: case E: case S: case W:
+ ret = update_movement_1<true >(*this, i, info, nframes, new_r); break;
+ case NW: case NE: case SE: case SW:
+ ret = update_movement_1<false>(*this, i, info, nframes, new_r); break;
}
if (!ret) [[unlikely]]
diff --git a/src/hole-cut.cpp b/src/hole-cut.cpp
index 1ecf96ce..a7736762 100644
--- a/src/hole-cut.cpp
+++ b/src/hole-cut.cpp
@@ -2,6 +2,7 @@
#include "compat/array-size.hpp"
#include "compat/iota.hpp"
#include "compat/map.hpp"
+#include "hole-cut.hpp"
//#include <mg/Functions.h>
#ifdef __GNUG__
@@ -32,7 +33,7 @@ struct coords
struct element
{
- uint8_t size;
+ uint8_t s, size;
std::array<coords, 8> array;
};
@@ -45,9 +46,9 @@ constexpr element make_element(uint8_t s)
switch (s)
{
using enum location;
- case x0|x1|y0|y1: return element{0, {{ // 9.1
+ case x0|x1|y0|y1: return element{s, 0, {{ // 9.1
}}};
- case __|__|__|__: return element{8, {{ // 14.1
+ case __|__|__|__: return element{s, 8, {{ // 14.1
{R0, H0, R0, H0},
{H0, H1, R0, H0},
{H1, R1, R0, H0},
@@ -58,62 +59,62 @@ constexpr element make_element(uint8_t s)
{H1, R1, H1, R1},
}}};
- case x0|x1|__|__: return element{2, {{ // 13.1
+ case x0|x1|__|__: return element{s, 2, {{ // 13.1
{R0, R1, R0, H0},
{R0, R1, H1, R1},
}}};
- case __|__|y0|y1: return element{2, {{ // 13.2
+ case __|__|y0|y1: return element{s, 2, {{ // 13.2
{R0, H0, R0, R1},
{H1, R1, R0, R1},
}}};
- case x0|x1|y0|__: return element{1, {{ // 12.1
+ case x0|x1|y0|__: return element{s, 1, {{ // 12.1
{R0, R1, H1, R1},
}}};
- case x0|x1|__|y1: return element{1, {{ // 12.2
+ case x0|x1|__|y1: return element{s, 1, {{ // 12.2
{R0, R1, R0, H0},
}}};
- case x0|__|y0|y1: return element{1, {{ // 12.3
+ case x0|__|y0|y1: return element{s, 1, {{ // 12.3
{H1, R1, R0, R1},
}}};
- case __|x1|y0|y1: return element{1, {{ // 12.4
+ case __|x1|y0|y1: return element{s, 1, {{ // 12.4
{R0, H0, R0, R1},
}}};
- case x0|__|__|__: return element{3, {{ // 10.1
+ case x0|__|__|__: return element{s, 3, {{ // 10.1
{R0, R1, R0, H0},
{H1, R1, H0, H1},
{R0, R1, H1, R1},
}}};
- case __|x1|__|__: return element{3, {{ // 10.2
+ case __|x1|__|__: return element{s, 3, {{ // 10.2
{R0, R1, R0, H0},
{R0, H0, H0, H1},
{R0, R1, H1, R1},
}}};
- case __|__|y0|__: return element{3, {{ // 10.3
+ case __|__|y0|__: return element{s, 3, {{ // 10.3
{R0, H0, R0, R1},
{H0, H1, H1, R1},
{H1, R1, R0, R1},
}}};
- case __|__|__|y1: return element{3, {{ // 10.4
+ case __|__|__|y1: return element{s, 3, {{ // 10.4
{R0, H0, R0, R1},
{H0, H1, R0, H0},
{H1, R1, R0, R1},
}}};
- case x0|__|y0|__: return element{2, {{ // 11.1
+ case x0|__|y0|__: return element{s, 2, {{ // 11.1
{H1, R1, R0, H1},
{R0, R1, H1, R1},
}}};
- case __|x1|y0|__: return element{2, {{ // 11.2
+ case __|x1|y0|__: return element{s, 2, {{ // 11.2
{R0, H0, R0, H1},
{R0, R1, H1, R1},
}}};
- case x0|__|__|y1: return element{2, {{ // 11.3
+ case x0|__|__|y1: return element{s, 2, {{ // 11.3
{R0, R1, R0, H0},
{H1, R1, H0, R1},
}}};
- case __|x1|__|y1: return element{2, {{ // 11.4
+ case __|x1|__|y1: return element{s, 2, {{ // 11.4
{R0, R1, R0, H0},
{R0, H0, H0, R1},
}}};
@@ -123,8 +124,6 @@ constexpr element make_element(uint8_t s)
fm_assert(false);
}
-constexpr auto elements = map(make_element, iota_array<uint8_t, 16>);
-
template<typename T>
constexpr auto get_value_from_coord(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1, coords c)
{
@@ -141,13 +140,32 @@ template<typename T>
[[nodiscard]]
constexpr bool check_empty(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1)
{
- bool iempty = r0.x() == r1.x() | r0.y() == r1.y();
+ //bool iempty = r0.x() == r1.x() | r0.y() == r1.y();
bool hempty = h0.x() == h1.x() | h0.y() == h1.y();
bool empty_before_x = h1.x() <= r0.x();
bool empty_after_x = h0.x() >= r1.x();
bool empty_before_y = h1.y() <= r0.y();
bool empty_after_y = h0.y() >= r1.y();
- return iempty | hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y;
+ return /*iempty |*/ hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y;
+}
+
+template<typename T>
+constexpr Cr<T> cut_rectangleʹ(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1, uint8_t val)
+{
+ constexpr auto table = map(make_element, iota_array<uint8_t, 16>);
+
+ CORRADE_ASSUME(val < 16);
+ const auto elt = table[val];
+ const auto sz = elt.size;
+ Cr<T> res = {
+ .s = val,
+ .size = sz,
+ .array = {},
+ };
+
+ for (auto i = 0u; i < 8; i++)
+ res.array[i] = get_value_from_coord<T>(r0, r1, h0, h1, elt.array[i]);
+ return res;
}
template<typename T>
@@ -155,9 +173,9 @@ constexpr Cr<T> cut_rectangle(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T
{
if (check_empty<T>(r0, r1, h0, h1))
return {
- .array = {{ { r0, r1 }, }},
+ .s = (uint8_t)-1,
.size = 1,
- .found = false,
+ .array = {{ { r0, r1 }, }},
};
const bool sx = h0.x() <= r0.x();
@@ -165,18 +183,9 @@ constexpr Cr<T> cut_rectangle(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T
const bool sy = h0.y() <= r0.y();
const bool ey = h1.y() >= r1.y();
- auto val = uint8_t(sx << 0 | ex << 1 | sy << 2 | ey << 3);
+ const auto val = uint8_t(sx << 0 | ex << 1 | sy << 2 | ey << 3);
CORRADE_ASSUME(val < 16);
- const auto elt = elements[val];
- const auto sz = elt.size;
- Cr<T> res = {
- .array = {},
- .size = sz,
- .found = true,
- };
-
- for (auto i = 0u; i < 8; i++)
- res.array[i] = get_value_from_coord<T>(r0, r1, h0, h1, elt.array[i]);
+ const auto res = cut_rectangleʹ<T>(r0, r1, h0, h1, val);
return res;
}
@@ -199,10 +208,18 @@ constexpr Cr<T> cut_rectangle(bbox<T> input, bbox<T> hole)
} // namespace
-template<typename T> Cr<T> CutResult<T>::cut(bbox input, bbox hole) { return cut_rectangle<T>(input, hole); }
+template<typename T> Cr<T> CutResult<T>::cutʹ(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1, uint8_t s)
+{
+ return cut_rectangleʹ<T>(r0, r1, h0, h1, s);
+}
+
+template<typename T> Cr<T> CutResult<T>::cut(bbox input, bbox hole) requires std::is_signed_v<T> { return cut_rectangle<T>(input, hole); }
template<typename T> Cr<T> CutResult<T>::cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1) { return cut_rectangle<T>(r0, r1, h0, h1); }
-template struct CutResult<Int>;
+template<typename T> bool CutResult<T>::found() const { return s != (uint8_t)-1; }
+
+template struct CutResult<uint32_t>;
+template struct CutResult<int32_t>;
template struct CutResult<float>;
} // namespace floormat
diff --git a/src/hole-cut.hpp b/src/hole-cut.hpp
new file mode 100644
index 00000000..4ec5c168
--- /dev/null
+++ b/src/hole-cut.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include <array>
+#include <mg/Vector2.h>
+#include <Magnum/DimensionTraits.h>
+
+namespace floormat {
+
+template<typename T>
+struct CutResult
+{
+ using Vec2 = VectorTypeFor<2, T>;
+ struct bbox { Vec2 position; Vector2ub bbox_size; };
+ struct rect { Vec2 min, max; };
+
+ static CutResult cut(bbox input, bbox hole) requires std::is_signed_v<T>;
+ static CutResult cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1);
+ static CutResult cutʹ(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1, uint8_t s);
+
+ uint8_t s = (uint8_t)-1, size = 0;
+ std::array<rect, 8> array;
+
+ bool found() const;
+};
+
+} // namespace floormat
diff --git a/src/hole.hpp b/src/hole.hpp
index 35fd29d9..f70fac15 100644
--- a/src/hole.hpp
+++ b/src/hole.hpp
@@ -22,7 +22,6 @@ struct hole_proto final : object_proto
bool on_render : 1 = true;
bool on_physics : 1 = true;
bool enabled : 1 = true;
- bool is_wall : 1 = false;
};
uint8_t height = 0, z_offset = tile_size_z/2;
@@ -57,19 +56,4 @@ private:
void maybe_mark_neighbor_chunks_modified() override;
};
-template<typename T>
-struct CutResult
-{
- using Vec2 = VectorTypeFor<2, T>;
- struct bbox { Vec2 position; Vector2ub bbox_size; };
- struct rect { Vec2 min, max; };
-
- static CutResult cut(bbox input, bbox hole);
- static CutResult cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1);
-
- std::array<rect, 8> array;
- uint8_t size = 0;
- bool found = false;
-};
-
} // namespace floormat
diff --git a/src/object.cpp b/src/object.cpp
index 449a0fcb..1679f5b7 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -173,7 +173,7 @@ static bool do_search(class chunk* c, chunk_coords_ coord,
bool ret = true;
c->rtree()->Search(min.data(), max.data(), [&](object_id data, const auto& r) {
auto x = std::bit_cast<collision_data>(data);
- if (x.data != id && x.pass != (uint64_t)pass_mode::pass &&
+ if (x.id != id && x.pass != (uint64_t)pass_mode::pass &&
rect_intersects(min, max, {r.m_min[0], r.m_min[1]}, {r.m_max[0], r.m_max[1]}))
return ret = false;
else
diff --git a/src/object.hpp b/src/object.hpp
index a73f97b1..e3cbb628 100644
--- a/src/object.hpp
+++ b/src/object.hpp
@@ -57,7 +57,6 @@ struct object : bptr_base
const rotation r = rotation::N; // todo remove bitfield?
const pass_mode pass = pass_mode::see_through;
bool ephemeral : 1 = false;
- bool gone : 1 = false;
//char _pad[4]; // got 4 bytes left
virtual ~object() noexcept override;
diff --git a/src/point.hpp b/src/point.hpp
index 8d40992b..f0e39aed 100644
--- a/src/point.hpp
+++ b/src/point.hpp
@@ -30,7 +30,7 @@ struct point
constexpr chunk_coords_ chunk3() const;
constexpr local_coords local() const;
constexpr Vector2b offset() const;
- template<size_t N> std::tuple_element_t<N, point> constexpr get() const;
+ template<size_t N> typename std::tuple_element<N, point>::type constexpr get() const;
friend Debug& operator<<(Debug& dbg, const point& pt);
@@ -59,7 +59,7 @@ constexpr chunk_coords point::chunk() const { return {cx, cy}; }
constexpr local_coords point::local() const { return tile; }
constexpr Vector2b point::offset() const { return _offset; }
-template<size_t N> std::tuple_element_t<N, point> constexpr point::get() const
+template<size_t N> typename std::tuple_element<N, point>::type constexpr point::get() const
{
static_assert(N < 2);
if constexpr(N == 0)
diff --git a/src/raycast.cpp b/src/raycast.cpp
index 06cc416e..cb939758 100644
--- a/src/raycast.cpp
+++ b/src/raycast.cpp
@@ -168,9 +168,9 @@ raycast_result_s do_raycasting(std::conditional_t<EnableDiagnostics, raycast_dia
.to = to,
.collision = {},
.collider = {
- .tag = (uint64_t)collision_type::none,
+ .type = (uint64_t)collision_type::none,
.pass = (uint64_t)pass_mode::pass,
- .data = ((uint64_t)1 << collision_data_BITS)-1,
+ .id = ((uint64_t)1 << collision_data_BITS)-1,
},
.has_result = true,
.success = false,
@@ -234,7 +234,7 @@ raycast_result_s do_raycasting(std::conditional_t<EnableDiagnostics, raycast_dia
const auto do_check_collider = [&](uint64_t data, const Rect& r)
{
auto x = std::bit_cast<collision_data>(data);
- if (x.data == self || x.pass == (uint64_t)pass_mode::pass)
+ if (x.id == self || x.pass == (uint64_t)pass_mode::pass)
return;
//Debug{} << "item" << x.data << Vector2(r.m_min[0], r.m_min[1]) << Vector2(r.m_max[0], r.m_max[1]);
auto ret = ray_aabb_intersection(origin, dir_inv_norm,
diff --git a/src/script.cpp b/src/script.cpp
index f2b7d30d..23d11e0d 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -5,6 +5,8 @@ namespace floormat {
namespace {
+namespace fm_debug = floormat::debug::detail;
+
constexpr StringView names[(size_t)script_lifecycle::COUNT] =
{
"no-init"_s, "initializing"_s, "created"_s, "destroying"_s, "torn-down"_s,
@@ -23,10 +25,10 @@ StringView base_script::state_name(script_lifecycle x)
void base_script::_assert_state(script_lifecycle old_state, script_lifecycle s, const char* file, int line)
{
if (old_state != s) [[unlikely]]
- fm_emit_abort(file, line,
- "invalid state transition from '%s' to '%s'",
- state_name(old_state).data(),
- state_name(s).data());
+ fm_debug::emit_abort(file, line,
+ "invalid state transition from '%s' to '%s'",
+ state_name(old_state).data(),
+ state_name(s).data());
}
base_script::~base_script() noexcept = default;
diff --git a/src/search.cpp b/src/search.cpp
index 220e3869..424b1743 100644
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -45,7 +45,7 @@ bool path_search::is_passable_1(chunk& c, Vector2 min, Vector2 max, object_id ow
rt.Search(min.data(), max.data(), [&](uint64_t data, const auto& r)
{
auto x = std::bit_cast<collision_data>(data);
- if (x.data != own_id && x.pass != (uint64_t)pass_mode::pass)
+ if (x.id != own_id && x.pass != (uint64_t)pass_mode::pass)
{
if (rect_intersects(min, max, {r.m_min[0], r.m_min[1]}, {r.m_max[0], r.m_max[1]}))
if (p(x) != path_search_continue::pass)
diff --git a/src/tile-bbox.hpp b/src/tile-bbox.hpp
index 755004d2..6d2228b1 100644
--- a/src/tile-bbox.hpp
+++ b/src/tile-bbox.hpp
@@ -8,11 +8,12 @@
namespace floormat {
template<typename T = float>
-constexpr Vector2 tile_start(size_t k)
+constexpr VectorTypeFor<2, T> tile_start(size_t k)
{
- constexpr auto half_tile = VectorTypeFor<2,T>(tile_size_xy/2);
+ using Vec2 = VectorTypeFor<2,T>;
+ constexpr auto half_tile = Vec2{tile_size_xy/2};
const local_coords coord{k};
- return TILE_SIZE2 * VectorTypeFor<2,T>(coord) - half_tile;
+ return Vec2(TILE_SIZE2) * Vec2(coord) - half_tile;
}
constexpr Pair<Vector2i, Vector2i> scenery_tile(local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size)
@@ -31,24 +32,27 @@ constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> whole_tile(size_t k)
}
template<typename T = float>
-constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_north(size_t k, float wall_depth)
+constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_north(size_t k, T wall_depth)
{
- auto min = tile_start<T>(k) - VectorTypeFor<2,T>{0, wall_depth};
- return { min, min + VectorTypeFor<2,T>{TILE_SIZE2.x(), wall_depth} };
+ using Vec2 = VectorTypeFor<2,T>;
+ auto min = tile_start<T>(k) - Vec2{0, wall_depth};
+ return { min, min + Vec2{tile_size_xy, wall_depth} };
}
template<typename T = float>
-constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_west(size_t k, float wall_depth)
+constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_west(size_t k, T wall_depth)
{
- auto min = tile_start<T>(k) - VectorTypeFor<2,T>{wall_depth, 0};
- return { min, min + VectorTypeFor<2,T>{wall_depth, TILE_SIZE2.y()} };
+ using Vec2 = VectorTypeFor<2,T>;
+ auto min = tile_start<T>(k) - Vec2{wall_depth, 0};
+ return { min, min + Vec2{wall_depth, tile_size_xy} };
}
template<typename T = float>
-constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_pillar(size_t k, float wall_depth)
+constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_pillar(size_t k, T wall_depth)
{
- auto min = tile_start<T>(k) - VectorTypeFor<2,T>{wall_depth, 0};
- return { min - VectorTypeFor<2,T>{0, wall_depth}, min + VectorTypeFor<2,T>{wall_depth, TILE_SIZE2.y()} };
+ using Vec2 = VectorTypeFor<2,T>;
+ auto min = tile_start<T>(k) - Vec2{wall_depth, 0};
+ return { min - Vec2{0, wall_depth}, min + Vec2{wall_depth, tile_size_xy} };
}
} // namespace floormat
diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp
index e0203165..20dd2a84 100644
--- a/src/wall-atlas.hpp
+++ b/src/wall-atlas.hpp
@@ -53,19 +53,13 @@ struct Direction
bool operator==(const Direction&) const noexcept;
- static constexpr inline member_tuple groups[] = {
+ static constexpr member_tuple groups[] = {
{ "wall"_s, &Direction::wall, Group_::wall },
{ "side"_s, &Direction::side, Group_::side },
{ "top"_s, &Direction::top, Group_::top },
{ "corner"_s, &Direction::corner, Group_::corner },
};
- static_assert(array_size(groups) == (size_t)Group_::COUNT);
-
- static constexpr inline member_tuple groups_for_draw[] = {
- { "wall"_s, &Direction::wall, Group_::wall },
- { "side"_s, &Direction::side, Group_::side },
- { "top"_s, &Direction::top, Group_::top },
- };
+ static_assert(array_size(groups) + /*pillar 1 */ 0 == (size_t)Group_::COUNT);
};
struct Info
diff --git a/src/wall-defs.hpp b/src/wall-defs.hpp
index a19d560b..9f88853c 100644
--- a/src/wall-defs.hpp
+++ b/src/wall-defs.hpp
@@ -3,7 +3,7 @@
namespace floormat::Wall {
-enum class Group_ : uint8_t { wall, side, top, corner, COUNT };
+enum class Group_ : uint8_t { wall, side, top, corner, /*pillar,*/ COUNT };
enum class Direction_ : uint8_t { N, W, COUNT };
diff --git a/src/world.cpp b/src/world.cpp
index 89c127cc..1c7c45c9 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -33,9 +33,12 @@ struct world::robin_map_wrapper final : tsl::robin_map<object_id, bptr<object>,
world::world(world&& w) noexcept = default;
-world::world(std::unordered_map<chunk_coords_, chunk>&& chunks) :
- world{std::max(initial_capacity, size_t(1/max_load_factor * 2 * chunks.size()))}
+world::world(std::unordered_map<chunk_coords_, chunk, chunk_coords_hasher>&& chunks)
{
+ const auto capʹ = (size_t)(1e-4f + (float)chunks.size() / max_load_factor);
+ const auto cap = std::max(capʹ, initial_capacity);
+ _chunks.reserve(cap);
+ _chunks.max_load_factor(max_load_factor);
for (auto&& [coord, c] : chunks)
operator[](coord) = move(c);
}
diff --git a/src/world.hpp b/src/world.hpp
index a643de3b..01fc5cc9 100644
--- a/src/world.hpp
+++ b/src/world.hpp
@@ -67,7 +67,7 @@ private:
public:
explicit world();
~world() noexcept;
- explicit world(std::unordered_map<chunk_coords_, chunk>&& chunks);
+ explicit world(std::unordered_map<chunk_coords_, chunk, chunk_coords_hasher>&& chunks);
struct pair_chunk_tile final { chunk& c; tile_ref t; }; // NOLINT
diff --git a/test/app.cpp b/test/app.cpp
index 6ace3ca5..c3ffa8fd 100644
--- a/test/app.cpp
+++ b/test/app.cpp
@@ -58,6 +58,7 @@ int App::exec()
FM_TEST(test_local),
// fast
FM_TEST(test_magnum_math),
+ FM_TEST(test_util),
FM_TEST(test_math),
FM_TEST(test_astar_pool),
FM_TEST(test_coords),
diff --git a/test/app.hpp b/test/app.hpp
index b1995e77..0e4d7a3a 100644
--- a/test/app.hpp
+++ b/test/app.hpp
@@ -41,6 +41,7 @@ void test_rtree();
void test_save();
void test_saves();
void test_script();
+void test_util();
void test_wall_atlas();
void test_wall_atlas2();
diff --git a/test/bptr.cpp b/test/bptr.cpp
index e9d0dff3..7e225a2d 100644
--- a/test/bptr.cpp
+++ b/test/bptr.cpp
@@ -2,7 +2,11 @@
#include "compat/borrowed-ptr.inl"
#include "compat/assert.hpp"
#include "compat/defs.hpp"
+#ifndef FM_NO_WEAK_BPTR
+#include "compat/weak-borrowed-ptr.inl"
+#endif
#include <array>
+#include <cr/Debug.h>
namespace floormat {
@@ -291,7 +295,7 @@ void test8()
p1 = p2;
fm_assert(A_total == 2 && A_alive == 1);
- p2 = move(p1);
+ p2 = move(p1); (void)p2;
fm_assert(A_total == 2 && A_alive == 1);
p1.reset();
@@ -332,7 +336,7 @@ void test9()
fm_assert(p1.use_count() == 0);
fm_assert(p2.use_count() == 0);
fm_assert(A_total == 1 && A_alive == 0);
-};
+}
void test10()
{
@@ -373,10 +377,22 @@ void test11()
auto p1 = bptr<bptr_base>{new Foo{1}};
auto p2 = static_pointer_cast<Foo>(p1);
auto p3 = static_pointer_cast<bptr_base>(p1);
+
fm_assert(p2->x == 1);
fm_assert(p3);
p1.destroy();
fm_assert(!p2); fm_assert(!p3);
+
+ p1.destroy();
+ p1.destroy();
+ p1.destroy();
+ p2.destroy();
+ p2.destroy();
+ p2.destroy();
+ p3.destroy();
+ p3.destroy();
+ p3.destroy();
+ fm_assert(!p1); fm_assert(!p2); fm_assert(!p3);
}
void test12()
@@ -390,6 +406,48 @@ void test12()
fm_assert(p1.use_count() == 1);
}
+void test13()
+{
+#ifndef FM_NO_WEAK_BPTR
+ auto p1 = bptr<Foo>{InPlace, 13};
+ fm_assert_equal(13, p1->x);
+ auto w1 = weak_bptr{p1};
+ fm_assert(p1); fm_assert(w1.lock());
+ fm_assert_equal(1u, p1.use_count());
+ auto p2 = p1;
+ fm_assert_equal(2u, p2.use_count());
+ p1 = {};
+ fm_assert_equal(1u, p2.use_count());
+ fm_assert(!p1); fm_assert(p2);
+ fm_assert(w1.lock());
+ fm_assert_equal(13, w1.lock()->x);
+ p2 = {}; (void)p2;
+ fm_assert(!w1.lock());
+#endif
+}
+
+void test14()
+{
+#ifndef FM_NO_WEAK_BPTR
+ auto p1 = bptr<Foo>{InPlace, 14};
+ auto w1 = weak_bptr{p1};
+ auto w2 = weak_bptr{p1};
+ fm_assert_equal(14, w1.lock()->x);
+ fm_assert_equal(14, w2.lock()->x);
+ fm_assert_equal(1u, p1.use_count());
+ w1 = {};
+ fm_assert(p1);
+ fm_assert_equal(1u, p1.use_count());
+ w2 = {}; (void)w2;
+ fm_assert(p1);
+ fm_assert_equal(1u, p1.use_count());
+ auto w3 = weak_bptr{p1};
+ fm_assert_equal(14, w3.lock()->x);
+ p1 = {}; (void)p1;
+ fm_assert(!w1.lock()); fm_assert(!w2.lock()); fm_assert(!w3.lock());
+#endif
+}
+
} // namespace
void Test::test_bptr()
@@ -406,6 +464,8 @@ void Test::test_bptr()
test10();
test11();
test12();
+ test13();
+ test14();
}
} // namespace floormat
diff --git a/test/critter.cpp b/test/critter.cpp
index 90619ce8..5b7ee52d 100644
--- a/test/critter.cpp
+++ b/test/critter.cpp
@@ -18,6 +18,8 @@ namespace floormat {
namespace {
+namespace fm_debug = floormat::debug::detail;
+
using enum rotation;
using fu2::function_view;
using Function = function_view<Ns() const>;
@@ -147,7 +149,7 @@ bool run(world& w, const function_view<Ns() const>& make_dt,
if (b) [[likely]]
return false;
else
- fm_emit_assert_fail("false", file, line);
+ fm_debug::emit_abort(file, line, "false");
};
for (i = 0; true; i++)
diff --git a/test/entity.cpp b/test/entity.cpp
index 2bbdf29a..97ffd7a7 100644
--- a/test/entity.cpp
+++ b/test/entity.cpp
@@ -258,7 +258,7 @@ void test_range2()
const auto A = m_foo.erased();
auto r = A.get_range(&x);
auto i = r.convert<int>();
- fm_assert(i.second == rʹ.max);
+ fm_assert(i.second() == rʹ.max);
}
constexpr bool test_range3()
@@ -277,8 +277,8 @@ void test_range4()
constexpr auto rʹ = f.get_range(f.range, TestAccessors{});
const auto A = f.erased();
const auto r = A.get_range(&x).convert<Vector2i>();
- fm_assert(r.first == rʹ.min);
- fm_assert(r.second == rʹ.max);
+ fm_assert(r.first() == rʹ.min);
+ fm_assert(r.second() == rʹ.max);
}
constexpr bool test_enum_range()
diff --git a/test/hole.cpp b/test/hole.cpp
index 7ccc86c3..09395c47 100644
--- a/test/hole.cpp
+++ b/test/hole.cpp
@@ -1,5 +1,7 @@
#include "app.hpp"
#include "src/hole.hpp"
+#include "src/hole-cut.hpp"
+#include "src/tile-constants.hpp"
namespace floormat {
namespace {
@@ -53,6 +55,44 @@ void test1(Vector2i offset)
#endif
}
+auto make_search_predicate(const CutResult<int>& res)
+{
+ return [&](Vector2i min, Vector2i max) -> bool {
+ for (auto i = 0u; i < res.size; i++)
+ if (res.array[i].min == min && res.array[i].max == max)
+ return true;
+ return false;
+ };
+}
+
+void test2()
+{
+ const auto res = CutResult<int>::cut({{}, Vector2ub{tile_size_xy}}, {Vector2i(-tile_size_xy/2), Vector2ub{tile_size_xy}});
+ fm_assert(res.size == 2);
+ const auto has = make_search_predicate(res);
+ fm_assert(has({-32, 0}, {32, 32}));
+ fm_assert(has({0, -32}, {32, 0}));
+}
+
+void test3()
+{
+ constexpr auto h = tile_size_xy/2;
+
+ {
+ const auto res = CutResult<Int>::cut({-h, -1}, {h, 1}, {-2, -100}, {2, 100});
+ fm_assert(res.found());
+ fm_assert_equal(2, (int)res.size);
+ }
+ {
+ const auto res = CutResult<Int>::cut({-h, 0}, {h, 0}, {-2, -100}, {2, 100});
+ fm_assert(res.found());
+ fm_assert_equal(2, (int)res.size);
+ const auto has = make_search_predicate(res);
+ fm_assert(has({-h, 0}, {-2, 0}));
+ fm_assert(has({ 2, 0}, { h, 0}));
+ }
+}
+
} // namespace
void Test::test_hole()
@@ -67,6 +107,9 @@ void Test::test_hole()
for (auto offset : offsets)
test1(offset);
+
+ test2();
+ test3();
}
} // namespace floormat
diff --git a/test/save.cpp b/test/save.cpp
index 04c9810c..76cdd271 100644
--- a/test/save.cpp
+++ b/test/save.cpp
@@ -103,7 +103,6 @@ void assert_chunks_equal(const chunk& a, const chunk& b)
case object_type::COUNT:
fm_assert(false);
case object_type::critter: {
- // todo! remove duplication
const auto& e1 = static_cast<const critter&>(ae);
const auto& e2 = static_cast<const critter&>(be);
const auto p1 = critter_proto(e1), p2 = critter_proto(e2);
diff --git a/test/util.cpp b/test/util.cpp
new file mode 100644
index 00000000..e250b072
--- /dev/null
+++ b/test/util.cpp
@@ -0,0 +1,45 @@
+#include "app.hpp"
+#include "compat/array-size.hpp"
+
+namespace floormat::Test {
+
+namespace {
+
+struct Foo
+{
+ static constexpr std::array<int, 11> Array_1 = {};
+ static constexpr const void* Array_2[22] = {};
+
+ std::array<int, 33> array_3;
+ int array_4[55] = {};
+};
+
+constexpr bool test_array_size()
+{
+ fm_assert(static_array_size<decltype(Foo::Array_1)> == 11);
+ fm_assert(array_size(Foo::Array_1) == 11);
+
+ fm_assert(static_array_size<decltype(Foo::Array_2)> == 22);
+ fm_assert(array_size(&Foo::Array_2) == 22);
+
+ fm_assert(static_array_size<decltype(Foo{}.array_3)> == 33);
+ fm_assert(array_size(Foo{}.array_3) == 33);
+ fm_assert(array_size(&Foo::array_3) == 33);
+
+ fm_assert(static_array_size<const int(&)[44]> == 44);
+
+ fm_assert(static_array_size<decltype(Foo::array_4)> == 55);
+ fm_assert(array_size(&Foo::array_4) == 55);
+ fm_assert(array_size(Foo{}.array_4) == 55);
+
+ return true;
+}
+
+} // namespace
+
+void test_util()
+{
+ static_assert(test_array_size());
+}
+
+} // namespace floormat::Test
diff --git a/userconfig-sthalik@Windows-Clang.cmake b/userconfig-sthalik@Windows-Clang.cmake
index dc0ba1dd..4f2d9dfa 100644
--- a/userconfig-sthalik@Windows-Clang.cmake
+++ b/userconfig-sthalik@Windows-Clang.cmake
@@ -11,6 +11,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "DEBUG")
-fcoverage-mapping
)
endif()
+ add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE)
else()
set(BUILD_SHARED_LIBS OFF)
add_compile_options(-march=native -mavx2)
@@ -19,6 +20,8 @@ else()
add_link_options(-fmerge-all-constants -flto=full -fwhole-program-vtables -fforce-emit-vtables)
add_link_options(-Wl,--gc-sections -Wl,--icf=all)
add_compile_options(-Wno-nan-infinity-disabled)
+ add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST)
+ add_compile_options(-fpointer-tbaa)
endif()
if(FLOORMAT_ASAN)
@@ -26,13 +29,13 @@ if(FLOORMAT_ASAN)
add_link_options(-fsanitize=undefined,bounds,address)
endif()
-set(OpenCV_DIR "f:/build/opencv/build-clang-release-floormat/install" CACHE PATH "" FORCE)
+set(OpenCV_DIR "d:/dev/opencv-floormat-clang-release" CACHE PATH "" FORCE)
set(CMAKE_INSTALL_MESSAGE NEVER)
sets(STRING
CMAKE_C_FLAGS "-march=x86-64-v2 -mtune=native -mavx2 -maes -g -gcolumn-info -gdwarf-aranges"
CMAKE_C_FLAGS_DEBUG "-O0 -fstack-protector-all -g"
- CMAKE_C_FLAGS_RELEASE "-Ofast -ffast-math -mpopcnt -fomit-frame-pointer -fno-stack-protector -static"
+ CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math -mpopcnt -fomit-frame-pointer -fno-stack-protector -static"
CMAKE_EXE_LINKER_FLAGS_DEBUG ""
CMAKE_SHARED_LINKER_FLAGS_DEBUG ""
)
@@ -42,12 +45,12 @@ sets(STRING
CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}"
)
+add_definitions(-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
+
if(NOT CMAKE_CXX_COMPILER_VERSION LESS "18.0")
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fassume-nothrow-exception-dtor>)
endif()
-set(FLOORMAT_SUBMODULE-SDL2 1)
-
# for building submodule dependencies
function(fm-userconfig-external)
add_compile_options(
@@ -62,15 +65,15 @@ function(fm-userconfig-external)
SDL_SHARED OFF
SDL_STATIC ON
CORRADE_BUILD_STATIC ON
- CORRADE_BUILD_TESTS OFF
+ CORRADE_BUILD_TESTS ON
CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT ON
MAGNUM_BUILD_PLUGINS_STATIC ON
MAGNUM_BUILD_STATIC ON
- MAGNUM_BUILD_TESTS OFF
+ MAGNUM_BUILD_TESTS ON
)
else()
sets(BOOL
- FLOORMAT_SUBMODULE-SDL2 OFF
+ FLOORMAT_SUBMODULE-SDL2 ON
SDL_SHARED ON
SDL_STATIC OFF
CORRADE_BUILD_STATIC OFF
@@ -81,14 +84,6 @@ function(fm-userconfig-external)
MAGNUM_BUILD_TESTS ON
)
endif()
- if(FLOORMAT_ASAN)
- sets(BOOL
- CORRADE_BUILD_STATIC ON
- CORRADE_BUILD_TESTS OFF
- MAGNUM_BUILD_STATIC ON
- MAGNUM_BUILD_TESTS OFF
- )
- endif()
endfunction()
# for test_app sources only
diff --git a/userconfig-sthalik@Windows-GNU.cmake b/userconfig-sthalik@Windows-GNU.cmake
index 81d99338..99bb412a 100644
--- a/userconfig-sthalik@Windows-GNU.cmake
+++ b/userconfig-sthalik@Windows-GNU.cmake
@@ -13,23 +13,22 @@ sets(STRING
list(APPEND CMAKE_IGNORE_PATH "c:/msys64" "c:/msys64/clang64")
list(APPEND CMAKE_IGNORE_PREFIX_PATH "c:/msys64" "c:/msys64/clang64")
-add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fconcepts-diagnostics-depth=3>)
+add_definitions(-D_GLIBCXX_USE_DEPRECATED=0 -D_GLIBCXX_USE_CXX11_ABI)
add_compile_options(-fdiagnostics-color=always)
-add_compile_options(-fstack-usage -Wstack-usage=16384)
+add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fconcepts-diagnostics-depth=3>)
+
+add_definitions(-D_GLIBCXX_ASSERTIONS)
+add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:-D_GLIBCXX_DEBUG>>)
+add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:$<$<CONFIG:DEBUG,Debug>:-D_GLIBCXX_DEBUG_PEDANTIC>>)
+add_compile_definitions($<$<NOT:$<CONFIG:Debug,DEBUG>>:_FORTIFY_SOURCE=2>)
+add_compile_definitions($<$<CONFIG:Debug,DEBUG>:_FORTIFY_SOURCE=3>)
if(CMAKE_BUILD_TYPE STREQUAL "DEBUG")
- add_definitions(-D_GLIBCXX_ASSERTIONS)
- add_definitions(-D_GLIBCXX_USE_DEPRECATED=0 -D_GLIBCXX_USE_CXX11_ABI)
- add_definitions(-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC)
set(OpenCV_DIR "f:/build/opencv/build-gcc-debug-floormat/install" CACHE PATH "" FORCE)
else()
set(BUILD_SHARED_LIBS OFF)
set(OpenCV_DIR "f:/build/opencv/build-gcc-release-floormat/install" CACHE PATH "" FORCE)
endif()
-add_compile_definitions("$<$<CONFIG:Debug,DEBUG>:_FORTIFY_SOURCE=3>")
-add_compile_definitions("$<IF:$<CONFIG:Debug,DEBUG>,,_FORTIFY_SOURCE=3>")
-
-set(FLOORMAT_SUBMODULE-SDL2 1)
# for building submodule dependencies
function(fm-userconfig-external)
@@ -70,23 +69,30 @@ endfunction()
# for floormat sources only
function(fm-userconfig-src)
+ add_compile_options(-fstack-usage -Wstack-usage=16384)
add_compile_options(
-Wall -Wextra -Wpedantic -Wno-old-style-cast -Wno-padded
-Wstringop-overflow -Wstringop-truncation
-Wswitch-enum -Wlarger-than=8192
-Wlogical-op
-Wunsafe-loop-optimizations
+ -Wctor-dtor-privacy -Wno-error=ctor-dtor-privacy
+ -Winvalid-constexpr -Winvalid-imported-macros
+ -Woverloaded-virtual
+
#-fconcepts-diagnostics-depth=2
)
#add_compile_options(-Wuseless-cast)
- add_link_options(-Wno-lto-type-mismatch -Wno-odr)
+ add_link_options(-Wno-lto-type-mismatch -Wodr -Wno-error=odr)
add_compile_options(
#-Wno-c++20-compat
-Wno-switch-enum
-Wno-ctad-maybe-unsupported
-Wno-ignored-attributes
-Wno-parentheses
- -Wno-lto-type-mismatch -Wno-odr
+ #-Wno-lto-type-mismatch -Wno-odr
+ -Wno-error=lto-type-mismatch
+ -Wodr -Wno-error=odr
)
add_compile_options(
-Werror=format