summaryrefslogtreecommitdiffhomepage
path: root/loader/wall-atlas.cpp
blob: c7e9bb2b018fbb1005eb3256fd3cfd98413954ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "loader/impl.hpp"
#include "wall-info.hpp"
#include "compat/assert.hpp"
#include "compat/exception.hpp"
#include "src/wall-atlas.hpp"
#include "serialize/wall-atlas.hpp"
#include "wall-info.hpp"
#include "serialize/json-helper.hpp"
#include "serialize/corrade-string.hpp"
#include "src/tile-defs.hpp"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Utility/Path.h>
#include <Magnum/Trade/ImageData.h>
#include <Magnum/ImageView.h>
#include <vector>

namespace floormat {

using nlohmann::json;
using loader_detail::loader_impl;

[[maybe_unused]] static void from_json(const json& j, wall_info& val)
{
    val = {};
    val.name = j["name"];
    fm_soft_assert(loader.check_atlas_name(val.name));
    if (j.contains("descr"))
        val.descr = j["descr"];
}

[[maybe_unused]] static void to_json(json& j, const wall_info& val)
{
    j["name"] = val.name;
    if (val.descr)
        j["descr"] = val.descr;
}

} // namespace floormat

namespace floormat::loader_detail {

std::shared_ptr<wall_atlas> loader_impl::get_wall_atlas(StringView name, StringView path)
{
    auto filename = Path::join(path, name);
    auto def = wall_atlas_def::deserialize(""_s.join({filename, ".json"_s}));
    auto tex = texture(""_s, filename, false);

    fm_soft_assert(name == def.header.name);
    fm_soft_assert(!def.frames.empty());
    auto atlas = std::make_shared<class wall_atlas>(std::move(def), path, tex);
    return atlas;
}

const wall_info& loader_impl::make_invalid_wall_atlas()
{
    if (invalid_wall_atlas) [[likely]]
        return *invalid_wall_atlas;

    constexpr auto name = "<invalid>"_s;
    constexpr auto frame_size = Vector2ui{iTILE_SIZE.x(), iTILE_SIZE.z()};

    auto a = std::make_shared<class wall_atlas>(
        wall_atlas_def {
            Wall::Info{.name = name, .depth = 8},
            {{ {}, frame_size}, },
            {{ {.index = 0, .count = 1, .pixel_size = frame_size, .is_defined = true, } } },
            {{ {.val = 0}, {}, }},
            {1u},
        }, name, make_error_texture(frame_size));
    invalid_wall_atlas = Pointer<wall_info>{InPlaceInit, wall_info{ .name = name, .atlas = std::move(a) } };
    return *invalid_wall_atlas;
}

std::shared_ptr<class wall_atlas> loader_impl::wall_atlas(StringView name, bool fail_ok) noexcept(false)
{
    fm_soft_assert(check_atlas_name(name));
    char buf[FILENAME_MAX];
    auto path = make_atlas_path(buf, loader.WALL_TILESET_PATH, name);

    auto it = wall_atlas_map.find(name);
    if (it == wall_atlas_map.end())
    {
        if (!fail_ok)
            fm_throw("no such wall atlas '{}'"_cf, name);
        else
        {
            DBG_nospace << "wall_atlas '" << name << "'doesn't exist";
            return make_invalid_wall_atlas().atlas;
        }
    }
    fm_assert(it->second != nullptr);
    if (!it->second->atlas) [[unlikely]]
        it->second->atlas = get_wall_atlas(it->second->name, path);
    return it->second->atlas;
}

void loader_impl::get_wall_atlas_list()
{
    wall_atlas_array = json_helper::from_json<std::vector<wall_info>>(Path::join(WALL_TILESET_PATH, "walls.json"_s));
    wall_atlas_array.shrink_to_fit();
    wall_atlas_map.clear();
    wall_atlas_map.reserve(wall_atlas_array.size()*2);

    for (auto& x : wall_atlas_array)
    {
        fm_soft_assert(check_atlas_name(x.name));
        x.atlas = get_wall_atlas(x.name, WALL_TILESET_PATH);
        StringView name = x.name;
        wall_atlas_map[name] = &x;
        fm_debug_assert(name.data() == wall_atlas_map[name]->name.data());
    }

    fm_assert(!wall_atlas_map.empty());
}

ArrayView<const wall_info> loader_impl::wall_atlas_list()
{
    if (wall_atlas_map.empty())
        get_wall_atlas_list();
    fm_assert(!wall_atlas_map.empty());
    return wall_atlas_array;
}

} // namespace floormat::loader_detail