///|
/// Stable, machine-readable asset report assembled from the independent
/// analyzers. Consumers can use this as a CI artifact without understanding
/// each internal pass.
///|
pub(all) struct AssetCounts {
scenes : Int
nodes : Int
meshes : Int
primitives : Int
materials : Int
textures : Int
images : Int
buffers : Int
buffer_views : Int
accessors : Int
animations : Int
skins : Int
} derive(Debug, ToJson, Eq)
///|
pub(all) struct GeometryReport {
vertices : Int
triangles : Int
draw_calls : Int
indexed_primitives : Int
unindexed_primitives : Int
transformed_nodes : Int
indexed_ratio : Double
} derive(Debug, ToJson, Eq)
///|
pub(all) struct ResourceReport {
declared_buffer_bytes : Int
view_bytes : Int
external_uri_count : Int
embedded_buffer_count : Int
embedded_image_count : Int
interleaved_view_count : Int
sparse_like_accessor_count : Int
} derive(Debug, ToJson, Eq)
///|
pub(all) struct AssetReport {
version : String
generator : String?
counts : AssetCounts
geometry : GeometryReport
resources : ResourceReport
scene : NodeTreeInfo
transforms : TransformReport
diagnostics : DiagnosticSummary
} derive(Debug, ToJson, Eq)
///|
pub fn count_document(doc : GltfDocument) -> AssetCounts {
let mut primitives = 0
for mesh in doc.meshes {
primitives += mesh.primitives.length()
}
{
scenes: doc.scenes.length(),
nodes: doc.nodes.length(),
meshes: doc.meshes.length(),
primitives,
materials: doc.materials.length(),
textures: doc.textures.length(),
images: doc.images.length(),
buffers: doc.buffers.length(),
buffer_views: doc.buffer_views.length(),
accessors: doc.accessors.length(),
animations: doc.animations.length(),
skins: doc.skins.length(),
}
}
///|
pub fn report_geometry(doc : GltfDocument) -> GeometryReport {
let mut vertices = 0
let mut draw_calls = 0
let mut triangles = 0
let mut indexed_primitives = 0
let mut unindexed_primitives = 0
for mesh in doc.meshes {
for primitive in mesh.primitives {
draw_calls += 1
vertices += primitive_vertex_count(doc, primitive)
triangles += primitive_estimated_triangle_count(doc, primitive)
if primitive_is_indexed(primitive) {
indexed_primitives += 1
} else {
unindexed_primitives += 1
}
}
}
{
vertices,
triangles,
draw_calls,
indexed_primitives,
unindexed_primitives,
transformed_nodes: count_transformed_nodes(doc),
indexed_ratio: document_indexed_primitive_ratio(doc),
}
}
///|
pub fn report_resources(doc : GltfDocument) -> ResourceReport {
let deps = collect_resource_deps(doc)
{
declared_buffer_bytes: buffer_total_declared_bytes(doc),
view_bytes: buffer_total_view_bytes(doc),
external_uri_count: deps.external_uris.length(),
embedded_buffer_count: deps.embedded_buffer_count,
embedded_image_count: deps.embedded_image_count,
interleaved_view_count: count_interleaved_views(doc),
sparse_like_accessor_count: count_sparse_like_accessors(doc),
}
}
///|
pub fn build_asset_report(
doc : GltfDocument,
policy : DiagnosticPolicy,
) -> AssetReport {
{
version: doc.version,
generator: doc.generator,
counts: count_document(doc),
geometry: report_geometry(doc),
resources: report_resources(doc),
scene: traverse_node_tree(doc),
transforms: evaluate_scene_transforms(doc),
diagnostics: diagnose(doc, policy),
}
}
///|
pub fn build_default_asset_report(doc : GltfDocument) -> AssetReport {
build_asset_report(doc, default_diagnostic_policy())
}
///|
pub fn report_has_errors(report : AssetReport) -> Bool {
report.diagnostics.errors > 0
}
///|
pub fn report_is_acceptable(report : AssetReport) -> Bool {
report.diagnostics.passed
}
///|
pub fn report_summary_lines(report : AssetReport) -> Array[String] {
[
"glTF version: \{report.version}",
"nodes=\{report.counts.nodes}, meshes=\{report.counts.meshes}, primitives=\{report.counts.primitives}",
"vertices=\{report.geometry.vertices}, triangles=\{report.geometry.triangles}, draw_calls=\{report.geometry.draw_calls}",
"buffers=\{report.counts.buffers}, declared_bytes=\{report.resources.declared_buffer_bytes}",
"diagnostics: errors=\{report.diagnostics.errors}, warnings=\{report.diagnostics.warnings}, infos=\{report.diagnostics.infos}",
]
}
///|
pub fn report_to_json(report : AssetReport) -> String {
Repr(report).to_string()
}