17 const auto value =
static_cast<std::uint32_t
>(camera);
19 return std::unexpected(
"UDBoard backdrop camera is outside 0..38");
27 return std::unexpected(
"UDBoard backdrop city is outside 0..10");
28 return static_cast<std::uint32_t
>(city);
47 default:
return {0, 0};
52 std::expected<void, std::string> BoardBackdropPlayback::ensureSurfaces(
55 if (surfacesReady_)
return {};
59 for (
auto&
buffer : mainBuffers_)
66 return std::unexpected(
created.error());
72 buffer.customRootLoaded.clear();
76 const auto trade =
playback.runtimeBitmaps().create(
82 return std::unexpected(trade.error());
84 tradeSurface_ = *trade;
85 surfacesReady_ =
true;
89 std::expected<data::LegacyBitmapRGBA8, std::string>
90 BoardBackdropPlayback::loadBoardBitmap(
93 const auto resources =
playback.resources();
94 if (!resources)
return std::unexpected(
"UDBoard backdrop has no resource snapshot");
95 const auto metadata = resources->data().metadata(
id);
98 return std::unexpected(
"UDBoard backdrop source is not DataBMP");
100 const auto bytes = resources->data().load(
id);
101 if (!
bytes)
return std::unexpected(
bytes.error().detail);
106 std::expected<data::LegacyBitmapRGBA8, std::string>
107 BoardBackdropPlayback::loadCustomBoardBitmap(
108 std::uint32_t camera,
const std::filesystem::path& customRoot,
111 const auto resources =
playback.resources();
112 if (!resources)
return std::unexpected(
"custom UDBoard backdrop has no resource snapshot");
114 if (camera >= names.size())
115 return std::unexpected(
"custom UDBoard backdrop camera is outside 0..38");
117 resources->context().board, resources->context().language,
121 names[camera], context);
125 std::ifstream
input(*
resolved, std::ios::binary | std::ios::ate);
126 if (!
input)
return std::unexpected(
"cannot open custom 2D board bitmap");
127 const auto size =
input.tellg();
129 return std::unexpected(
"custom 2D board bitmap exceeds file budget");
130 std::vector<std::byte>
bytes(
static_cast<std::size_t
>(size));
131 input.seekg(0, std::ios::beg);
133 input.read(
reinterpret_cast<char*
>(
bytes.data()),
134 static_cast<std::streamsize
>(
bytes.size()));
135 if (!
input)
return std::unexpected(
"cannot read complete custom 2D board bitmap");
142 std::expected<void, std::string> BoardBackdropPlayback::validateCustomBoardSet(
143 const std::filesystem::path& customRoot,
146 if (customRoot.empty() || !customRoot.is_absolute())
147 return std::unexpected(
"custom UDBoard backdrop requires an absolute asset root");
148 const auto resources =
playback.resources();
149 if (!resources)
return std::unexpected(
"custom UDBoard backdrop has no resource snapshot");
151 resources->context().board, resources->context().language,
153 std::error_code
error;
161 return std::unexpected(
"custom 2D board set is incomplete");
166 std::expected<void, std::string> BoardBackdropPlayback::compileImageInto(
171 const auto extent =
bitmaps.extent(surface);
173 return std::unexpected(
"UDBoard backdrop runtime surface is missing");
178 static_cast<std::int32_t
>(extent->width),
179 static_cast<std::int32_t
>(extent->height), 0x00000000U);
183 return bitmaps.blit(surface, sourceImage, 0, 0,
187 std::expected<void, std::string> BoardBackdropPlayback::compileInto(
192 if (!sourceImage)
return std::unexpected(sourceImage.error());
193 return compileImageInto(surface, *sourceImage,
playback);
196 std::expected<data::DataId, std::string> BoardBackdropPlayback::selectBackdrop(
198 std::uint32_t tick,
const std::filesystem::path& customRoot,
202 if (!
index)
return std::unexpected(
index.error());
203 const bool custom = city == -1;
215 std::uint32_t
oldest = mainBuffers_[0].timeLoaded;
216 std::optional<std::size_t>
found;
217 for (std::size_t
i = 0;
i < mainBuffers_.size(); ++
i)
219 if (
oldest > mainBuffers_[
i].timeLoaded)
221 oldest = mainBuffers_[
i].timeLoaded;
224 if (mainBuffers_[
i].cityLoaded == city &&
225 mainBuffers_[
i].viewLoaded ==
static_cast<int>(*
index) &&
226 (!
custom || mainBuffers_[
i].customRootLoaded == customRoot))
232 currentMainBuffer_ = *
found;
233 return mainBuffers_[*
found].surface;
236 std::expected<void, std::string>
compiled;
239 if (validatedCustomRoot_ != customRoot)
243 validatedCustomRoot_ = customRoot;
245 const auto sourceImage = loadCustomBoardBitmap(*
index, customRoot,
playback);
246 if (!sourceImage)
return std::unexpected(sourceImage.error());
259 mainBuffers_[
oldestIndex].viewLoaded =
static_cast<int>(*index);
262 ? customRoot : std::filesystem::path{};
276 return tradeSurface_;
279 return std::unexpected(
"UDBoard backdrop requested for non-board view");
307 ? std::optional<data::DataId>{} : std::optional{activeBackdrop_};
312 currentView_ =
inputs.view;
313 currentCity_.reset();
314 currentCamera_.reset();
315 currentCustomRoot_.clear();
322 if (
playback.commands().pendingCount() >=
324 return std::unexpected(
"sequence command queue capacity exceeded");
326 if (!stopped)
return stopped;
329 currentCity_.reset();
330 currentCamera_.reset();
331 currentCustomRoot_.clear();
338 if (
inputs.customRoot.empty() || !
inputs.customRoot.is_absolute())
339 return std::unexpected(
"custom UDBoard backdrop requires an absolute asset root");
341 validatedCustomRoot_ !=
inputs.customRoot)
345 validatedCustomRoot_ =
inputs.customRoot;
354 ?
inputs.customRoot : std::filesystem::path{};
357 currentView_ ==
inputs.view &&
358 currentCity_ ==
inputs.city &&
359 currentCamera_ ==
inputs.camera &&
365 if (
playback.commands().pendingCount() >
367 return std::unexpected(
"sequence command queue capacity exceeded");
371 const auto selected = selectBackdrop(
374 if (!selected)
return std::unexpected(selected.error());
377 const std::optional<data::DataId>
previous =
379 ? std::nullopt : std::optional<data::DataId>{activeBackdrop_};
384 activeBackdrop_ = *selected;
385 currentView_ =
inputs.view;
386 currentCity_ =
inputs.city;
387 currentCamera_ =
inputs.camera;
396 currentMainBuffer_.reset();
399 currentCity_.reset();
400 currentCamera_.reset();
401 currentCustomRoot_.clear();
402 validatedCustomRoot_.clear();
403 surfacesReady_ =
false;
LegacyBitmapMetadata metadata
std::vector< std::byte > bytes