use molgfx_core::{Representation, RowDomain, Scene, StructureHandle, VisualAttributeRef};
use molgfx_geometry::ColorContext;
type Resolved<'a> = (ColorContext<'a>, [u64; 2]);
pub(super) type VisualResolved = ([Option<VisualAttributeRef>; 4], [u64; 4]);
pub(super) fn resolve<'a>(
scene: &'a Scene,
representation: &Representation,
structure: StructureHandle,
) -> Resolved<'a> {
let columns = representation.color_columns();
let revision = |handle: molgfx_core::AtomPropertyHandle| content_revision(scene, handle);
let scheme_revision = columns
.handles()
.filter(|handle| Some(*handle) != columns.appearance)
.fold(0_u64, |folded, handle| mix(folded, revision(handle)));
let appearance_revision = match columns.appearance {
Some(handle) => revision(handle),
None => 0,
};
(
ColorContext::new(scene, structure),
[scheme_revision, appearance_revision],
)
}
fn content_revision(scene: &Scene, handle: molgfx_core::AtomPropertyHandle) -> u64 {
let Some(revision) = scene.property_content_revision(handle) else {
return 0;
};
revision
}
const fn mix(folded: u64, revision: u64) -> u64 {
(folded ^ revision.wrapping_add(0x9e37_79b9_7f4a_7c15)).wrapping_mul(0x0100_0000_01b3)
}
pub(super) fn resolve_visual(
scene: &Scene,
representation: &Representation,
structure: StructureHandle,
) -> VisualResolved {
let handles = representation.visual.as_ref().map_or_else(
|| [None; 4],
|style| {
let mut handles = [None; 4];
for (slot, handle) in style.program().attributes().iter().enumerate() {
if slot == handles.len() {
break;
}
handles[slot] = Some(*handle);
}
handles
},
);
let handles = handles.map(|handle| {
handle.filter(|reference| match *reference {
VisualAttributeRef::Attribute { handle, kind } => scene
.attribute_for_domain(handle, RowDomain::Atoms(structure))
.is_some_and(|attribute| attribute.kind() == kind),
VisualAttributeRef::LegacyScalar(handle) => {
scene.property_for_structure(handle, structure).is_some()
}
VisualAttributeRef::Column { .. } => false,
})
});
let revisions = handles.map(|reference| match reference {
Some(VisualAttributeRef::Attribute { handle, .. }) => {
scene.attribute_change(handle).map_or(0, |change| change.0)
}
Some(VisualAttributeRef::LegacyScalar(handle)) => scene
.property_content_revision(handle)
.into_iter()
.fold(0, |_, revision| revision),
Some(VisualAttributeRef::Column { .. }) | None => 0,
});
(handles, revisions)
}