Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
ModernTokenPreview.cpp
Go to the documentation of this file.
3#include <fstream>
4
5namespace monopoly::menu
6{
8 {
9 if (token >= data::ModernTokenCount || failedPacks_[token]) return PackState::Failed;
10 if (activeToken_ == token) return PackState::Ready;
11 if (pendingToken_ == token) return PackState::Loading;
12 return PackState::Unloaded;
13 }
14
15 ModernTokenPreview::PackResult ModernTokenPreview::loadPack(std::filesystem::path directory) noexcept
16 {
17 try
18 {
19 PackResult result;
20 for (unsigned index = 0; index < result.frames.size(); ++index)
21 {
22 const std::string name{char('0' + index / 10), char('0' + index % 10)};
23 result.frames[index] = decode(directory / (name + ".png"));
24 if (!result.frames[index]) return {};
25 }
26 result.complete = true;
27 return result;
28 }
29 catch (...) { return {}; }
30 }
31
32 std::shared_ptr<const data::LegacyBitmapRGBA8>
33 ModernTokenPreview::decode(const std::filesystem::path& path)
34 {
35 constexpr std::size_t MaximumEncodedBytes = 2U * 1024U * 1024U;
36 std::ifstream input(path, std::ios::binary | std::ios::ate);
37 if (!input) return {};
38 const auto size = input.tellg();
39 if (size <= 0 || size > static_cast<std::streamoff>(MaximumEncodedBytes)) return {};
40 std::vector<std::byte> bytes(static_cast<std::size_t>(size));
41 input.seekg(0);
42 if (!input.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()))) return {};
44 {MaximumEncodedBytes, 768, 768U * 640U * 4U});
45 if (!decoded || (*decoded)->width != 768 || (*decoded)->height != 640 ||
46 (*decoded)->rgba.size() != 768U * 640U * 4U) return {};
47 bool transparent{}, visible{};
48 for (std::size_t index = 3; index < (*decoded)->rgba.size(); index += 4)
49 {
50 transparent |= (*decoded)->rgba[index] == 0;
51 visible |= (*decoded)->rgba[index] != 0;
52 }
53 if (!transparent || !visible) return {};
54 return std::make_shared<const data::LegacyBitmapRGBA8>(
55 data::LegacyBitmapRGBA8{768, 640, (*decoded)->rgba});
56 }
57
58 std::shared_ptr<const data::LegacyBitmapRGBA8>
59 ModernTokenPreview::image(std::uint8_t token, std::uint8_t frame) noexcept
60 {
61 if (token >= data::ModernTokenCount || (frame >= 28 && frame != 255)) return {};
62 try
63 {
64 const auto directory = root_ / data::modernTokenDefinitions()[token].slug;
65 if (frame == 255)
66 {
67 if (!attemptedThumbnails_[token])
68 {
69 attemptedThumbnails_[token] = true;
70 thumbnails_[token] = decode(directory / "thumbnail.png");
71 }
72 return thumbnails_[token];
73 }
74 if (pending_.valid())
75 {
76 if (pending_.wait_for(std::chrono::seconds(0)) != std::future_status::ready) return {};
77 const auto completedToken = *pendingToken_;
78 PackResult completed;
79 try { completed = pending_.get(); }
80 catch (...) { /* An actual failed job qualifies only its own token. */ }
81 pendingToken_.reset();
82 if (!completed.complete) failedPacks_[completedToken] = true;
83 else if (completedToken == token)
84 {
85 frames_ = std::move(completed.frames);
86 activeToken_ = token;
87 }
88 // A successful obsolete pack is destroyed before another job.
89 }
90 if (failedPacks_[token]) return {};
91 if (activeToken_ == token) return frames_[frame];
92 // Retire the previous pack before allocating: even a switch cannot
93 // temporarily retain two complete 28-frame packs inside this cache.
94 frames_ = {};
95 activeToken_.reset();
96 pending_ = std::async(std::launch::async, &ModernTokenPreview::loadPack, directory);
97 pendingToken_ = token;
98 return {};
99 }
100 catch (...)
101 {
102 if (frame == 255) attemptedThumbnails_[token] = true;
103 else failedPacks_[token] = true;
104 return {};
105 }
106 }
107}
const char * name
std::vector< std::byte > bytes
unsigned index
int token
std::size_t frame
std::filesystem::path directory
std::string path
Bytes input
PackState packState(std::uint8_t token) const noexcept
std::shared_ptr< const data::LegacyBitmapRGBA8 > image(std::uint8_t token, std::uint8_t frame) noexcept
std::expected< std::shared_ptr< const ModernTextureImage >, MeshRuntimeError > decodeModernImage(std::span< const std::byte > bytes, ModernImageEncoding encoding, ModernImageDecodeLimits limits)
const std::array< ModernTokenDefinition, ModernTokenCount > & modernTokenDefinitions() noexcept
constexpr std::size_t ModernTokenCount
std::size_t size()