use crate::resources::handles::TextureHandle;
use crate::resources::id::{ResourceId, ResourceId32};
use crate::v2_0::vertex::{VertexIndex, VertexRef};
#[repr(C)]
#[derive(Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub(crate) struct TextureMapCore<VR: VertexRef, RR: ResourceId> {
vertices: Vec<Option<VertexIndex<VR>>>,
rings: Vec<VertexIndex<VR>>,
ring_textures: Vec<Option<RR>>,
}
impl<VR: VertexRef, RR: ResourceId> TextureMapCore<VR, RR> {
pub(crate) fn is_empty(&self) -> bool {
self.vertices.is_empty() && self.rings.is_empty() && self.ring_textures.is_empty()
}
pub(crate) fn add_vertex(&mut self, vertex: Option<VertexIndex<VR>>) {
self.vertices.push(vertex);
}
pub(crate) fn add_ring(&mut self, ring_start: VertexIndex<VR>) {
self.rings.push(ring_start);
}
pub(crate) fn add_ring_texture(&mut self, texture: Option<RR>) {
self.ring_textures.push(texture);
}
pub(crate) fn vertices(&self) -> &[Option<VertexIndex<VR>>] {
&self.vertices
}
pub(crate) fn vertices_mut(&mut self) -> &mut [Option<VertexIndex<VR>>] {
&mut self.vertices
}
pub(crate) fn rings(&self) -> &[VertexIndex<VR>] {
&self.rings
}
pub(crate) fn rings_mut(&mut self) -> &mut [VertexIndex<VR>] {
&mut self.rings
}
pub(crate) fn ring_textures(&self) -> &[Option<RR>] {
&self.ring_textures
}
pub(crate) fn ring_textures_mut(&mut self) -> &mut [Option<RR>] {
&mut self.ring_textures
}
}
#[repr(C)]
#[derive(Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct TextureMap<VR: VertexRef> {
inner: TextureMapCore<VR, ResourceId32>,
}
impl<VR: VertexRef> TextureMap<VR> {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn add_vertex(&mut self, vertex: Option<VertexIndex<VR>>) {
self.inner.add_vertex(vertex);
}
pub fn add_ring(&mut self, ring_start: VertexIndex<VR>) {
self.inner.add_ring(ring_start);
}
pub fn add_ring_texture(&mut self, texture: Option<TextureHandle>) {
self.inner
.add_ring_texture(texture.map(super::super::handles::TextureHandle::to_raw));
}
#[must_use]
pub fn vertices(&self) -> &[Option<VertexIndex<VR>>] {
self.inner.vertices()
}
pub fn vertices_mut(&mut self) -> &mut [Option<VertexIndex<VR>>] {
self.inner.vertices_mut()
}
#[must_use]
pub fn rings(&self) -> &[VertexIndex<VR>] {
self.inner.rings()
}
pub fn rings_mut(&mut self) -> &mut [VertexIndex<VR>] {
self.inner.rings_mut()
}
#[must_use]
pub fn ring_textures(&self) -> Vec<Option<TextureHandle>> {
self.inner
.ring_textures()
.iter()
.copied()
.map(|r| r.map(TextureHandle::from_raw))
.collect()
}
pub fn set_ring_texture(&mut self, ring_index: usize, texture: Option<TextureHandle>) -> bool {
let Some(slot) = self.inner.ring_textures_mut().get_mut(ring_index) else {
return false;
};
*slot = texture.map(super::super::handles::TextureHandle::to_raw);
true
}
#[allow(dead_code)]
pub(crate) fn from_raw(inner: TextureMapCore<VR, ResourceId32>) -> Self {
Self { inner }
}
#[allow(dead_code)]
pub(crate) fn into_raw(self) -> TextureMapCore<VR, ResourceId32> {
self.inner
}
#[allow(dead_code)]
pub(crate) fn to_raw(&self) -> &TextureMapCore<VR, ResourceId32> {
&self.inner
}
}
#[cfg(test)]
mod texture_map {
use super::*;
use crate::resources::id::ResourceId32;
type Core = TextureMapCore<u32, ResourceId32>;
fn make_tex_id(index: u32) -> ResourceId32 {
ResourceId32::new(index, 0)
}
fn vi(n: u32) -> VertexIndex<u32> {
VertexIndex::new(n)
}
#[test]
fn ring_count_matches_uv_vertex_count() {
let mut core = Core::default();
core.add_vertex(Some(vi(0)));
core.add_vertex(Some(vi(1)));
core.add_vertex(Some(vi(2)));
core.add_ring(vi(0));
core.add_ring_texture(Some(make_tex_id(0)));
assert_eq!(core.vertices().len(), 3);
assert_eq!(core.rings().len(), 1);
assert_eq!(core.ring_textures().len(), 1);
}
#[test]
fn ring_texture_can_be_none() {
let mut core = Core::default();
core.add_vertex(Some(vi(0)));
core.add_ring(vi(0));
core.add_ring_texture(None);
assert!(core.ring_textures()[0].is_none());
}
#[test]
fn multi_ring_multi_texture() {
let mut core = Core::default();
core.add_vertex(Some(vi(0)));
core.add_vertex(Some(vi(1)));
core.add_vertex(Some(vi(2)));
core.add_ring(vi(0));
core.add_ring_texture(Some(make_tex_id(0)));
core.add_vertex(Some(vi(0)));
core.add_vertex(Some(vi(2)));
core.add_vertex(Some(vi(3)));
core.add_ring(vi(3));
core.add_ring_texture(Some(make_tex_id(1)));
assert_eq!(core.vertices().len(), 6);
assert_eq!(core.rings().len(), 2);
assert_eq!(core.ring_textures().len(), 2);
assert_eq!(core.ring_textures()[0], Some(make_tex_id(0)));
assert_eq!(core.ring_textures()[1], Some(make_tex_id(1)));
}
#[test]
fn vertex_reuse_different_uvs_per_ring() {
let mut core = Core::default();
core.add_vertex(Some(vi(0))); core.add_vertex(Some(vi(1))); core.add_ring(vi(0));
core.add_ring_texture(Some(make_tex_id(0)));
core.add_vertex(Some(vi(0))); core.add_vertex(Some(vi(1))); core.add_ring(vi(2));
core.add_ring_texture(Some(make_tex_id(0)));
assert_eq!(core.vertices().len(), 4, "4 uv-vertex slots (2 per ring)");
assert_eq!(core.vertices()[0], core.vertices()[2]);
assert_ne!(
core.rings()[0],
core.rings()[1],
"rings start at different uv-vertex offsets"
);
}
}