26 std::optional<Kakshya::MeshData> snapshot_mesh(
const std::shared_ptr<Buffers::VKBuffer>&
buffer)
28 if (
const auto mesh = std::dynamic_pointer_cast<Buffers::MeshBuffer>(
buffer)) {
29 return mesh->get_mesh_data();
32 if (
const auto network_buffer = std::dynamic_pointer_cast<Buffers::MeshNetworkBuffer>(
buffer)) {
33 const auto network = network_buffer->get_network();
37 if (
const auto geometry = std::dynamic_pointer_cast<Buffers::GeometryBuffer>(
buffer)) {
38 const auto node = std::dynamic_pointer_cast<Nodes::GpuSync::MeshWriterNode>(
39 geometry->get_geometry_node());
40 return node ? node->get_mesh_data() : std::nullopt;
43 if (
const auto compute = std::dynamic_pointer_cast<Buffers::ComputeMeshBuffer>(
buffer)) {
52 const auto it = std::ranges::find_if(layout.attributes,
53 [](
const auto& attribute) {
54 return attribute.component_modality == Kakshya::DataModality::VERTEX_POSITIONS_3D;
56 return it != layout.attributes.end() ? it->offset_in_vertex : 0;
59 std::span<const std::byte> vertex_bytes(
const Kakshya::MeshData& mesh)
61 const auto* vertices = std::get_if<std::vector<uint8_t>>(&mesh.vertex_variant);
62 return vertices ? std::as_bytes(std::span(*vertices)) :
std::span<const
std::byte> {};
65 std::optional<std::vector<glm::vec3>> decode_positions(
66 std::span<const uint8_t> bytes,
67 const Kakshya::VertexLayout& layout)
69 std::vector<Kakshya::DataVariant>
channels;
70 Kakshya::VertexInsertion insertion(
channels);
71 if (!insertion.insert_interleaved(bytes, layout)) {
75 const auto it = std::ranges::find_if(layout.attributes,
76 [](
const auto& attribute) {
77 return attribute.component_modality == Kakshya::DataModality::VERTEX_POSITIONS_3D;
79 if (it == layout.attributes.end()) {
83 auto*
positions = std::get_if<std::vector<glm::vec3>>(
84 &
channels.at(
static_cast<size_t>(it - layout.attributes.begin())));
85 return positions ? std::optional<std::vector<glm::vec3>> { std::move(*
positions) } : std::nullopt;
93 std::optional<Cloud> network_cloud(
const std::shared_ptr<Buffers::NetworkGeometryBuffer>&
buffer)
97 ?
dynamic_cast<const Nodes::Network::GraphicsOperator*
>(
network->get_operator())
103 const auto layout =
graphics->get_vertex_layout();
106 std::optional<std::vector<glm::vec3>>
positions;
107 if (
chain &&
chain->find<Nodes::Network::GpuFieldOperator>() &&
buffer->is_initialized()) {
108 std::vector<uint8_t> bytes(
graphics->get_vertex_count() * layout.stride_bytes);
109 std::shared_ptr<Buffers::VKBuffer> staging;
110 Buffers::download_from_gpu_async(
buffer, bytes.data(), bytes.size(), staging);
111 positions = decode_positions(bytes, layout);
119 return Cloud { .positions = std::move(*
positions), .clusters =
graphics->build_cluster_ids() };
122 bool field_driven(
const std::shared_ptr<Buffers::VKBuffer>&
buffer)
126 && (std::dynamic_pointer_cast<Buffers::VertexFieldProcessor>(
chain->get_postprocessor(
buffer))
127 ||
chain->get_processor<Buffers::VertexFieldProcessor>(
buffer));
130 std::optional<Cloud> node_cloud(
const std::shared_ptr<Buffers::GeometryBuffer>&
buffer)
132 const auto node =
buffer->get_geometry_node();
133 if (!node || std::dynamic_pointer_cast<Nodes::GpuSync::MeshWriterNode>(node)) {
137 const auto layout = node->get_vertex_layout();
142 std::optional<std::vector<glm::vec3>>
positions;
144 std::vector<uint8_t> bytes(
static_cast<size_t>(node->get_vertex_count()) * layout->stride_bytes);
145 std::shared_ptr<Buffers::VKBuffer> staging;
146 Buffers::download_from_gpu_async(
buffer, bytes.data(), bytes.size(), staging);
147 positions = decode_positions(bytes, *layout);
149 positions = decode_positions(node->get_vertex_data(), *layout);
155 return Cloud { .positions = std::move(*
positions), .clusters = {} };
158 std::optional<Cloud> cloud_of(
const std::shared_ptr<Buffers::VKBuffer>&
buffer)
160 if (
const auto network_buffer = std::dynamic_pointer_cast<Buffers::NetworkGeometryBuffer>(
buffer)) {
161 return network_cloud(network_buffer);
163 if (
const auto geometry = std::dynamic_pointer_cast<Buffers::GeometryBuffer>(
buffer)) {
164 return node_cloud(geometry);
169 std::optional<Kinesis::AABB3D> node_bounds(
const std::shared_ptr<Nodes::GpuSync::GeometryWriterNode>& node)
171 if (
const auto mesh = std::dynamic_pointer_cast<Nodes::GpuSync::MeshWriterNode>(node)) {
172 const auto& vertices = mesh->get_mesh_vertices();
173 return vertices.empty() ? std::nullopt : std::optional<Kinesis::AABB3D> { Kinesis::aabb(std::span(vertices)) };
176 const auto layout = node->get_vertex_layout();
177 const auto positions = layout ? decode_positions(node->get_vertex_data(), *layout) :
std::nullopt;
181 std::optional<Kinesis::AABB3D> instance_bounds(
const std::shared_ptr<Buffers::InstanceNetworkBuffer>&
buffer)
188 std::optional<Kinesis::AABB3D>
total;
189 for (uint32_t i = 0; i <
network->slot_count(); ++i) {
190 const auto& slot =
network->get_slot(i);
191 const auto local = slot.node ? node_bounds(slot.node) :
std::nullopt;
196 for (
int corner = 0; corner < 8; ++corner) {
197 const glm::vec3
point {
198 (corner & 1) != 0 ? local->max.x : local->
min.x,
199 (corner & 2) != 0 ? local->
max.y : local->
min.y,
200 (corner & 4) != 0 ? local->
max.z : local->
min.z,
202 const glm::vec3 placed = glm::vec3(slot.transform * glm::vec4(point, 1.0F));
204 ? Kinesis::AABB3D { .min = glm::min(
total->min, placed), .max = glm::max(
total->max, placed) }
205 : Kinesis::AABB3D { .min = placed, .max = placed };
214 const std::shared_ptr<Buffers::VKBuffer>& buf,
215 const std::optional<uint32_t>&
index)
217 if (
const auto cloud = cloud_of(buf); cloud && !cloud->positions.empty()) {
219 return Kinesis::centroid(cloud->positions);
221 return *
index < cloud->positions.size()
222 ? std::optional<glm::vec3> { cloud->positions.at(*
index) }
226 if (
const auto instances = std::dynamic_pointer_cast<Buffers::InstanceNetworkBuffer>(buf);
227 instances && !
index) {
228 const auto bounds = instance_bounds(instances);
229 return bounds ? std::optional<glm::vec3> { bounds->center() } : std::nullopt;
232 const auto mesh = snapshot_mesh(buf);
237 const auto bytes = vertex_bytes(*mesh);
242 const size_t stride = mesh->layout.stride_bytes;
246 return Kinesis::position_at(bytes, stride,
offset, *
index);
249 if (
const auto* faces = std::get_if<std::vector<uint32_t>>(&mesh->index_variant);
250 faces && !faces->empty()) {
251 return Kinesis::surface_centroid(bytes, stride,
offset, *faces);
253 return Kinesis::centroid(bytes, stride,
offset);
257 const std::shared_ptr<Buffers::VKBuffer>& buf,
258 const std::optional<uint32_t>& collection)
260 if (
const auto volume = std::dynamic_pointer_cast<Buffers::VolumeGridBuffer>(buf)) {
261 return volume->get_bounds();
264 if (
const auto network_buffer = std::dynamic_pointer_cast<Buffers::NetworkGeometryBuffer>(buf)) {
265 const auto cloud = network_cloud(network_buffer);
266 if (!cloud || cloud->positions.empty()) {
270 return Kinesis::aabb(cloud->positions);
273 std::vector<glm::vec3> chosen;
274 const size_t count = std::min(cloud->positions.size(), cloud->clusters.size());
275 for (
size_t i = 0; i <
count; ++i) {
276 if (cloud->clusters.at(i) == *collection) {
277 chosen.push_back(cloud->positions.at(i));
280 return chosen.empty() ? std::nullopt : std::optional<Kinesis::AABB3D> { Kinesis::aabb(chosen) };
283 if (
const auto geometry = std::dynamic_pointer_cast<Buffers::GeometryBuffer>(buf)) {
284 if (
const auto cloud = node_cloud(geometry); cloud && !cloud->positions.empty()) {
285 return Kinesis::aabb(cloud->positions);
289 if (
const auto instances = std::dynamic_pointer_cast<Buffers::InstanceNetworkBuffer>(buf)) {
290 return instance_bounds(instances);
293 const auto mesh = snapshot_mesh(buf);
294 const auto* vertices = mesh ? std::get_if<std::vector<uint8_t>>(&mesh->vertex_variant) :
nullptr;
299 const auto positions = decode_positions(*vertices, mesh->layout);
305 const auto proc = buf->get_render_processor();
307 return glm::mat4(1.0F);
309 if (
const auto& source = proc->get_geometry_transform_source()) {
312 if (
const auto& fixed = proc->get_geometry_transform()) {
315 return glm::mat4(1.0F);
Core::GlobalNetworkConfig network
Core::GlobalGraphicsConfig graphics
std::shared_ptr< NetworkGeometryBuffer > buffer
BufferProcessingChain * chain
std::vector< glm::vec3 > positions
std::vector< glm::vec3 > positions
std::vector< uint32_t > clusters
std::optional< Kakshya::MeshData > download_compute_mesh(const std::shared_ptr< ComputeMeshBuffer > &buffer)
Download a ComputeMeshBuffer's current live geometry to CPU.
glm::mat4 read_placement(const std::shared_ptr< Buffers::VKBuffer > &buf)
Where a buffer is drawn: the geometry transform of its primary render processor.
std::optional< glm::vec3 > read_anchor(const std::shared_ptr< Buffers::VKBuffer > &buf, const std::optional< uint32_t > &index)
Anchor of a buffer's geometry in its own stored coordinates.
std::optional< Kinesis::AABB3D > read_bounds(const std::shared_ptr< Buffers::VKBuffer > &buf, const std::optional< uint32_t > &collection)
Bounds of a buffer's geometry in its own stored coordinates.