* Fix broken catacombs wall tile
When tile 15 is followed by tile 1 below, change tile 1 to tile 8
(left corner) to fix a visual glitch in the catacombs.
* Silence fmt catch warnings and guard SaveHelper copy
Turns out, `add_custom_target`'s `DEPENDS` argument can only
refer to outputs of custom commands in the same directory (i.e. the same
CMakeLists.txt scope).
Interestingly, this worked with all generators except parallel
make, so perhaps there some ongoing work in CMake to allow
cross-directory `DEPENDS`.
Works around this limitation by moving tests to the same scope
(`CMakeLists.txt` file) as assets.
Tricks the compiler into skipping expensive
`uninit var analysis` (`-Wmaybe-uninitialized`) by using
a struct with state rather than separate variables for `best` /
`bestDiff`.
This has no performance impact.
Also optimizes lookup a bit further and moves some code that
does not need to be inlined to the cpp file.
```
Benchmark Time CPU Time Old Time New CPU Old CPU New
-----------------------------------------------------------------------------------------------------------------------------------
BM_GenerateBlendedLookupTable_pvalue 0.0002 0.0002 U Test, Repetitions: 10 vs 10
BM_GenerateBlendedLookupTable_mean +0.0237 +0.0237 2092090 2141601 2091732 2141291
BM_GenerateBlendedLookupTable_median +0.0237 +0.0237 2092104 2141662 2091669 2141319
BM_GenerateBlendedLookupTable_stddev -0.6414 -0.5834 664 238 538 224
BM_GenerateBlendedLookupTable_cv -0.6497 -0.5930 0 0 0 0
BM_BuildTree_pvalue 0.0002 0.0002 U Test, Repetitions: 10 vs 10
BM_BuildTree_mean +0.0410 +0.0410 4495 4679 4494 4678
BM_BuildTree_median +0.0403 +0.0402 4494 4675 4493 4674
BM_BuildTree_stddev +0.9515 +0.9359 7 14 7 14
BM_BuildTree_cv +0.8746 +0.8596 0 0 0 0
BM_FindNearestNeighbor_pvalue 0.0002 0.0002 U Test, Repetitions: 10 vs 10
BM_FindNearestNeighbor_mean -0.0399 -0.0398 1964257108 1885966812 1963954917 1885694336
BM_FindNearestNeighbor_median -0.0397 -0.0396 1963969748 1886074435 1963650984 1885803182
BM_FindNearestNeighbor_stddev -0.3380 -0.3443 1217360 805946 1225442 803469
BM_FindNearestNeighbor_cv -0.3105 -0.3171 0 0 0 0
OVERALL_GEOMEAN +0.0077 +0.0077 0 0 0 0
```
Uses a k-d tree to quickly find the best match
for a color when generating the palette blending
lookup table.
https://en.wikipedia.org/wiki/K-d_tree
This is 3x faster than the previous naive approach:
```
Benchmark Time CPU Time Old Time New CPU Old CPU New
-----------------------------------------------------------------------------------------------------------------------------------
BM_GenerateBlendedLookupTable_pvalue 0.0002 0.0002 U Test, Repetitions: 10 vs 10
BM_GenerateBlendedLookupTable_mean -0.7153 -0.7153 18402641 5239051 18399111 5238025
BM_GenerateBlendedLookupTable_median -0.7153 -0.7153 18403261 5239042 18398841 5237497
BM_GenerateBlendedLookupTable_stddev -0.2775 +0.3858 2257 1631 1347 1867
BM_GenerateBlendedLookupTable_cv +1.5379 +3.8677 0 0 0 0
OVERALL_GEOMEAN -0.7153 -0.7153 0 0 0 0
```
The distribution is somewhat poor with just 3 levels, so this can be improved further.
For example, here is the leaf size distribution in the cathedral:
```
r0.g0.b0: 88
r0.g0.b1: 10
r0.g1.b0: 2
r0.g1.b1: 32
r1.g0.b0: 27
r1.g0.b1: 4
r1.g1.b0: 12
r1.g1.b1: 81
```
This test covers a few vision bugs:
1. VisibilityInStraightLineOfSight - test case checks the visibility
of objects in a straight line of sight parallel to the X or Y
coordinate lines:
https://github.com/diasurgical/DevilutionX/pull/7901
2. NoVisibilityThroughAdjacentTiles - test case checks that nothing is
visible through the diagonally adjacent tiles:
https://github.com/diasurgical/DevilutionX/pull/7920
3. VisibleObjects - generic test, which makes sure some objects are
visible, but some - are not.
Signed-off-by: Roman Penyaev <r.peniaev@gmail.com>
1. Fixes DrawStringwithColors kerning fit handling and newline handling.
2. Splits tests into one file per function call, making it easier to compare diffs and add new tests.
Also adds `--update_expected` argument to update the expected files with actual results.
This does not fully address the issue of most everything
being a giant library but it's a start.
Note that the libraries are OBJECT libraries, so they
may (and currently do) contain references to missing
symbols.
Also fixes the implementation of transitive dependency
support for OBJECT libraries.
Our implementation has a more modern interface and only
supports the features that we care about.
It always outputs `\n` as newlines and does not output BOM.
The modern interface eliminates awkward `c_str()/data()` conversions.
This implementation preserves comments and the file order of sections
and keys. New keys are written in insertion order.
We now also support modifying and adding default comments,
which may be a useful thing to do for the especially tricky
ini options (this PR doesn't add any but adds the ability to do so).
Sadly, this increases the RG99 binary size by 24 KiB.
I'm guessing this is because the map implementation generates
quite a bit of code.
Note that while it might seem that using `std::string` for every key and
value would do a lot of allocations, most of these strings are
small and thus benefit from Small String Optimization (= no allocations).
The new algorithm is a lot less code, slightly faster, and results
in a smaller binary (-40 KiB on rg99).
The previous algorithm filled all the pixels around every solid pixel.
The new algorithm only fills pixels that will be visible.
We first collect the outline pixels into an array (which may contain a
small amount of duplicates). Then, we render the entire array in a
single loop. This turns out to be slightly faster than rendering inline,
at the cost of ~4 KiB of stack (basically free).
To collect the pixels, we go through the CLX sprite, keeping track
of the solid runs in the current row, and the filled pixels on the line
above and the line below.
To be able to quickly test the pixels above and below, we introduce a
new data structure, `StaticBitVector`. It is similar to a bitset,
except the size is determined at runtime (capacity is fixed),
and it supports quick updates of entire subspans.
Also added an iterator based API, though it's not useful for this use-case. Might be nice in the future?
The field/record iterators is single-pass input iterators with shared state.
To avoid rescanning fields unnecessarily parseInt currently can only be called once, it would be possible to make these iterators bidirectional with a bit of extra state (holding onto the start pointer)
Co-authored-by: Gleb Mazovetskiy <glex.spb@gmail.com>
1. Use `fmt::format_int` directly instead of parsing a format string.
2. Use `AppendStrView`.
3. Define the varargs versions using fold expressions when available.
4. Add tests.
Adds a custom sized type for the world tile rectagle.
This allows us to better express intent.
It also allows us to make certain globals smaller, e.g. `THEME_LOC`.