10 const sequence::Matrix2D&
matrix,
float x,
float y)
noexcept
13 const float outX =
m[0] *
x +
m[3] *
y +
m[6];
14 const float outY =
m[1] *
x +
m[4] *
y +
m[7];
15 const float outW =
m[2] *
x +
m[5] *
y +
m[8];
16 if (
outW == 0.0F)
return {};
21 const sequence::SequenceScrollingWorldView& view,
22 const sequence::Matrix2D& worldToScreen)
noexcept
25 !std::holds_alternative<sequence::Matrix2D>(view.worldTransform))
28 const auto&
box = *view.bounds2D;
30 std::get<sequence::Matrix2D>(view.worldTransform), worldToScreen);
31 const std::array points{
33 static_cast<float>(
box.left),
34 static_cast<float>(
box.top)),
36 static_cast<float>(
box.right),
37 static_cast<float>(
box.top)),
39 static_cast<float>(
box.left),
40 static_cast<float>(
box.bottom)),
42 static_cast<float>(
box.right),
43 static_cast<float>(
box.bottom))};
45 float left = points.front()[0];
47 float top = points.front()[1];
49 for (
const auto& point : points)
53 top = std::min(
top, point[1]);
63 const auto found = spatialSounds2D_.find(node);
64 return found == spatialSounds2D_.end() ? std::nullopt :
65 std::optional<std::int32_t>{
found->second.screenCenterX};
70 for (
const auto id : europeanDeeds_)
72 retiredDeeds_.push_back(
id);
79 const auto snapshot = resources();
83 static constexpr std::array<int, 28> squares{
84 1,3,5,6,8,9,11,12,13,14,15,16,18,19,
85 21,23,24,25,26,27,28,29,31,32,34,35,37,39};
86 const auto found = std::find(squares.begin(), squares.end(), square);
88 const auto property = std::distance(squares.begin(),
found);
89 return europeanDeeds_[
static_cast<std::size_t
>(
property + (front ? 0 : 28))];
99 if (nextRuntimeVideoTag_ == 0)
100 nextRuntimeVideoTag_ = 1;
102 RuntimeVideoGroup, nextRuntimeVideoTag_++);
103 if (runtimePrograms_.contains(
id))
107 id, std::move(fileName), options, bounds, binkDoubleSize);
109 return std::unexpected(program.error().detail);
110 runtimePrograms_.emplace(
id, *program);
113 return std::unexpected(
"runtime video DataID space exhausted");
118 return runtimePrograms_.erase(
id) != 0;
123 int city,
int currency,
const std::filesystem::path& customRoot)
127 return std::unexpected(
"board textures require a resource snapshot");
128 const auto context =
resources->context();
129 const BoardTextureSelection selection{
130 mesh, resolution, context.board, context.language, city, currency, customRoot};
131 if (boardTextureSelection_ == selection)
return {};
136 if (!
recipe)
return std::unexpected(std::string(
recipe.error().detail));
138 {context.board, context.language, city, currency, customRoot});
142 boardTextureSelection_ = selection;
146 std::expected<std::shared_ptr<const sequence::SequenceProgram>, std::string>
149 if (
const auto found = runtimePrograms_.find(
id);
150 found != runtimePrograms_.end())
151 return found->second;
156 if (!program)
return std::unexpected(program.error().detail);
160 if (!program)
return std::unexpected(program.error().detail);
168 if (!program)
return std::unexpected(program.error());
170 *program,
priority, {}, std::nullopt, labelOverride});
172 return std::unexpected(
"sequence command queue capacity exceeded");
178 std::int32_t
x, std::int32_t
y,
bool dropFrames,
179 std::uint8_t labelOverride)
182 if (!program)
return std::unexpected(program.error());
188 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
194 std::int32_t
x, std::int32_t
y,
bool dropFrames,
195 std::uint8_t labelOverride)
202 std::int32_t
x, std::int32_t
y,
203 float scale,
float rotate)
206 if (!program)
return std::unexpected(program.error());
212 return std::unexpected(
213 "sequence command queue capacity exceeded");
219 float yaw,
float scale,
float x,
float z)
222 if (!program)
return std::unexpected(program.error());
228 return std::unexpected(
229 "sequence command queue capacity exceeded");
235 float yaw,
float scale,
float x,
float z,
239 if (!program)
return std::unexpected(program.error());
247 return std::unexpected(
248 "sequence command queue capacity exceeded");
255 std::uint16_t
priority, std::int32_t
x, std::int32_t
y,
259 if (!program)
return std::unexpected(program.error());
262 return std::unexpected(
"sequence command queue capacity exceeded");
265 const auto stopped = commands_.
enqueue(
267 if (!stopped)
return std::unexpected(
"sequence command queue capacity exceeded");
273 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
279 if (action == 0 || action > 3)
280 return std::unexpected(
"invalid sequence ending action");
283 if (!queued)
return std::unexpected(
"sequence command queue rejected ending action");
293 return std::unexpected(
294 "sequence command queue rejected volume change");
302 const auto queued = commands_.
enqueue(
306 return std::unexpected(
307 "sequence command queue rejected pitch change");
314 const auto queued = commands_.
enqueue(
318 return std::unexpected(
319 "sequence command queue rejected panning change");
326 const auto queued = commands_.
enqueue(
329 return std::unexpected(
330 "sequence command queue rejected redraw");
339 if (!program)
return std::unexpected(program.error());
341 *program,
priority, {}, std::move(transform)});
342 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
349 const auto queued = commands_.
enqueue(
351 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
360 id,
priority, std::move(transform)));
361 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
368 std::uint8_t endingAction)
371 if (!program)
return std::unexpected(program.error());
372 if (endingAction == 0 || endingAction > 3)
373 return std::unexpected(
"invalid sequence ending action");
377 return std::unexpected(
"sequence command queue capacity exceeded");
381 auto queued = commands_.
enqueue(
383 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
389 *program,
priority, options, std::move(transform)});
390 if (!queued)
return std::unexpected(
"sequence command queue capacity exceeded");
393 if (!queued)
return std::unexpected(
"sequence command queue rejected ending action");
399 std::uint16_t
priority,
float yaw,
float scale,
float x,
float z)
413 return std::unexpected(
414 "sequence command queue rejected World3D viewport");
425 if (!queued)
return std::unexpected(
"sequence command queue rejected World3D camera");
430 std::uint8_t cameraNumber)
434 {0.0F, 0.0F, -500.0F}, {0.0F, 0.0F, 1.0F},
435 {0.0F, 1.0F, 0.0F}, 0.785398F, 1.0F, 1000.0F});
436 if (!queued)
return std::unexpected(
"sequence command queue rejected camera label");
441 std::vector<sequence::SequenceMeshRenderItem> items)
443 if (items.empty() && nativeSceneItems_.empty())
return {};
444 nativeSceneItems_ = std::move(items);
445 return publishRuntimeViews();
448 std::expected<void, std::string> SequencePlayback::publishRuntimeViews()
450 for (
const auto&
outcome : commands_.outcomes())
455 return std::unexpected(
outcome.error->detail);
463 return std::unexpected(items.error().cause.detail);
466 items->insert(items->end(), nativeSceneItems_.begin(), nativeSceneItems_.end());
468 runtime_, meshes_.
resources(), &runtimeBitmaps_);
473 return std::unexpected(
bitmapItems.error().detail);
479 for (
const auto& sound :
sounds)
481 if (!sound.spatial2D)
continue;
482 const auto&
spatial = *sound.spatial2D;
483 const auto previous = spatialSounds2D_.find(sound.node);
484 if (
previous != spatialSounds2D_.end() &&
485 previous->second.movementRevision ==
spatial.movementRevision)
continue;
487 spatialSounds2D_[sound.node] = {
spatial.movementRevision,
490 std::erase_if(spatialSounds2D_, [&](
const auto&
entry) {
491 return std::ranges::none_of(
sounds, [&](
const auto& sound) {
492 return sound.node ==
entry.first && sound.spatial2D.has_value();
502 camera->bounds =
bitmap.bounds.value_or(data::Sequence2DBoundingBoxAttribute{
523 return std::unexpected(
"duplicate sequence render node");
526 for (
const auto& scrolling : runtime_.scrollingWorldInstances())
529 if (scrolling.dimensionality == 2)
531 else if (scrolling.dimensionality == 3 &&
532 scrolling.bounds3D &&
533 std::holds_alternative<sequence::Matrix3D>(
534 scrolling.worldTransform))
537 std::get<sequence::Matrix3D>(
538 scrolling.worldTransform));
540 if (visible == scrolling.onScreen)
543 scrolling.node, visible);
545 return std::unexpected(changed.error().detail);
552 [
id](
const auto& item) { return item.contentsDataId == id; }))
566 const auto result = commands_.
collect();
568 return std::unexpected(
"sequence command collection nesting overflow");
574 const auto result = commands_.
execute();
576 return std::unexpected(
"sequence command execution nesting overflow");
581 return std::unexpected(
outcome.error->detail);
592 return std::unexpected(updated.error().detail);
594 return publishRuntimeViews();
600 if (!flushed)
return flushed;
602 spatialSounds2D_.clear();
607 runtimePrograms_.clear();
608 retiredDeeds_.clear();
619 return std::unexpected(updated.error().detail);
621 return publishRuntimeViews();
std::atomic< float > left
std::atomic< float > right
LegacyBitmapMetadata metadata
std::size_t releaseUnused() noexcept
std::size_t releaseUnused() noexcept
std::expected< void, MeshRuntimeError > replaceTextureImages(DataId id, std::span< const std::shared_ptr< const HmdTextureImage > > images)
std::shared_ptr< const ResourceSnapshot > resources() const noexcept
bool contains(DataId id) const noexcept
bool remove(DataId id) noexcept
std::optional< std::int32_t > soundScreenCenterX2D(sequence::SequenceNodeId node) const noexcept
std::expected< void, std::string > move(data::DataId id, std::uint16_t priority, sequence::SequenceTransform transform)
std::expected< int, std::string > collectCommands()
std::expected< void, std::string > forceRedraw(data::DataId id, std::uint16_t priority)
std::expected< void, std::string > setNativeSceneItems(std::vector< sequence::SequenceMeshRenderItem > items)
std::expected< void, std::string > setViewport3D(World3DRect viewport)
std::expected< void, std::string > setVolume(data::DataId id, std::uint16_t priority, std::uint8_t volume)
std::expected< void, std::string > configureBoardTextures(data::BoardMeshKind mesh, data::TextureResolution resolution, int city, int currency, const std::filesystem::path &customRoot={})
std::expected< void, std::string > start(data::DataId id, std::uint16_t priority=0, std::uint8_t labelOverride=0)
std::expected< void, std::string > transitionXY(std::optional< data::DataId > previousId, data::DataId id, std::uint16_t priority, std::int32_t x, std::int32_t y, bool dropFrames=false)
std::expected< void, std::string > startMoved(data::DataId id, std::uint16_t priority, sequence::SequenceTransform transform)
std::expected< void, std::string > transitionMovedDrop(std::optional< data::DataId > previousId, data::DataId id, std::uint16_t priority, sequence::SequenceTransform transform, std::uint8_t endingAction)
std::expected< void, std::string > update(std::int32_t tick)
std::expected< void, std::string > startRySTxzDrop(data::DataId id, std::uint16_t priority, float yaw, float scale, float x, float z, bool dropFrames)
std::expected< void, std::string > setEndingAction(data::DataId id, std::uint16_t priority, std::uint8_t action)
std::expected< void, std::string > setCamera3D(const World3DCamera &camera)
std::expected< void, std::string > stop(data::DataId id, std::uint16_t priority)
std::expected< void, std::string > startXYDrop(data::DataId id, std::uint16_t priority, std::int32_t x, std::int32_t y, bool dropFrames=true, std::uint8_t labelOverride=0)
std::expected< void, std::string > transitionRySTxzDropStayAtEnd(std::optional< data::DataId > previousId, data::DataId id, std::uint16_t priority, float yaw, float scale, float x, float z)
std::expected< std::shared_ptr< const sequence::SequenceProgram >, std::string > loadProgram(data::DataId id)
bool freeRuntimeSequence(data::DataId id) noexcept
data::DataId deedDataId(int square, bool front, data::DataId staticFallback) const noexcept
std::expected< void, std::string > setCameraNumber(std::uint8_t cameraNumber)
std::expected< void, std::string > startXYSR(data::DataId id, std::uint16_t priority, std::int32_t x, std::int32_t y, float scale, float rotate)
std::expected< int, std::string > executeCommands()
std::expected< void, std::string > setPitch(data::DataId id, std::uint16_t priority, std::uint16_t pitch)
std::expected< void, std::string > stopAll()
std::expected< void, std::string > startXY(data::DataId id, std::uint16_t priority, std::int32_t x, std::int32_t y, bool dropFrames=false, std::uint8_t labelOverride=0)
std::expected< void, std::string > setPanning(data::DataId id, std::uint16_t priority, std::int8_t panning)
std::expected< void, std::string > processUserCommands()
std::expected< void, std::string > startRySTxz(data::DataId id, std::uint16_t priority, float yaw, float scale, float x, float z)
std::shared_ptr< const data::ResourceSnapshot > resources() const noexcept
std::expected< data::DataId, std::string > createVideoObject(std::string fileName, data::SequenceVideoData options, data::Sequence2DBoundingBoxAttribute bounds, bool binkDoubleSize=false)
void setEuropeanDeeds(const std::array< data::DataId, 56 > &ids)
static std::array< std::int32_t, 2 > boundsCenter(const sequence::Matrix2D &matrix, const data::Sequence2DBoundingBoxAttribute &bounds) noexcept
void updateCamera(const std::optional< sequence::SequenceCamera2DView > &camera) noexcept
static constexpr std::uint8_t cameraLabel() noexcept
const sequence::Matrix2D & worldToScreen() const noexcept
std::expected< SequenceWorld2DSyncStats, std::string > sync(const std::vector< sequence::SequenceBitmapRenderItem > &items, data::BitmapRuntimeCache &cache)
std::expected< SequenceWorld3DSyncStats, SequenceWorld3DSlotError > sync(const std::vector< sequence::SequenceMeshRenderItem > &items)
bool boundsVisible(const sequence::SequenceBounds3D &bounds, const sequence::Matrix3D &worldTransform) const noexcept
static constexpr std::size_t Capacity
std::span< const SequenceCommandOutcome > outcomes() const noexcept
std::expected< int, CommandQueueError > execute()
std::expected< void, RuntimeError > updateCycle(std::int32_t parentClock)
std::expected< void, RuntimeError > processUserCommands()
std::size_t pendingCount() const noexcept
const std::optional< RuntimeError > & lastCycleError() const noexcept
std::expected< void, CommandQueueError > enqueue(StartSequenceCommand command)
std::expected< int, CommandQueueError > collect()
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > rawBitmap(data::DataId id, data::LegacyDataType sourceType, DescriptionLimits limits={})
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > load(const data::DataSource &source, data::DataId id, std::size_t offset=0, DescriptionLimits limits={})
static std::expected< std::shared_ptr< const SequenceProgram >, RuntimeError > runtimeVideo(data::DataId id, std::string fileName, data::SequenceVideoData options, data::Sequence2DBoundingBoxAttribute bounds, bool binkDoubleSize=false)
std::optional< SequenceCamera2DView > camera2DForLabel(std::uint8_t label) const
std::vector< SequenceSoundInstanceView > soundInstances() const
std::expected< void, RuntimeError > setScrollingWorldVisibility(SequenceNodeId node, bool onScreen)
constexpr DataId EmptyDataId
BoardTextureRecipeResult buildUsaTextureRecipe(BoardMeshKind mesh, TextureResolution resolution)
std::expected< std::vector< std::shared_ptr< const HmdTextureImage > >, std::string > loadBoardTextureImages(const ResourcePaths &paths, const BoardTextureRecipe &recipe, const BoardTextureContext &context)
constexpr DataId packDataId(std::uint16_t group, DataTag tag) noexcept
BoardTextureRecipeResult buildEuropeanTextureRecipe(BoardMeshKind mesh, TextureResolution resolution)
std::expected< std::vector< SequenceMeshRenderItem >, SequenceRenderDataError > collectSequenceMeshRenderData(const SequenceRuntime &runtime, data::MeshRuntimeCache &meshes)
std::expected< std::vector< SequenceBitmapRenderItem >, SequenceBitmapRenderDataError > collectSequenceBitmapRenderData(const SequenceRuntime &runtime, std::shared_ptr< const data::ResourceSnapshot > resources, const data::RuntimeBitmapStore *runtimeBitmaps)
MoveSequenceCommand makeMoveTheWorks(data::DataId dataId, std::uint16_t priority, SequenceTransform transform, bool wholeTree) noexcept
Matrix3D moveRySTxzTransform(float yaw, float scale, float x, float z) noexcept
std::variant< std::monostate, Matrix2D, Matrix3D > SequenceTransform
std::uint64_t SequenceNodeId
Matrix2D moveXYSRTransform(std::int32_t x, std::int32_t y, float scale, float rotate) noexcept
SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
MoveSequenceCommand makeMoveRySTxz(data::DataId dataId, std::uint16_t priority, float yaw, float scale, float x, float z) noexcept
Matrix2D multiply(const Matrix2D &left, const Matrix2D &right) noexcept
std::array< float, 3 > location
std::array< float, 3 > forward
std::array< float, 3 > up
std::optional< bool > dropFrames