22 constexpr std::array<ModernEnvironmentDefinition, ModernEnvironmentCount>
Definitions{{
23 {
"fountain",
"environment/paris_fountain.glb",
25 {0.0F, 0.12F, -2.0F}, -90.0F},
26 {
"station",
"environment/paris_station.glb",
28 {-5.5F, 0.12F, -5.9F}, -90.0F},
29 {
"morris",
"environment/paris_morris_column.glb",
31 {3.9F, 0.0F, -4.1F}, -90.0F}
41 constexpr std::array<ModernEnvironmentDefinition, ModernCityCount>
CityDefinitions{{
72 if (mesh.vertices.empty() || mesh.indices.empty() || mesh.batches.empty() ||
73 mesh.indices.size() % 3U != 0
U)
return false;
75 if (!std::isfinite(mesh.bounds.minimum[
axis]) ||
76 !std::isfinite(mesh.bounds.maximum[
axis]) ||
77 mesh.bounds.minimum[
axis] > mesh.bounds.maximum[
axis])
return false;
78 for (
const auto& vertex : mesh.vertices)
80 if (!std::isfinite(vertex.position[
axis]) ||
81 !std::isfinite(vertex.normal[
axis]))
return false;
82 for (
const auto index : mesh.indices)
84 for (
const auto&
batch : mesh.batches)
93 const std::array<ModernEnvironmentDefinition, ModernEnvironmentCount>&
102 const auto hardware=std::thread::hardware_concurrency();
104 if (loader_) decodeWorkers_ = 1;
105 else if (
const auto*
value = std::getenv(
"MONOPOLY_ENVIRONMENT_WORKERS"))
115 void ModernEnvironment::report(std::string_view message)
const
117 if (diagnostic_) diagnostic_(message);
118 else std::cerr <<
"Modern environment: " << message <<
'\n';
121 void ModernEnvironment::loadPending(
const std::vector<std::size_t>& indices)
123 struct Result { std::shared_ptr<const data::MeshRuntimeAsset> asset;
bool failed{}; std::string
error; };
124 std::vector<std::size_t> pending;
125 for(
const auto index:indices)
127 if(pending.empty())
return;
128 std::vector<Result>
results(pending.size());
131 std::atomic<std::size_t>
next{};
132 const auto decode=[&]()
noexcept
136 const auto slot=
next.fetch_add(1,std::memory_order_relaxed);
137 if(
slot>=pending.size())
return;
142 data::ModernGltfLoadOptions options;
144 options.yawDegrees=
definition.localYawDegrees;
145 options.localOffset={};options.groundToZero=
false;
151 result.error=std::string(
definition.slug)+
": skipped "+
152 (
loaded ?
"invalid native geometry" :
loaded.error().detail);
155 auto asset=std::make_shared<data::MeshRuntimeAsset>();
157 asset->renderData=std::move(*
loaded);result.asset=std::move(asset);
164 try { result.error=std::string(
definition.slug)+
": skipped decode exception: "+
exception.what(); }
170 try { result.error=std::string(
definition.slug)+
": skipped unknown decode exception"; }
177 const auto workers=std::min<std::size_t>(decodeWorkers_,pending.size());
178 std::vector<std::jthread>
threads;
182 for(std::size_t worker=1;worker<
workers;++worker)
threads.emplace_back(decode);
184 catch(
const std::exception&) { }
201 assets_[
index].reset();
202 attempted_[
index] =
true;
205 if (
dropped) report(
"dropped rejected native GPU geometry");
212 std::vector<sequence::SequenceMeshRenderItem> result;
213 if (!enabled_)
return result;
215 [](
float value) { return std::isfinite(value); }))
217 if (!invalidMatrixReported_)
219 invalidMatrixReported_ =
true;
220 report(
"skipped invalid board transform");
226 result.reserve(
count);
227 std::vector<std::size_t> selected;
235 selected.push_back(
index);
237 loadPending(selected);
238 for (
const auto index:selected)
240 if (!assets_[
index])
continue;
242 const auto& position = definition.originalYup;
248 item.
node = definition.node;
253 item.
clock =
static_cast<std::int32_t
>(std::min(tick,
254 static_cast<std::uint32_t
>(std::numeric_limits<std::int32_t>::max())));
260 result.push_back(std::move(item));
std::vector< std::uint8_t > data
std::function< std::expected< std::shared_ptr< const data::MeshRenderData >, data::MeshRuntimeError >(const std::filesystem::path &, data::ModernGltfLoadOptions)> Loader
std::function< void(std::string_view)> Diagnostic
std::vector< sequence::SequenceMeshRenderItem > items(const sequence::Matrix3D &boardMatrix, std::uint32_t tick, bool includePresentation=false, bool includeLandmarks=true, bool includeCity=false)
ModernEnvironment()=default
void rejectGeometry(const data::MeshRenderData *geometry)
bool decode(std::span< const std::uint8_t > data, State &result) noexcept
constexpr DataId EmptyDataId
std::expected< std::shared_ptr< const MeshRenderData >, MeshRuntimeError > loadModernGltfMesh(const std::filesystem::path &path, ModernGltfLoadOptions options)
constexpr DataId packDataId(std::uint16_t group, DataTag tag) noexcept
constexpr std::uint16_t Board3DPriority
const std::array< ModernEnvironmentDefinition, ModernEnvironmentCount > & modernEnvironmentDefinitions() noexcept
constexpr sequence::SequenceNodeId ModernEnvironmentNodeBase
constexpr std::uint16_t ModernEnvironmentLogicalGroup
const SquareDefinition & definition(SquareType square)
Matrix3D translate3D(float x, float y, float z) noexcept
Matrix2D multiply(const Matrix2D &left, const Matrix2D &right) noexcept
data::DataId contentsDataId
data::DataId rootSequenceDataId
std::shared_ptr< const data::MeshRuntimeAsset > asset
std::shared_ptr< const data::MeshRenderData > renderData