From 6883f7455ffab4e64f96a94640a623de2cae6b52 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 11:45:27 +0100 Subject: [PATCH 01/44] Add start of a rewrite --- crates/bevy_mikktspace/Cargo.toml | 9 +- crates/bevy_mikktspace/src/refactored.rs | 100 +++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_mikktspace/src/refactored.rs diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index c456b3008850f..b8661fde4dca3 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -2,7 +2,11 @@ name = "bevy_mikktspace" version = "0.8.0-dev" edition = "2021" -authors = ["Benjamin Wasty ", "David Harvey-Macaulay ", "Layl Bongers "] +authors = [ + "Benjamin Wasty ", + "David Harvey-Macaulay ", + "Layl Bongers ", +] description = "Mikkelsen tangent space algorithm" documentation = "https://docs.rs/bevy" homepage = "https://bevyengine.org" @@ -12,6 +16,9 @@ keywords = ["bevy", "3D", "graphics", "algorithm", "tangent"] [dependencies] glam = "0.20.0" +id-arena = "2.2.1" +smallvec = { version = "1.6", features = ["union"] } + [[example]] name = "generate" diff --git a/crates/bevy_mikktspace/src/refactored.rs b/crates/bevy_mikktspace/src/refactored.rs new file mode 100644 index 0000000000000..76a5c1f3f6e67 --- /dev/null +++ b/crates/bevy_mikktspace/src/refactored.rs @@ -0,0 +1,100 @@ +//! The contents of this file are a combination of transpilation and human +//! modification to Morten S. Mikkelsen's original tangent space algorithm +//! implementation written in C. The original source code can be found at +//! +//! and includes the following licence: +//! +//! Copyright (C) 2011 by Morten S. Mikkelsen +//! +//! This software is provided 'as-is', without any express or implied +//! warranty. In no event will the authors be held liable for any damages +//! arising from the use of this software. +//! +//! Permission is granted to anyone to use this software for any purpose, +//! including commercial applications, and to alter it and redistribute it +//! freely, subject to the following restrictions: +//! +//! 1. The origin of this software must not be misrepresented; you must not +//! claim that you wrote the original software. If you use this software +//! in a product, an acknowledgment in the product documentation would be +//! appreciated but is not required. +//! +//! 2. Altered source versions must be plainly marked as such, and must not be +//! misrepresented as being the original software. +//! +//! 3. This notice may not be removed or altered from any source distribution. + +use std::{ + cmp::Ordering, + collections::{btree_map::Entry, BTreeMap}, +}; + +use glam::{Vec2, Vec3}; + +use crate::Geometry; + +pub fn generate_tangents(geometry: &mut impl Geometry) { + let triangle_count = geometry.num_faces(); + if triangle_count == 0 { + // Nothing to do - further steps can now assume at least one face exists. + return; + } + let vertex_indices = find_shared_vertices(geometry); + // Ignore degenerate triangles for now +} + +fn find_shared_vertices(geometry: &impl Geometry) -> Vec { + let mut vertex_indices = BTreeMap::::new(); + let mut vertices = Vec::::new(); + for face in 0..geometry.num_faces() { + for vert in 0..3 { + let info = VertexInfo { + position: geometry.position(face, vert), + normal: geometry.normal(face, vert), + tex_coord: geometry.tex_coord(face, vert), + }; + match vertex_indices.entry(info) { + Entry::Vacant(vacant) => { + let new_idx = vertices.len(); + vacant.insert(new_idx); + vertices.push(new_idx); + } + Entry::Occupied(o) => vertices.push(*o.get()), + } + } + } + vertices +} + +fn build_groups() {} + +fn build_neighbours() {} + +#[derive(PartialEq, Clone, Copy)] +struct VertexInfo { + position: Vec3, + normal: Vec3, + tex_coord: Vec2, +} + +impl Eq for VertexInfo {} + +impl Ord for VertexInfo { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap_or(Ordering::Less) + } +} + +impl PartialOrd for VertexInfo { + fn partial_cmp(&self, other: &Self) -> Option { + match self.position.partial_cmp(&other.position) { + Some(Ordering::Equal) => {} + ord => return ord, + } + match self.normal.partial_cmp(&other.normal) { + Some(Ordering::Equal) => {} + ord => return ord, + } + self.tex_coord.partial_cmp(&other.tex_coord) + } +} From e27de92e15ed2706ee1a8488ae3ceba67f40d443 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 11:46:46 +0100 Subject: [PATCH 02/44] Cleanup `genTangSpace` slightly --- crates/bevy_mikktspace/src/generated.rs | 52 ++++++++++--------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index c05b8c1566ee3..fce14f068cf78 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -199,48 +199,40 @@ impl STmpVert { } pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32) -> bool { - let mut iNrTrianglesIn = 0; - let mut f = 0; - let mut t = 0; - let mut i = 0; - let mut iNrTSPaces = 0; - let mut iTotTris = 0; - let mut iDegenTriangles = 0; - let mut iNrMaxGroups = 0; - let mut iNrActiveGroups: i32 = 0i32; - let mut index = 0; let iNrFaces = geometry.num_faces(); let mut bRes: bool = false; - let fThresCos: f32 = - ((fAngularThreshold * 3.14159265358979323846f64 as f32 / 180.0f32) as f64).cos() as f32; - f = 0; - while f < iNrFaces { + let fThresCos = (fAngularThreshold.to_radians()).cos(); + + let mut iNrTrianglesIn = 0; + // The number of triangles here is + for f in 0..iNrFaces { let verts = geometry.num_vertices_of_face(f); if verts == 3 { iNrTrianglesIn += 1 } else if verts == 4 { iNrTrianglesIn += 2 } - f += 1 } + if iNrTrianglesIn <= 0 { return false; } - + let iNrTrianglesIn = iNrTrianglesIn; let mut piTriListIn = vec![0i32; 3 * iNrTrianglesIn]; let mut pTriInfos = vec![STriInfo::zero(); iNrTrianglesIn]; - iNrTSPaces = GenerateInitialVerticesIndexList( + // Make an initial triangle --> face index list + // This also produces + let iNrTSPaces = GenerateInitialVerticesIndexList( &mut pTriInfos, &mut piTriListIn, geometry, iNrTrianglesIn, ); GenerateSharedVerticesIndexList(piTriListIn.as_mut_ptr(), geometry, iNrTrianglesIn); - iTotTris = iNrTrianglesIn; - iDegenTriangles = 0; - t = 0; - while t < iTotTris as usize { + let iTotTris = iNrTrianglesIn; + let mut iDegenTriangles = 0; + for t in 0..(iTotTris as usize) { let i0 = piTriListIn[t * 3 + 0]; let i1 = piTriListIn[t * 3 + 1]; let i2 = piTriListIn[t * 3 + 2]; @@ -253,7 +245,7 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 } t += 1 } - iNrTrianglesIn = iTotTris - iDegenTriangles; + let iNrTrianglesIn = iTotTris - iDegenTriangles; DegenPrologue( pTriInfos.as_mut_ptr(), piTriListIn.as_mut_ptr(), @@ -266,12 +258,12 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 geometry, iNrTrianglesIn, ); - iNrMaxGroups = iNrTrianglesIn * 3; + let iNrMaxGroups = iNrTrianglesIn * 3; let mut pGroups = vec![SGroup::zero(); iNrMaxGroups]; let mut piGroupTrianglesBuffer = vec![0; iNrTrianglesIn * 3]; - iNrActiveGroups = Build4RuleGroups( + let iNrActiveGroups = Build4RuleGroups( pTriInfos.as_mut_ptr(), pGroups.as_mut_ptr(), piGroupTrianglesBuffer.as_mut_ptr(), @@ -290,7 +282,7 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 iNrTSPaces ]; - bRes = GenerateTSpaces( + let bRes = GenerateTSpaces( &mut psTspace, pTriInfos.as_ptr(), pGroups.as_ptr(), @@ -310,13 +302,11 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 iNrTrianglesIn as i32, iTotTris as i32, ); - index = 0; - f = 0; - while f < iNrFaces { + let mut index = 0; + for f in 0..iNrFaces { let verts_0 = geometry.num_vertices_of_face(f); if !(verts_0 != 3 && verts_0 != 4) { - i = 0; - while i < verts_0 { + for i in 0..verts_0 { let mut pTSpace: *const STSpace = &mut psTspace[index] as *mut STSpace; let mut tang = Vec3::new((*pTSpace).vOs.x, (*pTSpace).vOs.y, (*pTSpace).vOs.z); let mut bitang = Vec3::new((*pTSpace).vOt.x, (*pTSpace).vOt.y, (*pTSpace).vOt.z); @@ -330,10 +320,8 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 i, ); index += 1; - i += 1 } } - f += 1 } return true; From 4d93183e94058dd857c0e905bfb089438c28be1d Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 12:16:47 +0100 Subject: [PATCH 03/44] Fixup double use of t --- crates/bevy_mikktspace/src/generated.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index fce14f068cf78..77d3d87c616f8 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -243,7 +243,6 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 pTriInfos[t].iFlag |= 1i32; iDegenTriangles += 1 } - t += 1 } let iNrTrianglesIn = iTotTris - iDegenTriangles; DegenPrologue( From 6d01fb4bc08ac99c5a51f6801d0f5870b2eef92e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 12:17:11 +0100 Subject: [PATCH 04/44] Migrate to bitflags --- crates/bevy_mikktspace/Cargo.toml | 2 +- crates/bevy_mikktspace/src/generated.rs | 217 ++++++++++++----------- crates/bevy_mikktspace/src/refactored.rs | 47 ++++- 3 files changed, 155 insertions(+), 111 deletions(-) diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index b8661fde4dca3..a6eee86a207bc 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -18,7 +18,7 @@ keywords = ["bevy", "3D", "graphics", "algorithm", "tangent"] glam = "0.20.0" id-arena = "2.2.1" smallvec = { version = "1.6", features = ["union"] } - +bitflags = "1.3.2" [[example]] name = "generate" diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 77d3d87c616f8..2aa4ce59cba81 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -47,12 +47,14 @@ use std::ptr::null_mut; +use bitflags::bitflags; use glam::Vec3; use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, Geometry}; #[derive(Copy, Clone)] pub struct STSpace { + // Normalised f pub vOs: Vec3, pub fMagS: f32, pub vOt: Vec3, @@ -99,6 +101,15 @@ impl STSpace { // However, this must be used both by the sampler and your tools/rendering pipeline. // internal structure +bitflags! { + pub struct TriangleFlags: u8 { + const DEGENERATE = 0b0000_0001; + const QUAD_ONE_DEGENERATE_TRI = 0b0000_0010; + const GROUP_WITH_ANY = 0b0000_0100; + const ORIENT_PRESERVING = 0b0000_1000; + } +} + #[derive(Copy, Clone)] pub struct STriInfo { pub FaceNeighbors: [i32; 3], @@ -108,7 +119,7 @@ pub struct STriInfo { pub fMagS: f32, pub fMagT: f32, pub iOrgFaceNumber: i32, - pub iFlag: i32, + pub iFlag: TriangleFlags, pub iTSpacesOffs: i32, pub vert_num: [u8; 4], } @@ -123,7 +134,7 @@ impl STriInfo { fMagS: 0.0, fMagT: 0.0, iOrgFaceNumber: 0, - iFlag: 0, + iFlag: TriangleFlags::empty(), iTSpacesOffs: 0, vert_num: [0, 0, 0, 0], } @@ -240,7 +251,7 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 let p1 = get_position(geometry, i1 as usize); let p2 = get_position(geometry, i2 as usize); if p0 == p1 || p0 == p2 || p1 == p2 { - pTriInfos[t].iFlag |= 1i32; + pTriInfos[t].iFlag.insert(TriangleFlags::DEGENERATE); iDegenTriangles += 1 } } @@ -337,11 +348,9 @@ unsafe fn DegenEpilogue( let mut i: i32 = 0i32; t = iNrTrianglesIn; while t < iTotTris { - let bSkip: bool = if (*pTriInfos.offset(t as isize)).iFlag & 2i32 != 0i32 { - true - } else { - false - }; + let bSkip: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); if !bSkip { i = 0i32; while i < 3i32 { @@ -374,7 +383,10 @@ unsafe fn DegenEpilogue( } t = 0i32; while t < iNrTrianglesIn { - if (*pTriInfos.offset(t as isize)).iFlag & 2i32 != 0i32 { + if (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) + { let mut vDstP = Vec3::new(0.0, 0.0, 0.0); let mut iOrgF: i32 = -1i32; let mut i_0: i32 = 0i32; @@ -506,15 +518,9 @@ unsafe fn GenerateTSpaces( if VNotZero(vOt2) { vOt2 = Normalize(vOt2) } - let bAny: bool = if ((*pTriInfos.offset(f as isize)).iFlag + let bAny: bool = ((*pTriInfos.offset(f as isize)).iFlag | (*pTriInfos.offset(t as isize)).iFlag) - & 4i32 - != 0i32 - { - true - } else { - false - }; + .contains(TriangleFlags::GROUP_WITH_ANY); let bSameOrgFace: bool = iOF_1 == iOF_2; let fCosS: f32 = vOs.dot(vOs2); let fCosT: f32 = vOt.dot(vOt2); @@ -646,7 +652,10 @@ unsafe fn EvalTspace( face = 0i32; while face < iFaces { let f: i32 = *face_indices.offset(face as isize); - if (*pTriInfos.offset(f as isize)).iFlag & 4i32 == 0i32 { + if !(*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::GROUP_WITH_ANY) + { let mut n = Vec3::new(0.0, 0.0, 0.0); let mut vOs = Vec3::new(0.0, 0.0, 0.0); let mut vOt = Vec3::new(0.0, 0.0, 0.0); @@ -810,7 +819,9 @@ unsafe fn Build4RuleGroups( while f < iNrTrianglesIn { i = 0i32; while i < 3i32 { - if (*pTriInfos.offset(f as isize)).iFlag & 4i32 == 0i32 + if !(*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::GROUP_WITH_ANY) && (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize].is_null() { let mut bOrPre: bool = false; @@ -822,18 +833,18 @@ unsafe fn Build4RuleGroups( (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]) .iVertexRepresentitive = vert_index; (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).bOrientPreservering = - (*pTriInfos.offset(f as isize)).iFlag & 8i32 != 0i32; + (*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces = 0i32; let ref mut fresh3 = (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).pFaceIndices; *fresh3 = &mut *piGroupTrianglesBuffer.offset(iOffset as isize) as *mut i32; iNrActiveGroups += 1; AddTriToGroup((*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], f); - bOrPre = if (*pTriInfos.offset(f as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; + bOrPre = (*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); neigh_indexL = (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize]; neigh_indexR = (*pTriInfos.offset(f as isize)).FaceNeighbors [(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; @@ -844,12 +855,9 @@ unsafe fn Build4RuleGroups( neigh_indexL, (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], ); - let bOrPre2: bool = - if (*pTriInfos.offset(neigh_indexL as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; + let bOrPre2: bool = (*pTriInfos.offset(neigh_indexL as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff: bool = if bOrPre != bOrPre2 { true } else { false }; } if neigh_indexR >= 0i32 { @@ -859,12 +867,9 @@ unsafe fn Build4RuleGroups( neigh_indexR, (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], ); - let bOrPre2_0: bool = - if (*pTriInfos.offset(neigh_indexR as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; + let bOrPre2_0: bool = (*pTriInfos.offset(neigh_indexR as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff_0: bool = if bOrPre != bOrPre2_0 { true } else { false }; } iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces @@ -904,24 +909,20 @@ unsafe fn AssignRecur( return false; } } - if (*pMyTriInfo).iFlag & 4i32 != 0i32 { + if (*pMyTriInfo).iFlag.contains(TriangleFlags::GROUP_WITH_ANY) { if (*pMyTriInfo).AssignedGroup[0usize].is_null() && (*pMyTriInfo).AssignedGroup[1usize].is_null() && (*pMyTriInfo).AssignedGroup[2usize].is_null() { - (*pMyTriInfo).iFlag &= !8i32; - (*pMyTriInfo).iFlag |= if (*pGroup).bOrientPreservering { - 8i32 - } else { - 0i32 - } + (*pMyTriInfo).iFlag.set( + TriangleFlags::ORIENT_PRESERVING, + (*pGroup).bOrientPreservering, + ); } } - let bOrient: bool = if (*pMyTriInfo).iFlag & 8i32 != 0i32 { - true - } else { - false - }; + let bOrient: bool = (*pMyTriInfo) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); if bOrient != (*pGroup).bOrientPreservering { return false; } @@ -966,7 +967,9 @@ unsafe fn InitTriInfo( (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; - (*pTriInfos.offset(f as isize)).iFlag |= 4i32; + (*pTriInfos.offset(f as isize)) + .iFlag + .insert(TriangleFlags::GROUP_WITH_ANY); i += 1 } f += 1 @@ -988,16 +991,19 @@ unsafe fn InitTriInfo( let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; let mut vOs = (t31y * d1) - (t21y * d2); let mut vOt = (-t31x * d1) + (t21x * d2); - (*pTriInfos.offset(f as isize)).iFlag |= if fSignedAreaSTx2 > 0i32 as f32 { - 8i32 - } else { - 0i32 - }; + if fSignedAreaSTx2 > 0.0 { + (*pTriInfos.offset(f as isize)) + .iFlag + .insert(TriangleFlags::ORIENT_PRESERVING); + } if NotZero(fSignedAreaSTx2) { let fAbsArea: f32 = fSignedAreaSTx2.abs(); let fLenOs: f32 = vOs.length(); let fLenOt: f32 = vOt.length(); - let fS: f32 = if (*pTriInfos.offset(f as isize)).iFlag & 8i32 == 0i32 { + let fS: f32 = if (*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING) + { -1.0f32 } else { 1.0f32 @@ -1013,7 +1019,9 @@ unsafe fn InitTriInfo( if NotZero((*pTriInfos.offset(f as isize)).fMagS) && NotZero((*pTriInfos.offset(f as isize)).fMagT) { - (*pTriInfos.offset(f as isize)).iFlag &= !4i32 + (*pTriInfos.offset(f as isize)) + .iFlag + .remove(TriangleFlags::GROUP_WITH_ANY); } } f += 1 @@ -1022,30 +1030,25 @@ unsafe fn InitTriInfo( let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; if iFO_a == iFO_b { - let bIsDeg_a: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - let bIsDeg_b: bool = if (*pTriInfos.offset((t + 1) as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; + let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); if !(bIsDeg_a || bIsDeg_b) { - let bOrientA: bool = if (*pTriInfos.offset(t as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; - let bOrientB: bool = if (*pTriInfos.offset((t + 1) as isize)).iFlag & 8i32 != 0i32 { - true - } else { - false - }; + let bOrientA: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); + let bOrientB: bool = (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); if bOrientA != bOrientB { let mut bChooseOrientFirstTri: bool = false; - if (*pTriInfos.offset((t + 1) as isize)).iFlag & 4i32 != 0i32 { + if (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::GROUP_WITH_ANY) + { bChooseOrientFirstTri = true } else if CalcTexArea(geometry, &*piTriListIn.offset((t * 3 + 0) as isize)) >= CalcTexArea(geometry, &*piTriListIn.offset(((t + 1) * 3 + 0) as isize)) @@ -1054,9 +1057,12 @@ unsafe fn InitTriInfo( } let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; - (*pTriInfos.offset(t1_0 as isize)).iFlag &= !8i32; - (*pTriInfos.offset(t1_0 as isize)).iFlag |= - (*pTriInfos.offset(t0 as isize)).iFlag & 8i32 + (*pTriInfos.offset(t1_0 as isize)).iFlag.set( + TriangleFlags::ORIENT_PRESERVING, + (*pTriInfos.offset(t0 as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING), + ); } } t += 2 @@ -1326,19 +1332,21 @@ unsafe fn DegenPrologue( let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; let iFO_b: i32 = (*pTriInfos.offset((t + 1i32) as isize)).iOrgFaceNumber; if iFO_a == iFO_b { - let bIsDeg_a: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - let bIsDeg_b: bool = if (*pTriInfos.offset((t + 1i32) as isize)).iFlag & 1i32 != 0i32 { - true - } else { - false - }; - if bIsDeg_a ^ bIsDeg_b != false { - (*pTriInfos.offset(t as isize)).iFlag |= 2i32; - (*pTriInfos.offset((t + 1i32) as isize)).iFlag |= 2i32 + let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = (*pTriInfos.offset((t + 1i32) as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + // If exactly one is degenerate, mark both as QUAD_ONE_DEGENERATE_TRI, i.e. that the other triangle + // (If both are degenerate, this) + if bIsDeg_a ^ bIsDeg_b { + (*pTriInfos.offset(t as isize)) + .iFlag + .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + (*pTriInfos.offset((t + 1i32) as isize)) + .iFlag + .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); } t += 2i32 } else { @@ -1349,11 +1357,9 @@ unsafe fn DegenPrologue( t = 0i32; bStillFindingGoodOnes = true; while t < iNrTrianglesIn && bStillFindingGoodOnes { - let bIsGood: bool = if (*pTriInfos.offset(t as isize)).iFlag & 1i32 == 0i32 { - true - } else { - false - }; + let bIsGood: bool = !(*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); if bIsGood { if iNextGoodTriangleSearchIndex < t + 2i32 { iNextGoodTriangleSearchIndex = t + 2i32 @@ -1363,14 +1369,9 @@ unsafe fn DegenPrologue( let mut t1: i32 = 0; let mut bJustADegenerate: bool = true; while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { - let bIsGood_0: bool = - if (*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)).iFlag & 1i32 - == 0i32 - { - true - } else { - false - }; + let bIsGood_0: bool = !(*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); if bIsGood_0 { bJustADegenerate = false } else { @@ -1789,7 +1790,7 @@ unsafe fn GenerateInitialVerticesIndexList( } t = 0; while t < iNrTrianglesIn { - pTriInfos[t].iFlag = 0; + pTriInfos[t].iFlag = TriangleFlags::empty(); t += 1 } return iTSpacesOffs; diff --git a/crates/bevy_mikktspace/src/refactored.rs b/crates/bevy_mikktspace/src/refactored.rs index 76a5c1f3f6e67..30f762be2b311 100644 --- a/crates/bevy_mikktspace/src/refactored.rs +++ b/crates/bevy_mikktspace/src/refactored.rs @@ -24,6 +24,51 @@ //! //! 3. This notice may not be removed or altered from any source distribution. +/// The interface by which mikktspace interacts with your geometry. +pub trait Geometry { + // For simplicity's sake, we intentionall eschew the quad handling of mikktspace. + // You should ensure that the mesh passed here is triangulated + + /// Returns the number of faces. + fn num_faces(&self) -> usize; + + /// Returns the position of a vertex. + fn position(&self, face: usize, vert: usize) -> Vec3; + + /// Returns the normal of a vertex. + fn normal(&self, face: usize, vert: usize) -> Vec3; + + /// Returns the texture coordinate of a vertex. + fn tex_coord(&self, face: usize, vert: usize) -> Vec2; + + /// Sets the generated tangent for a vertex. + /// Leave this function unimplemented if you are implementing + /// `set_tangent_encoded`. + fn set_tangent( + &mut self, + tangent: [f32; 3], + _bi_tangent: [f32; 3], + _f_mag_s: f32, + _f_mag_t: f32, + bi_tangent_preserves_orientation: bool, + face: usize, + vert: usize, + ) { + let sign = if bi_tangent_preserves_orientation { + 1.0 + } else { + -1.0 + }; + self.set_tangent_encoded([tangent[0], tangent[1], tangent[2], sign], face, vert); + } + + /// Sets the generated tangent for a vertex with its bi-tangent encoded as the 'W' (4th) + /// component in the tangent. The 'W' component marks if the bi-tangent is flipped. This + /// is called by the default implementation of `set_tangent`; therefore, this function will + /// not be called by the crate unless `set_tangent` is unimplemented. + fn set_tangent_encoded(&mut self, _tangent: [f32; 4], _face: usize, _vert: usize) {} +} + use std::{ cmp::Ordering, collections::{btree_map::Entry, BTreeMap}, @@ -31,8 +76,6 @@ use std::{ use glam::{Vec2, Vec3}; -use crate::Geometry; - pub fn generate_tangents(geometry: &mut impl Geometry) { let triangle_count = geometry.num_faces(); if triangle_count == 0 { From 99db5b59464e653b18fbcd2c7b2015675783a3d5 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 12:34:27 +0100 Subject: [PATCH 05/44] Fix up mixed up flag --- crates/bevy_mikktspace/src/generated.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 2aa4ce59cba81..6f4cbbcf9c3e9 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -103,10 +103,10 @@ impl STSpace { bitflags! { pub struct TriangleFlags: u8 { - const DEGENERATE = 0b0000_0001; - const QUAD_ONE_DEGENERATE_TRI = 0b0000_0010; - const GROUP_WITH_ANY = 0b0000_0100; - const ORIENT_PRESERVING = 0b0000_1000; + const DEGENERATE = 1; + const QUAD_ONE_DEGENERATE_TRI = 2; + const GROUP_WITH_ANY = 4; + const ORIENT_PRESERVING = 8; } } @@ -1000,7 +1000,7 @@ unsafe fn InitTriInfo( let fAbsArea: f32 = fSignedAreaSTx2.abs(); let fLenOs: f32 = vOs.length(); let fLenOt: f32 = vOt.length(); - let fS: f32 = if (*pTriInfos.offset(f as isize)) + let fS: f32 = if !(*pTriInfos.offset(f as isize)) .iFlag .contains(TriangleFlags::ORIENT_PRESERVING) { From b4ddeecbe13b042318219631bacb46be099afd3f Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 14:37:07 +0100 Subject: [PATCH 06/44] Use an enum for vertex counts --- crates/bevy_mikktspace/examples/generate.rs | 5 +- crates/bevy_mikktspace/src/generated.rs | 192 +++++++++--------- crates/bevy_mikktspace/src/lib.rs | 17 +- .../bevy_mikktspace/tests/regression_test.rs | 7 +- crates/bevy_render/src/mesh/mesh/mod.rs | 5 +- 5 files changed, 120 insertions(+), 106 deletions(-) diff --git a/crates/bevy_mikktspace/examples/generate.rs b/crates/bevy_mikktspace/examples/generate.rs index a8cefb8809ff4..cd1ce24d52edc 100644 --- a/crates/bevy_mikktspace/examples/generate.rs +++ b/crates/bevy_mikktspace/examples/generate.rs @@ -1,5 +1,6 @@ #![allow(clippy::bool_assert_comparison, clippy::useless_conversion)] +use bevy_mikktspace::FaceKind; use glam::{Vec2, Vec3}; pub type Face = [u32; 3]; @@ -26,8 +27,8 @@ impl bevy_mikktspace::Geometry for Mesh { self.faces.len() } - fn num_vertices_of_face(&self, _face: usize) -> usize { - 3 + fn num_vertices_of_face(&self, _face: usize) -> FaceKind { + FaceKind::Triangle } fn position(&self, face: usize, vert: usize) -> [f32; 3] { diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 6f4cbbcf9c3e9..629ee247bccdc 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -50,7 +50,7 @@ use std::ptr::null_mut; use bitflags::bitflags; use glam::Vec3; -use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, Geometry}; +use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, FaceKind, Geometry}; #[derive(Copy, Clone)] pub struct STSpace { @@ -215,13 +215,11 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 let fThresCos = (fAngularThreshold.to_radians()).cos(); let mut iNrTrianglesIn = 0; - // The number of triangles here is for f in 0..iNrFaces { let verts = geometry.num_vertices_of_face(f); - if verts == 3 { - iNrTrianglesIn += 1 - } else if verts == 4 { - iNrTrianglesIn += 2 + match verts { + FaceKind::Triangle => iNrTrianglesIn += 1, + FaceKind::Quad => iNrTrianglesIn += 2, } } @@ -315,22 +313,20 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 let mut index = 0; for f in 0..iNrFaces { let verts_0 = geometry.num_vertices_of_face(f); - if !(verts_0 != 3 && verts_0 != 4) { - for i in 0..verts_0 { - let mut pTSpace: *const STSpace = &mut psTspace[index] as *mut STSpace; - let mut tang = Vec3::new((*pTSpace).vOs.x, (*pTSpace).vOs.y, (*pTSpace).vOs.z); - let mut bitang = Vec3::new((*pTSpace).vOt.x, (*pTSpace).vOt.y, (*pTSpace).vOt.z); - geometry.set_tangent( - tang.into(), - bitang.into(), - (*pTSpace).fMagS, - (*pTSpace).fMagT, - (*pTSpace).bOrient, - f, - i, - ); - index += 1; - } + for i in 0..verts_0.num_vertices() { + let mut pTSpace: *const STSpace = &mut psTspace[index] as *mut STSpace; + let mut tang = Vec3::new((*pTSpace).vOs.x, (*pTSpace).vOs.y, (*pTSpace).vOs.z); + let mut bitang = Vec3::new((*pTSpace).vOt.x, (*pTSpace).vOt.y, (*pTSpace).vOt.z); + geometry.set_tangent( + tang.into(), + bitang.into(), + (*pTSpace).fMagS, + (*pTSpace).fMagT, + (*pTSpace).bOrient, + f, + i, + ); + index += 1; } } @@ -1703,89 +1699,89 @@ unsafe fn GenerateInitialVerticesIndexList( f = 0; while f < geometry.num_faces() { let verts = geometry.num_vertices_of_face(f); - if !(verts != 3 && verts != 4) { - pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; - if verts == 3 { - let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts[0] = 0; - pVerts[1] = 1; - pVerts[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; - piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; - piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; - iDstTriIndex += 1 + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; + if let FaceKind::Triangle = verts { + let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts[0] = 0; + pVerts[1] = 1; + pVerts[2] = 2; + piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; + piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; + piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; + iDstTriIndex += 1 + } else { + pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; + pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; + let i0 = face_vert_to_index(f, 0); + let i1 = face_vert_to_index(f, 1); + let i2 = face_vert_to_index(f, 2); + let i3 = face_vert_to_index(f, 3); + let T0 = get_tex_coord(geometry, i0); + let T1 = get_tex_coord(geometry, i1); + let T2 = get_tex_coord(geometry, i2); + let T3 = get_tex_coord(geometry, i3); + let distSQ_02: f32 = (T2 - T0).length_squared(); + let distSQ_13: f32 = (T3 - T1).length_squared(); + let mut bQuadDiagIs_02: bool = false; + if distSQ_02 < distSQ_13 { + bQuadDiagIs_02 = true + } else if distSQ_13 < distSQ_02 { + bQuadDiagIs_02 = false } else { - pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; - let i0 = face_vert_to_index(f, 0); - let i1 = face_vert_to_index(f, 1); - let i2 = face_vert_to_index(f, 2); - let i3 = face_vert_to_index(f, 3); - let T0 = get_tex_coord(geometry, i0); - let T1 = get_tex_coord(geometry, i1); - let T2 = get_tex_coord(geometry, i2); - let T3 = get_tex_coord(geometry, i3); - let distSQ_02: f32 = (T2 - T0).length_squared(); - let distSQ_13: f32 = (T3 - T1).length_squared(); - let mut bQuadDiagIs_02: bool = false; - if distSQ_02 < distSQ_13 { - bQuadDiagIs_02 = true - } else if distSQ_13 < distSQ_02 { - bQuadDiagIs_02 = false + let P0 = get_position(geometry, i0); + let P1 = get_position(geometry, i1); + let P2 = get_position(geometry, i2); + let P3 = get_position(geometry, i3); + let distSQ_02_0: f32 = (P2 - P0).length_squared(); + let distSQ_13_0: f32 = (P3 - P1).length_squared(); + bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { + false } else { - let P0 = get_position(geometry, i0); - let P1 = get_position(geometry, i1); - let P2 = get_position(geometry, i2); - let P3 = get_position(geometry, i3); - let distSQ_02_0: f32 = (P2 - P0).length_squared(); - let distSQ_13_0: f32 = (P3 - P1).length_squared(); - bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { - false - } else { - true - } + true } - if bQuadDiagIs_02 { - let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A[0] = 0; - pVerts_A[1] = 1; - pVerts_A[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; - iDstTriIndex += 1; + } + if bQuadDiagIs_02 { + let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_A[0] = 0; + pVerts_A[1] = 1; + pVerts_A[2] = 2; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; + iDstTriIndex += 1; - let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B[0] = 0; - pVerts_B[1] = 2; - pVerts_B[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } else { - let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A_0[0] = 0; - pVerts_A_0[1] = 1; - pVerts_A_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1; + let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_B[0] = 0; + pVerts_B[1] = 2; + pVerts_B[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1 + } else { + let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_A_0[0] = 0; + pVerts_A_0[1] = 1; + pVerts_A_0[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1; - let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B_0[0] = 1; - pVerts_B_0[1] = 2; - pVerts_B_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } + let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_B_0[0] = 1; + pVerts_B_0[1] = 2; + pVerts_B_0[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1 } - iTSpacesOffs += verts } + iTSpacesOffs += verts.num_vertices(); + f += 1 } t = 0; diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index 89d7b05427407..5791349028060 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -4,13 +4,28 @@ use glam::{Vec2, Vec3}; mod generated; +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum FaceKind { + Triangle, + Quad, +} + +impl FaceKind { + fn num_vertices(&self) -> usize { + match self { + FaceKind::Triangle => 3, + FaceKind::Quad => 4, + } + } +} + /// The interface by which mikktspace interacts with your geometry. pub trait Geometry { /// Returns the number of faces. fn num_faces(&self) -> usize; /// Returns the number of vertices of a face. - fn num_vertices_of_face(&self, face: usize) -> usize; + fn num_vertices_of_face(&self, face: usize) -> FaceKind; /// Returns the position of a vertex. fn position(&self, face: usize, vert: usize) -> [f32; 3]; diff --git a/crates/bevy_mikktspace/tests/regression_test.rs b/crates/bevy_mikktspace/tests/regression_test.rs index 42177cbc3496d..367667265d928 100644 --- a/crates/bevy_mikktspace/tests/regression_test.rs +++ b/crates/bevy_mikktspace/tests/regression_test.rs @@ -8,7 +8,7 @@ clippy::map_flatten )] -use bevy_mikktspace::{generate_tangents, Geometry}; +use bevy_mikktspace::{generate_tangents, FaceKind, Geometry}; use glam::{Vec2, Vec3}; pub type Face = [u32; 3]; @@ -73,8 +73,9 @@ impl Geometry for Context { self.mesh.faces.len() } - fn num_vertices_of_face(&self, _face: usize) -> usize { - 3 + fn num_vertices_of_face(&self, _face: usize) -> FaceKind { + // We don't currently support Quads + FaceKind::Triangle } fn position(&self, face: usize, vert: usize) -> [f32; 3] { diff --git a/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index 3193ebb5d1a09..4ba3e47ea2b92 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -1,5 +1,6 @@ mod conversions; pub mod skinning; +use bevy_mikktspace::FaceKind; pub use wgpu::PrimitiveTopology; use crate::{ @@ -883,8 +884,8 @@ impl bevy_mikktspace::Geometry for MikktspaceGeometryHelper<'_> { self.indices.len() / 3 } - fn num_vertices_of_face(&self, _: usize) -> usize { - 3 + fn num_vertices_of_face(&self, _: usize) -> FaceKind { + FaceKind::Triangle } fn position(&self, face: usize, vert: usize) -> [f32; 3] { From 84d62cfbc50b7511f971ce726506b54354b51159 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 14:41:52 +0100 Subject: [PATCH 07/44] Use `impl Geometry` syntax and descope mutable access --- crates/bevy_mikktspace/src/generated.rs | 34 ++++++++++++------------- crates/bevy_mikktspace/src/lib.rs | 8 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 629ee247bccdc..b8c0c11a4aecf 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -209,9 +209,8 @@ impl STmpVert { } } -pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32) -> bool { +pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { let iNrFaces = geometry.num_faces(); - let mut bRes: bool = false; let fThresCos = (fAngularThreshold.to_radians()).cos(); let mut iNrTrianglesIn = 0; @@ -224,6 +223,7 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 } if iNrTrianglesIn <= 0 { + // Easier if we can assume there's at least one face return false; } let iNrTrianglesIn = iNrTrianglesIn; @@ -332,11 +332,11 @@ pub unsafe fn genTangSpace(geometry: &mut I, fAngularThreshold: f32 return true; } -unsafe fn DegenEpilogue( +unsafe fn DegenEpilogue( mut psTspace: *mut STSpace, mut pTriInfos: *mut STriInfo, mut piTriListIn: *mut i32, - geometry: &mut I, + geometry: &impl Geometry, iNrTrianglesIn: i32, iTotTris: i32, ) { @@ -426,14 +426,14 @@ unsafe fn DegenEpilogue( } } -unsafe fn GenerateTSpaces( +unsafe fn GenerateTSpaces( psTspace: &mut [STSpace], mut pTriInfos: *const STriInfo, mut pGroups: *const SGroup, iNrActiveGroups: i32, mut piTriListIn: *const i32, fThresCos: f32, - geometry: &mut I, + geometry: &impl Geometry, ) -> bool { let mut iMaxNrFaces: usize = 0; let mut iUniqueTspaces = 0; @@ -619,12 +619,12 @@ unsafe fn NotZero(fX: f32) -> bool { fX.abs() > 1.17549435e-38f32 } -unsafe fn EvalTspace( +unsafe fn EvalTspace( mut face_indices: *mut i32, iFaces: i32, mut piTriListIn: *const i32, mut pTriInfos: *const STriInfo, - geometry: &mut I, + geometry: &impl Geometry, iVertexRepresentitive: i32, ) -> STSpace { let mut res: STSpace = STSpace { @@ -939,10 +939,10 @@ unsafe fn AddTriToGroup(mut pGroup: *mut SGroup, iTriIndex: i32) { *(*pGroup).pFaceIndices.offset((*pGroup).iNrFaces as isize) = iTriIndex; (*pGroup).iNrFaces += 1; } -unsafe fn InitTriInfo( +unsafe fn InitTriInfo( mut pTriInfos: *mut STriInfo, mut piTriListIn: *const i32, - geometry: &mut I, + geometry: &impl Geometry, iNrTrianglesIn: usize, ) { let mut f = 0; @@ -1297,7 +1297,7 @@ unsafe fn QuickSortEdges( } // returns the texture area times 2 -unsafe fn CalcTexArea(geometry: &mut I, mut indices: *const i32) -> f32 { +unsafe fn CalcTexArea(geometry: &impl Geometry, mut indices: *const i32) -> f32 { let t1 = get_tex_coord(geometry, *indices.offset(0isize) as usize); let t2 = get_tex_coord(geometry, *indices.offset(1isize) as usize); let t3 = get_tex_coord(geometry, *indices.offset(2isize) as usize); @@ -1399,9 +1399,9 @@ unsafe fn DegenPrologue( } } } -unsafe fn GenerateSharedVerticesIndexList( +unsafe fn GenerateSharedVerticesIndexList( mut piTriList_in_and_out: *mut i32, - geometry: &mut I, + geometry: &impl Geometry, iNrTrianglesIn: usize, ) { let mut i = 0; @@ -1537,10 +1537,10 @@ unsafe fn GenerateSharedVerticesIndexList( } } -unsafe fn MergeVertsFast( +unsafe fn MergeVertsFast( mut piTriList_in_and_out: *mut i32, mut pTmpVert: *mut STmpVert, - geometry: &mut I, + geometry: &impl Geometry, iL_in: i32, iR_in: i32, ) { @@ -1686,10 +1686,10 @@ unsafe fn FindGridCell(fMin: f32, fMax: f32, fVal: f32) -> usize { }; } -unsafe fn GenerateInitialVerticesIndexList( +unsafe fn GenerateInitialVerticesIndexList( pTriInfos: &mut [STriInfo], piTriList_out: &mut [i32], - geometry: &mut I, + geometry: &mut impl Geometry, iNrTrianglesIn: usize, ) -> usize { let mut iTSpacesOffs: usize = 0; diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index 5791349028060..835c9b3925ad3 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -70,23 +70,23 @@ pub trait Geometry { /// /// Returns `false` if the geometry is unsuitable for tangent generation including, /// but not limited to, lack of vertices. -pub fn generate_tangents(geometry: &mut I) -> bool { +pub fn generate_tangents(geometry: &mut impl Geometry) -> bool { unsafe { generated::genTangSpace(geometry, 180.0) } } -fn get_position(geometry: &mut I, index: usize) -> Vec3 { +fn get_position(geometry: &impl Geometry, index: usize) -> Vec3 { let (face, vert) = index_to_face_vert(index); geometry.position(face, vert).into() } -fn get_tex_coord(geometry: &mut I, index: usize) -> Vec3 { +fn get_tex_coord(geometry: &impl Geometry, index: usize) -> Vec3 { let (face, vert) = index_to_face_vert(index); let tex_coord: Vec2 = geometry.tex_coord(face, vert).into(); let val = tex_coord.extend(1.0); val } -fn get_normal(geometry: &mut I, index: usize) -> Vec3 { +fn get_normal(geometry: &impl Geometry, index: usize) -> Vec3 { let (face, vert) = index_to_face_vert(index); geometry.normal(face, vert).into() } From b60fa484edc26c50bc563159a5fdfefdfcfdd701 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 15:01:19 +0100 Subject: [PATCH 08/44] Remove unused deps --- crates/bevy_mikktspace/Cargo.toml | 4 ++-- crates/bevy_mikktspace/src/generated.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index a6eee86a207bc..0b0b8eddb4fc7 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -16,9 +16,9 @@ keywords = ["bevy", "3D", "graphics", "algorithm", "tangent"] [dependencies] glam = "0.20.0" -id-arena = "2.2.1" -smallvec = { version = "1.6", features = ["union"] } bitflags = "1.3.2" +# id-arena = "2.2.1" +# smallvec = { version = "1.6", features = ["union"] } [[example]] name = "generate" diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index b8c0c11a4aecf..2d1bd5451eac8 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -211,6 +211,7 @@ impl STmpVert { pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { let iNrFaces = geometry.num_faces(); + // TODO: Accept in radians by default here? let fThresCos = (fAngularThreshold.to_radians()).cos(); let mut iNrTrianglesIn = 0; From dae89e7c24c17a8d1a293bf1dc6e197fc3c9612d Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 4 Jun 2022 23:01:08 +0100 Subject: [PATCH 09/44] Add some comments --- crates/bevy_mikktspace/src/generated.rs | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 2d1bd5451eac8..96f911c060569 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -26,6 +26,9 @@ //! misrepresented as being the original software. //! //! 3. This notice may not be removed or altered from any source distribution. +//! +// Comments starting with `C:` are copied as-is from the original +// Note that some comments may originate from the original but not be marked as such #![allow( clippy::all, @@ -224,24 +227,29 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) } if iNrTrianglesIn <= 0 { - // Easier if we can assume there's at least one face + // Easier if we can assume there's at least one face later + // No tangents need to be generated return false; } let iNrTrianglesIn = iNrTrianglesIn; let mut piTriListIn = vec![0i32; 3 * iNrTrianglesIn]; let mut pTriInfos = vec![STriInfo::zero(); iNrTrianglesIn]; - // Make an initial triangle --> face index list - // This also produces + // C: Make an initial triangle --> face index list + // This also handles quads + // TODO: Make this return triangle_info and tri_face_map + // probably in a single structure. let iNrTSPaces = GenerateInitialVerticesIndexList( &mut pTriInfos, &mut piTriListIn, geometry, iNrTrianglesIn, ); + // C: Make a welded index list of identical positions and attributes (pos, norm, texc) GenerateSharedVerticesIndexList(piTriListIn.as_mut_ptr(), geometry, iNrTrianglesIn); let iTotTris = iNrTrianglesIn; let mut iDegenTriangles = 0; + // C: Mark all degenerate triangles for t in 0..(iTotTris as usize) { let i0 = piTriListIn[t * 3 + 0]; let i1 = piTriListIn[t * 3 + 1]; @@ -255,18 +263,26 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) } } let iNrTrianglesIn = iTotTris - iDegenTriangles; + // C: Mark all triangle pairs that belong to a quad with only one + // C: good triangle. These need special treatment in DegenEpilogue(). + // C: Additionally, move all good triangles to the start of + // C: pTriInfos[] and piTriListIn[] without changing order and + // C: put the degenerate triangles last. + // Note: A quad can have degenerate traignles if two vertices are in the same location DegenPrologue( pTriInfos.as_mut_ptr(), piTriListIn.as_mut_ptr(), iNrTrianglesIn as i32, iTotTris as i32, ); + // C: Evaluate triangle level attributes and neighbor list InitTriInfo( pTriInfos.as_mut_ptr(), piTriListIn.as_ptr(), geometry, iNrTrianglesIn, ); + //C: Based on the 4 rules, identify groups based on connectivity let iNrMaxGroups = iNrTrianglesIn * 3; let mut pGroups = vec![SGroup::zero(); iNrMaxGroups]; @@ -1350,6 +1366,15 @@ unsafe fn DegenPrologue( t += 1 } } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + // That is, a semi-stable partition, e.g. as described at + // https://dlang.org/library/std/algorithm/sorting/partition.html + // TODO: Use `Vec::retain` with a second vec here - not perfect, + // but good enough and safe. + // TODO: Consider using `sort_by_key` on Vec instead (which is stable) - it might be + // technically slower, but it's much easier to reason about iNextGoodTriangleSearchIndex = 1i32; t = 0i32; bStillFindingGoodOnes = true; @@ -1378,6 +1403,7 @@ unsafe fn DegenPrologue( t0 = t; t1 = iNextGoodTriangleSearchIndex; iNextGoodTriangleSearchIndex += 1; + // Swap t0 and t1 if !bJustADegenerate { let mut i: i32 = 0i32; i = 0i32; @@ -1401,6 +1427,13 @@ unsafe fn DegenPrologue( } } unsafe fn GenerateSharedVerticesIndexList( + // The input vertex index->face/vert mappings + // Identical face/verts will have each vertex index + // point to the same (arbitrary?) face/vert + // TODO: This seems overly complicated - storing vertex properties in a + // side channel seems much easier. + // Hopefully implementation can be changed to just use a btreemap or + // something too. mut piTriList_in_and_out: *mut i32, geometry: &impl Geometry, iNrTrianglesIn: usize, From 4eab80cfbb37485b3ecb36011ae8d4d04c1c7fd3 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:00:40 +0100 Subject: [PATCH 10/44] Update `DegenEpilogue` --- crates/bevy_mikktspace/src/generated.rs | 67 ++++++++++--------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 96f911c060569..9d1f97b122013 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -357,53 +357,44 @@ unsafe fn DegenEpilogue( iNrTrianglesIn: i32, iTotTris: i32, ) { - let mut t: i32 = 0i32; - let mut i: i32 = 0i32; - t = iNrTrianglesIn; - while t < iTotTris { + // For all degenerate triangles + for t in iNrTrianglesIn..iTotTris { let bSkip: bool = (*pTriInfos.offset(t as isize)) .iFlag .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); if !bSkip { - i = 0i32; - while i < 3i32 { + for i in 0..3i32 { + // For all vertices on that triangle let index1: i32 = *piTriListIn.offset((t * 3i32 + i) as isize); - let mut bNotFound: bool = true; - let mut j: i32 = 0i32; - while bNotFound && j < 3i32 * iNrTrianglesIn { + for j in 0..(3i32 * iNrTrianglesIn) { let index2: i32 = *piTriListIn.offset(j as isize); + // If the vertex properties are the same as another non-degenerate vertex if index1 == index2 { - bNotFound = false - } else { - j += 1 + let iTri: i32 = j / 3i32; + let iVert: i32 = j % 3i32; + let iSrcVert: i32 = + (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; + let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; + let iDstVert: i32 = + (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; + let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; + // Set the tangent space of this vertex to the tangent space of that vertex + // TODO: This is absurd - doing a linear search through all vertices for each + // degenerate triangle? + *psTspace.offset((iDstOffs + iDstVert) as isize) = + *psTspace.offset((iSrcOffs + iSrcVert) as isize); + break; } } - if !bNotFound { - let iTri: i32 = j / 3i32; - let iVert: i32 = j % 3i32; - let iSrcVert: i32 = - (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; - let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; - let iDstVert: i32 = (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; - let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - *psTspace.offset((iDstOffs + iDstVert) as isize) = - *psTspace.offset((iSrcOffs + iSrcVert) as isize) - } - i += 1 } } - t += 1 } - t = 0i32; - while t < iNrTrianglesIn { + for t in 0..iNrTrianglesIn { + // Handle quads with a single degenerate triangle by if (*pTriInfos.offset(t as isize)) .iFlag .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) { - let mut vDstP = Vec3::new(0.0, 0.0, 0.0); - let mut iOrgF: i32 = -1i32; - let mut i_0: i32 = 0i32; - let mut bNotFound_0: bool = false; let mut pV: *mut u8 = (*pTriInfos.offset(t as isize)).vert_num.as_mut_ptr(); let mut iFlag: i32 = 1i32 << *pV.offset(0isize) as i32 | 1i32 << *pV.offset(1isize) as i32 @@ -416,14 +407,13 @@ unsafe fn DegenEpilogue( } else if iFlag & 8i32 == 0i32 { iMissingIndex = 3i32 } - iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - vDstP = get_position( + let iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; + let vDstP = get_position( geometry, face_vert_to_index(iOrgF as usize, iMissingIndex as usize), ); - bNotFound_0 = true; - i_0 = 0i32; - while bNotFound_0 && i_0 < 3i32 { + + for i_0 in 0..3i32 { let iVert_0: i32 = *pV.offset(i_0 as isize) as i32; let vSrcP = get_position( geometry, @@ -433,13 +423,10 @@ unsafe fn DegenEpilogue( let iOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; *psTspace.offset((iOffs + iMissingIndex) as isize) = *psTspace.offset((iOffs + iVert_0) as isize); - bNotFound_0 = false - } else { - i_0 += 1 + break; } } } - t += 1 } } From 2ad067a083d0fac920b6269192799bf7c180e1b5 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:01:01 +0100 Subject: [PATCH 11/44] Update GenerateTSpaces --- crates/bevy_mikktspace/src/generated.rs | 62 +++++++++++-------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 9d1f97b122013..cb955342cb045 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -441,14 +441,10 @@ unsafe fn GenerateTSpaces( ) -> bool { let mut iMaxNrFaces: usize = 0; let mut iUniqueTspaces = 0; - let mut g: i32 = 0i32; - let mut i: i32 = 0i32; - g = 0i32; - while g < iNrActiveGroups { + for g in 0..iNrActiveGroups { if iMaxNrFaces < (*pGroups.offset(g as isize)).iNrFaces as usize { iMaxNrFaces = (*pGroups.offset(g as isize)).iNrFaces as usize } - g += 1 } if iMaxNrFaces == 0 { return true; @@ -459,26 +455,19 @@ unsafe fn GenerateTSpaces( let mut pTmpMembers = vec![0i32; iMaxNrFaces]; iUniqueTspaces = 0; - g = 0i32; - while g < iNrActiveGroups { + + for g in 0..iNrActiveGroups { let mut pGroup: *const SGroup = &*pGroups.offset(g as isize) as *const SGroup; let mut iUniqueSubGroups = 0; let mut s = 0; - i = 0i32; - while i < (*pGroup).iNrFaces { + + for i in 0..(*pGroup).iNrFaces { let f: i32 = *(*pGroup).pFaceIndices.offset(i as isize); let mut index: i32 = -1i32; - let mut iVertIndex: i32 = -1i32; - let mut iOF_1: i32 = -1i32; - let mut iMembers: usize = 0; - let mut j: i32 = 0i32; - let mut l: usize = 0; let mut tmp_group: SSubGroup = SSubGroup { iNrFaces: 0, pTriMembers: Vec::new(), }; - let mut bFound: bool = false; - let mut n = Vec3::new(0.0, 0.0, 0.0); let mut vOs = Vec3::new(0.0, 0.0, 0.0); let mut vOt = Vec3::new(0.0, 0.0, 0.0); if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] == pGroup as *mut SGroup { @@ -490,8 +479,8 @@ unsafe fn GenerateTSpaces( { index = 2i32 } - iVertIndex = *piTriListIn.offset((f * 3i32 + index) as isize); - n = get_normal(geometry, iVertIndex as usize); + let iVertIndex = *piTriListIn.offset((f * 3i32 + index) as isize); + let n = get_normal(geometry, iVertIndex as usize); let mut vOs = (*pTriInfos.offset(f as isize)).vOs - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); let mut vOt = (*pTriInfos.offset(f as isize)).vOt @@ -502,10 +491,10 @@ unsafe fn GenerateTSpaces( if VNotZero(vOt) { vOt = Normalize(vOt) } - iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; - iMembers = 0; - j = 0i32; - while j < (*pGroup).iNrFaces { + let iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; + let mut iMembers = 0; + + for j in 0..(*pGroup).iNrFaces { let t: i32 = *(*pGroup).pFaceIndices.offset(j as isize); let iOF_2: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; let mut vOs2 = (*pTriInfos.offset(t as isize)).vOs @@ -529,23 +518,26 @@ unsafe fn GenerateTSpaces( iMembers = iMembers + 1; pTmpMembers[fresh0] = t } - j += 1 } if iMembers > 1 { - let mut uSeed: u32 = 39871946i32 as u32; - QuickSort(pTmpMembers.as_mut_ptr(), 0i32, (iMembers - 1) as i32, uSeed); + pTmpMembers[0..(iMembers - 1)].sort(); } tmp_group.iNrFaces = iMembers as i32; tmp_group.pTriMembers = pTmpMembers.clone(); - bFound = false; - l = 0; - while l < iUniqueSubGroups && !bFound { - bFound = CompareSubGroups(&mut tmp_group, &mut pUniSubGroups[l]); - if !bFound { - l += 1 + + let mut found = None; + for l in 0..iUniqueSubGroups { + if tmp_group == pUniSubGroups[l] { + found = Some(l); + break; } } - if !bFound { + let idx; + if let Some(it) = found { + idx = it; + } else { + idx = iUniqueSubGroups; + // C: if no match was found we allocate a new subgroup pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers as i32; pUniSubGroups[iUniqueSubGroups].pTriMembers = tmp_group.pTriMembers.clone(); @@ -563,18 +555,16 @@ unsafe fn GenerateTSpaces( let iVert = (*pTriInfos.offset(f as isize)).vert_num[index as usize] as usize; let mut pTS_out: *mut STSpace = &mut psTspace[iOffs + iVert] as *mut STSpace; if (*pTS_out).iCounter == 1i32 { - *pTS_out = AvgTSpace(pTS_out, &mut pSubGroupTspace[l]); + *pTS_out = AvgTSpace(pTS_out, &mut pSubGroupTspace[idx]); (*pTS_out).iCounter = 2i32; (*pTS_out).bOrient = (*pGroup).bOrientPreservering } else { - *pTS_out = pSubGroupTspace[l]; + *pTS_out = pSubGroupTspace[idx]; (*pTS_out).iCounter = 1i32; (*pTS_out).bOrient = (*pGroup).bOrientPreservering } - i += 1 } iUniqueTspaces += iUniqueSubGroups; - g += 1 } return true; } From e20f512c82775fcd0d71a1943527fbdc21e3d623 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:01:29 +0100 Subject: [PATCH 12/44] Update `EvalTspace` --- crates/bevy_mikktspace/src/generated.rs | 66 ++++++++----------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index cb955342cb045..bd95b2e67b7cb 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -621,48 +621,21 @@ unsafe fn EvalTspace( geometry: &impl Geometry, iVertexRepresentitive: i32, ) -> STSpace { - let mut res: STSpace = STSpace { - vOs: Vec3::new(0.0, 0.0, 0.0), - fMagS: 0., - vOt: Vec3::new(0.0, 0.0, 0.0), - fMagT: 0., - iCounter: 0, - bOrient: false, - }; + let mut res: STSpace = STSpace::zero(); let mut fAngleSum: f32 = 0i32 as f32; - let mut face: i32 = 0i32; - res.vOs.x = 0.0f32; - res.vOs.y = 0.0f32; - res.vOs.z = 0.0f32; - res.vOt.x = 0.0f32; - res.vOt.y = 0.0f32; - res.vOt.z = 0.0f32; - res.fMagS = 0i32 as f32; - res.fMagT = 0i32 as f32; - face = 0i32; - while face < iFaces { + + for face in 0..iFaces { let f: i32 = *face_indices.offset(face as isize); if !(*pTriInfos.offset(f as isize)) .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { - let mut n = Vec3::new(0.0, 0.0, 0.0); let mut vOs = Vec3::new(0.0, 0.0, 0.0); let mut vOt = Vec3::new(0.0, 0.0, 0.0); - let mut p0 = Vec3::new(0.0, 0.0, 0.0); - let mut p1 = Vec3::new(0.0, 0.0, 0.0); - let mut p2 = Vec3::new(0.0, 0.0, 0.0); - let mut v1 = Vec3::new(0.0, 0.0, 0.0); - let mut v2 = Vec3::new(0.0, 0.0, 0.0); + let mut fCos: f32 = 0.; - let mut fAngle: f32 = 0.; - let mut fMagS: f32 = 0.; - let mut fMagT: f32 = 0.; let mut i: i32 = -1i32; - let mut index: i32 = -1i32; - let mut i0: i32 = -1i32; - let mut i1: i32 = -1i32; - let mut i2: i32 = -1i32; + if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive { i = 0i32 } else if *piTriListIn.offset((3i32 * f + 1i32) as isize) == iVertexRepresentitive { @@ -670,8 +643,8 @@ unsafe fn EvalTspace( } else if *piTriListIn.offset((3i32 * f + 2i32) as isize) == iVertexRepresentitive { i = 2i32 } - index = *piTriListIn.offset((3i32 * f + i) as isize); - n = get_normal(geometry, index as usize); + let index = *piTriListIn.offset((3i32 * f + i) as isize); + let n = get_normal(geometry, index as usize); let mut vOs = (*pTriInfos.offset(f as isize)).vOs - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); let mut vOt = (*pTriInfos.offset(f as isize)).vOt @@ -682,14 +655,16 @@ unsafe fn EvalTspace( if VNotZero(vOt) { vOt = Normalize(vOt) } - i2 = *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - i1 = *piTriListIn.offset((3i32 * f + i) as isize); - i0 = *piTriListIn.offset((3i32 * f + if i > 0i32 { i - 1i32 } else { 2i32 }) as isize); - p0 = get_position(geometry, i0 as usize); - p1 = get_position(geometry, i1 as usize); - p2 = get_position(geometry, i2 as usize); - v1 = p0 - p1; - v2 = p2 - p1; + let i2 = + *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); + let i1 = *piTriListIn.offset((3i32 * f + i) as isize); + let i0 = + *piTriListIn.offset((3i32 * f + if i > 0i32 { i - 1i32 } else { 2i32 }) as isize); + let p0 = get_position(geometry, i0 as usize); + let p1 = get_position(geometry, i1 as usize); + let p2 = get_position(geometry, i2 as usize); + let v1 = p0 - p1; + let v2 = p2 - p1; let mut v1 = v1 - (n.dot(v1) * n); if VNotZero(v1) { v1 = Normalize(v1) @@ -707,16 +682,15 @@ unsafe fn EvalTspace( } else { fCos }; - fAngle = (fCos as f64).acos() as f32; - fMagS = (*pTriInfos.offset(f as isize)).fMagS; - fMagT = (*pTriInfos.offset(f as isize)).fMagT; + let fAngle = (fCos as f64).acos() as f32; + let fMagS = (*pTriInfos.offset(f as isize)).fMagS; + let fMagT = (*pTriInfos.offset(f as isize)).fMagT; res.vOs = res.vOs + (fAngle * vOs); res.vOt = res.vOt + (fAngle * vOt); res.fMagS += fAngle * fMagS; res.fMagT += fAngle * fMagT; fAngleSum += fAngle } - face += 1 } if VNotZero(res.vOs) { res.vOs = Normalize(res.vOs) From 833e2cffa49fd2fd84199e60d08fa793fec22971 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:02:45 +0100 Subject: [PATCH 13/44] Update `Build4RuleGroups` --- crates/bevy_mikktspace/src/generated.rs | 82 ++----------------------- 1 file changed, 6 insertions(+), 76 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index bd95b2e67b7cb..6e16fd15204d6 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -705,68 +705,6 @@ unsafe fn EvalTspace( return res; } -unsafe fn CompareSubGroups(mut pg1: *const SSubGroup, mut pg2: *const SSubGroup) -> bool { - let mut bStillSame: bool = true; - let mut i = 0; - if (*pg1).iNrFaces != (*pg2).iNrFaces { - return false; - } - while i < (*pg1).iNrFaces as usize && bStillSame { - bStillSame = if (*pg1).pTriMembers[i] == (*pg2).pTriMembers[i] { - true - } else { - false - }; - if bStillSame { - i += 1 - } - } - return bStillSame; -} -unsafe fn QuickSort(mut pSortBuffer: *mut i32, mut iLeft: i32, mut iRight: i32, mut uSeed: u32) { - let mut iL: i32 = 0; - let mut iR: i32 = 0; - let mut n: i32 = 0; - let mut index: i32 = 0; - let mut iMid: i32 = 0; - let mut iTmp: i32 = 0; - - // Random - let mut t: u32 = uSeed & 31i32 as u32; - t = uSeed.rotate_left(t) | uSeed.rotate_right((32i32 as u32).wrapping_sub(t)); - uSeed = uSeed.wrapping_add(t).wrapping_add(3i32 as u32); - // Random end - - iL = iLeft; - iR = iRight; - n = iR - iL + 1i32; - index = uSeed.wrapping_rem(n as u32) as i32; - iMid = *pSortBuffer.offset((index + iL) as isize); - loop { - while *pSortBuffer.offset(iL as isize) < iMid { - iL += 1 - } - while *pSortBuffer.offset(iR as isize) > iMid { - iR -= 1 - } - if iL <= iR { - iTmp = *pSortBuffer.offset(iL as isize); - *pSortBuffer.offset(iL as isize) = *pSortBuffer.offset(iR as isize); - *pSortBuffer.offset(iR as isize) = iTmp; - iL += 1; - iR -= 1 - } - if !(iL <= iR) { - break; - } - } - if iLeft < iR { - QuickSort(pSortBuffer, iLeft, iR, uSeed); - } - if iL < iRight { - QuickSort(pSortBuffer, iL, iRight, uSeed); - }; -} unsafe fn Build4RuleGroups( mut pTriInfos: *mut STriInfo, mut pGroups: *mut SGroup, @@ -777,20 +715,14 @@ unsafe fn Build4RuleGroups( let iNrMaxGroups: i32 = iNrTrianglesIn * 3i32; let mut iNrActiveGroups: i32 = 0i32; let mut iOffset: i32 = 0i32; - let mut f: i32 = 0i32; - let mut i: i32 = 0i32; - f = 0i32; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { + + for f in 0..iNrTrianglesIn { + for i in 0..3i32 { if !(*pTriInfos.offset(f as isize)) .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) && (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize].is_null() { - let mut bOrPre: bool = false; - let mut neigh_indexL: i32 = 0; - let mut neigh_indexR: i32 = 0; let vert_index: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); let ref mut fresh2 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; *fresh2 = &mut *pGroups.offset(iNrActiveGroups as isize) as *mut SGroup; @@ -806,11 +738,11 @@ unsafe fn Build4RuleGroups( *fresh3 = &mut *piGroupTrianglesBuffer.offset(iOffset as isize) as *mut i32; iNrActiveGroups += 1; AddTriToGroup((*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], f); - bOrPre = (*pTriInfos.offset(f as isize)) + let bOrPre = (*pTriInfos.offset(f as isize)) .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - neigh_indexL = (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize]; - neigh_indexR = (*pTriInfos.offset(f as isize)).FaceNeighbors + let mut neigh_indexL = (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize]; + let mut neigh_indexR = (*pTriInfos.offset(f as isize)).FaceNeighbors [(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; if neigh_indexL >= 0i32 { let bAnswer: bool = AssignRecur( @@ -838,9 +770,7 @@ unsafe fn Build4RuleGroups( } iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces } - i += 1 } - f += 1 } return iNrActiveGroups; } From dc044cad37305816fa470c2245028cf596788707 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:03:21 +0100 Subject: [PATCH 14/44] Update InitTriInfo --- crates/bevy_mikktspace/src/generated.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 6e16fd15204d6..748bac7f53569 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -843,13 +843,8 @@ unsafe fn InitTriInfo( geometry: &impl Geometry, iNrTrianglesIn: usize, ) { - let mut f = 0; - let mut i = 0; - let mut t = 0; - f = 0; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { + for f in 0..iNrTrianglesIn { + for i in 0..3i32 { (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize] = -1i32; let ref mut fresh4 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; *fresh4 = 0 as *mut SGroup; @@ -864,12 +859,9 @@ unsafe fn InitTriInfo( (*pTriInfos.offset(f as isize)) .iFlag .insert(TriangleFlags::GROUP_WITH_ANY); - i += 1 } - f += 1 } - f = 0; - while f < iNrTrianglesIn { + for f in 0..iNrTrianglesIn { let v1 = get_position(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); let v2 = get_position(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); let v3 = get_position(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); @@ -918,8 +910,8 @@ unsafe fn InitTriInfo( .remove(TriangleFlags::GROUP_WITH_ANY); } } - f += 1 } + let mut t = 0; while t < iNrTrianglesIn - 1 { let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; From bd774415c461da7d460d8114cc1537426c12462e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:03:44 +0100 Subject: [PATCH 15/44] Update BuildNeighborsFast --- crates/bevy_mikktspace/src/generated.rs | 165 ++++-------------------- 1 file changed, 26 insertions(+), 139 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 748bac7f53569..9ab4c8253c3ba 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -958,17 +958,12 @@ unsafe fn InitTriInfo( } let mut pEdges = vec![SEdge::zero(); iNrTrianglesIn * 3]; - BuildNeighborsFast( - pTriInfos, - pEdges.as_mut_ptr(), - piTriListIn, - iNrTrianglesIn as i32, - ); + BuildNeighborsFast(pTriInfos, &mut pEdges, piTriListIn, iNrTrianglesIn as i32); } unsafe fn BuildNeighborsFast( mut pTriInfos: *mut STriInfo, - mut pEdges: *mut SEdge, + mut pEdges: &mut [SEdge], mut piTriListIn: *const i32, iNrTrianglesIn: i32, ) { @@ -977,58 +972,25 @@ unsafe fn BuildNeighborsFast( let mut uSeed: u32 = 39871946i32 as u32; let mut iEntries: i32 = 0i32; let mut iCurStartIndex: i32 = -1i32; - let mut f: i32 = 0i32; - let mut i: i32 = 0i32; - f = 0i32; - while f < iNrTrianglesIn { - i = 0i32; - while i < 3i32 { + + for f in 0..iNrTrianglesIn { + for i in 0..3i32 { let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); let i1: i32 = *piTriListIn.offset((f * 3i32 + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.i0 = if i0 < i1 { i0 } else { i1 }; - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.i1 = if !(i0 < i1) { i0 } else { i1 }; - (*pEdges.offset((f * 3i32 + i) as isize)).unnamed.f = f; - i += 1 - } - f += 1 - } - QuickSortEdges(pEdges, 0i32, iNrTrianglesIn * 3i32 - 1i32, 0i32, uSeed); - iEntries = iNrTrianglesIn * 3i32; - iCurStartIndex = 0i32; - i = 1i32; - while i < iEntries { - if (*pEdges.offset(iCurStartIndex as isize)).unnamed.i0 - != (*pEdges.offset(i as isize)).unnamed.i0 - { - let iL: i32 = iCurStartIndex; - let iR: i32 = i - 1i32; - iCurStartIndex = i; - QuickSortEdges(pEdges, iL, iR, 1i32, uSeed); + pEdges[((f * 3i32 + i) as usize)].i0 = if i0 < i1 { i0 } else { i1 }; // put minimum index in i0 + (pEdges[(f * 3i32 + i) as usize]).i1 = if !(i0 < i1) { i0 } else { i1 }; // put maximum index in i1 + (pEdges[(f * 3i32 + i) as usize]).f = f; // record face number } - i += 1 - } - iCurStartIndex = 0i32; - i = 1i32; - while i < iEntries { - if (*pEdges.offset(iCurStartIndex as isize)).unnamed.i0 - != (*pEdges.offset(i as isize)).unnamed.i0 - || (*pEdges.offset(iCurStartIndex as isize)).unnamed.i1 - != (*pEdges.offset(i as isize)).unnamed.i1 - { - let iL_0: i32 = iCurStartIndex; - let iR_0: i32 = i - 1i32; - iCurStartIndex = i; - QuickSortEdges(pEdges, iL_0, iR_0, 2i32, uSeed); - } - i += 1 } - i = 0i32; - while i < iEntries { - let i0_0: i32 = (*pEdges.offset(i as isize)).unnamed.i0; - let i1_0: i32 = (*pEdges.offset(i as isize)).unnamed.i1; - let f_0: i32 = (*pEdges.offset(i as isize)).unnamed.f; - let mut bUnassigned_A: bool = false; + pEdges.sort(); + + for i in 0..iEntries { + let edge = pEdges[i as usize]; + let i0_0: i32 = edge.i0; + let i1_0: i32 = edge.i1; + let f_0: i32 = edge.f; + let mut i0_A: i32 = 0; let mut i1_A: i32 = 0; let mut edgenum_A: i32 = 0; @@ -1041,34 +1003,29 @@ unsafe fn BuildNeighborsFast( i0_0, i1_0, ); - bUnassigned_A = - if (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32 { - true - } else { - false - }; + let bUnassigned_A = + (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32; if bUnassigned_A { let mut j: i32 = i + 1i32; - let mut t: i32 = 0; + let mut bNotFound: bool = true; while j < iEntries - && i0_0 == (*pEdges.offset(j as isize)).unnamed.i0 - && i1_0 == (*pEdges.offset(j as isize)).unnamed.i1 + && i0_0 == pEdges[j as usize].i0 + && i1_0 == pEdges[j as usize].i1 && bNotFound { - let mut bUnassigned_B: bool = false; let mut i0_B: i32 = 0; let mut i1_B: i32 = 0; - t = (*pEdges.offset(j as isize)).unnamed.f; + let t = pEdges[j as usize].f; GetEdge( &mut i1_B, &mut i0_B, &mut edgenum_B, &*piTriListIn.offset((t * 3i32) as isize), - (*pEdges.offset(j as isize)).unnamed.i0, - (*pEdges.offset(j as isize)).unnamed.i1, + pEdges[j as usize].i0, + pEdges[j as usize].i1, ); - bUnassigned_B = + let bUnassigned_B = if (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32 { true } else { @@ -1081,12 +1038,11 @@ unsafe fn BuildNeighborsFast( } } if !bNotFound { - let mut t_0: i32 = (*pEdges.offset(j as isize)).unnamed.f; + let mut t_0: i32 = pEdges[j as usize].f; (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0 } } - i += 1 } } unsafe fn GetEdge( @@ -1116,75 +1072,6 @@ unsafe fn GetEdge( } // /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// -unsafe fn QuickSortEdges( - mut pSortBuffer: *mut SEdge, - mut iLeft: i32, - mut iRight: i32, - channel: i32, - mut uSeed: u32, -) { - let mut t: u32 = 0; - let mut iL: i32 = 0; - let mut iR: i32 = 0; - let mut n: i32 = 0; - let mut index: i32 = 0; - let mut iMid: i32 = 0; - // early out - let mut sTmp: SEdge = SEdge { - unnamed: unnamed { i0: 0, i1: 0, f: 0 }, - }; - let iElems: i32 = iRight - iLeft + 1i32; - if iElems < 2i32 { - return; - } else { - if iElems == 2i32 { - if (*pSortBuffer.offset(iLeft as isize)).array[channel as usize] - > (*pSortBuffer.offset(iRight as isize)).array[channel as usize] - { - sTmp = *pSortBuffer.offset(iLeft as isize); - *pSortBuffer.offset(iLeft as isize) = *pSortBuffer.offset(iRight as isize); - *pSortBuffer.offset(iRight as isize) = sTmp - } - return; - } - } - - // Random - t = uSeed & 31i32 as u32; - t = uSeed.rotate_left(t) | uSeed.rotate_right((32i32 as u32).wrapping_sub(t)); - uSeed = uSeed.wrapping_add(t).wrapping_add(3i32 as u32); - // Random end - - iL = iLeft; - iR = iRight; - n = iR - iL + 1i32; - index = uSeed.wrapping_rem(n as u32) as i32; - iMid = (*pSortBuffer.offset((index + iL) as isize)).array[channel as usize]; - loop { - while (*pSortBuffer.offset(iL as isize)).array[channel as usize] < iMid { - iL += 1 - } - while (*pSortBuffer.offset(iR as isize)).array[channel as usize] > iMid { - iR -= 1 - } - if iL <= iR { - sTmp = *pSortBuffer.offset(iL as isize); - *pSortBuffer.offset(iL as isize) = *pSortBuffer.offset(iR as isize); - *pSortBuffer.offset(iR as isize) = sTmp; - iL += 1; - iR -= 1 - } - if !(iL <= iR) { - break; - } - } - if iLeft < iR { - QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); - } - if iL < iRight { - QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); - }; -} // returns the texture area times 2 unsafe fn CalcTexArea(geometry: &impl Geometry, mut indices: *const i32) -> f32 { From 5e545ca4084ae1cc5d374f39f9074af8d4a46120 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:04:00 +0100 Subject: [PATCH 16/44] Update DegenPrologue --- crates/bevy_mikktspace/src/generated.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 9ab4c8253c3ba..c69fd3aaf988f 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -1097,8 +1097,6 @@ unsafe fn DegenPrologue( iNrTrianglesIn: i32, iTotTris: i32, ) { - let mut iNextGoodTriangleSearchIndex: i32 = -1i32; - let mut bStillFindingGoodOnes: bool = false; // locate quads with only one good triangle let mut t: i32 = 0i32; while t < iTotTris - 1i32 { @@ -1135,9 +1133,9 @@ unsafe fn DegenPrologue( // but good enough and safe. // TODO: Consider using `sort_by_key` on Vec instead (which is stable) - it might be // technically slower, but it's much easier to reason about - iNextGoodTriangleSearchIndex = 1i32; + let mut iNextGoodTriangleSearchIndex = 1i32; t = 0i32; - bStillFindingGoodOnes = true; + let mut bStillFindingGoodOnes = true; while t < iNrTrianglesIn && bStillFindingGoodOnes { let bIsGood: bool = !(*pTriInfos.offset(t as isize)) .iFlag @@ -1147,8 +1145,6 @@ unsafe fn DegenPrologue( iNextGoodTriangleSearchIndex = t + 2i32 } } else { - let mut t0: i32 = 0; - let mut t1: i32 = 0; let mut bJustADegenerate: bool = true; while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { let bIsGood_0: bool = !(*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)) @@ -1160,19 +1156,16 @@ unsafe fn DegenPrologue( iNextGoodTriangleSearchIndex += 1 } } - t0 = t; - t1 = iNextGoodTriangleSearchIndex; + let t0 = t; + let t1 = iNextGoodTriangleSearchIndex; iNextGoodTriangleSearchIndex += 1; // Swap t0 and t1 if !bJustADegenerate { - let mut i: i32 = 0i32; - i = 0i32; - while i < 3i32 { + for i in 0..3i32 { let index: i32 = *piTriList_out.offset((t0 * 3i32 + i) as isize); *piTriList_out.offset((t0 * 3i32 + i) as isize) = *piTriList_out.offset((t1 * 3i32 + i) as isize); *piTriList_out.offset((t1 * 3i32 + i) as isize) = index; - i += 1 } let tri_info: STriInfo = *pTriInfos.offset(t0 as isize); *pTriInfos.offset(t0 as isize) = *pTriInfos.offset(t1 as isize); From 226e4e1f1f6a3053213c0a2559f2da943d6f525b Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:04:13 +0100 Subject: [PATCH 17/44] Update GenerateSharedVerticesIndexList --- crates/bevy_mikktspace/src/generated.rs | 69 ++++++++++--------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index c69fd3aaf988f..db8a4cc23e258 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -1191,18 +1191,10 @@ unsafe fn GenerateSharedVerticesIndexList( geometry: &impl Geometry, iNrTrianglesIn: usize, ) { - let mut i = 0; - let mut iChannel: i32 = 0i32; - let mut k = 0; - let mut e = 0; - let mut iMaxCount = 0; let mut vMin = get_position(geometry, 0); let mut vMax = vMin; - let mut vDim = Vec3::new(0.0, 0.0, 0.0); - let mut fMin: f32 = 0.; - let mut fMax: f32 = 0.; - i = 1; - while i < iNrTrianglesIn * 3 { + + for i in 0..(iNrTrianglesIn * 3) { let index: i32 = *piTriList_in_and_out.offset(i as isize); let vP = get_position(geometry, index as usize); if vMin.x > vP.x { @@ -1220,12 +1212,11 @@ unsafe fn GenerateSharedVerticesIndexList( } else if vMax.z < vP.z { vMax.z = vP.z } - i += 1 } - vDim = vMax - vMin; - iChannel = 0i32; - fMin = vMin.x; - fMax = vMax.x; + let vDim = vMax - vMin; + let iChannel; + let fMin; + let fMax; if vDim.y > vDim.x && vDim.y > vDim.z { iChannel = 1i32; fMin = vMin.y; @@ -1234,6 +1225,10 @@ unsafe fn GenerateSharedVerticesIndexList( iChannel = 2i32; fMin = vMin.z; fMax = vMax.z + } else { + iChannel = 0i32; + fMin = vMin.x; + fMax = vMax.x; } let mut piHashTable = vec![0i32; iNrTrianglesIn * 3]; @@ -1241,8 +1236,7 @@ unsafe fn GenerateSharedVerticesIndexList( let mut piHashCount = vec![0i32; g_iCells]; let mut piHashCount2 = vec![0i32; g_iCells]; - i = 0; - while i < iNrTrianglesIn * 3 { + for i in 0..(iNrTrianglesIn * 3) { let index_0: i32 = *piTriList_in_and_out.offset(i as isize); let vP_0 = get_position(geometry, index_0 as usize); let fVal: f32 = if iChannel == 0i32 { @@ -1254,16 +1248,13 @@ unsafe fn GenerateSharedVerticesIndexList( }; let iCell = FindGridCell(fMin, fMax, fVal); piHashCount[iCell] += 1; - i += 1 } piHashOffsets[0] = 0i32; - k = 1; - while k < g_iCells { + + for k in 1..g_iCells { piHashOffsets[k] = piHashOffsets[k - 1] + piHashCount[k - 1]; - k += 1 } - i = 0; - while i < iNrTrianglesIn * 3 { + for i in 0..(iNrTrianglesIn * 3) { let index_1: i32 = *piTriList_in_and_out.offset(i as isize); let vP_1 = get_position(geometry, index_1 as usize); let fVal_0: f32 = if iChannel == 0i32 { @@ -1275,32 +1266,26 @@ unsafe fn GenerateSharedVerticesIndexList( }; let iCell_0 = FindGridCell(fMin, fMax, fVal_0); let mut pTable: *mut i32 = 0 as *mut i32; - pTable = &mut piHashTable[piHashOffsets[iCell_0] as usize] as *mut i32; + let pTable = piHashTable + .as_mut_ptr() + .offset(piHashOffsets[iCell_0] as isize); *pTable.offset(piHashCount2[iCell_0] as isize) = i as i32; piHashCount2[iCell_0] += 1; - i += 1 - } - k = 0; - while k < g_iCells { - k += 1 - } - iMaxCount = piHashCount[0] as usize; - k = 1; - while k < g_iCells { - if iMaxCount < piHashCount[k] as usize { - iMaxCount = piHashCount[k] as usize - } - k += 1 } + + debug_assert_eq!(piHashCount, piHashCount2); + drop(piHashCount2); + + let iMaxCount = piHashCount.iter().max().copied().unwrap() as usize; + let mut pTmpVert = vec![STmpVert::zero(); iMaxCount]; - k = 0; - while k < g_iCells { + + for k in 0..g_iCells { // extract table of cell k and amount of entries in it let mut pTable_0 = &mut piHashTable[piHashOffsets[k] as usize] as *mut i32; let iEntries = piHashCount[k] as usize; if !(iEntries < 2) { - e = 0; - while e < iEntries { + for e in 0..iEntries { let mut i_0: i32 = *pTable_0.offset(e as isize); let vP_2 = get_position( geometry, @@ -1310,7 +1295,6 @@ unsafe fn GenerateSharedVerticesIndexList( pTmpVert[e].vert[1usize] = vP_2.y; pTmpVert[e].vert[2usize] = vP_2.z; pTmpVert[e].index = i_0; - e += 1 } MergeVertsFast( piTriList_in_and_out, @@ -1320,7 +1304,6 @@ unsafe fn GenerateSharedVerticesIndexList( (iEntries - 1) as i32, ); } - k += 1 } } From 2e7d1b61eb9eabb98d7f57578538b7fd8a7d0c62 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:04:51 +0100 Subject: [PATCH 18/44] Update MergeVertsFast --- crates/bevy_mikktspace/src/generated.rs | 37 +++++++++---------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index db8a4cc23e258..de14f3337bdec 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -1315,47 +1315,37 @@ unsafe fn MergeVertsFast( iR_in: i32, ) { // make bbox - let mut c: i32 = 0i32; - let mut l: i32 = 0i32; - let mut channel: i32 = 0i32; let mut fvMin: [f32; 3] = [0.; 3]; let mut fvMax: [f32; 3] = [0.; 3]; - let mut dx: f32 = 0i32 as f32; - let mut dy: f32 = 0i32 as f32; - let mut dz: f32 = 0i32 as f32; - let mut fSep: f32 = 0i32 as f32; - c = 0i32; - while c < 3i32 { + + for c in 0..3i32 { fvMin[c as usize] = (*pTmpVert.offset(iL_in as isize)).vert[c as usize]; fvMax[c as usize] = fvMin[c as usize]; - c += 1 } - l = iL_in + 1i32; - while l <= iR_in { - c = 0i32; - while c < 3i32 { + + for l in (iL_in + 1i32)..=iR_in { + for c in 0..3i32 { if fvMin[c as usize] > (*pTmpVert.offset(l as isize)).vert[c as usize] { fvMin[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] } else if fvMax[c as usize] < (*pTmpVert.offset(l as isize)).vert[c as usize] { fvMax[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] } - c += 1 } - l += 1 } - dx = fvMax[0usize] - fvMin[0usize]; - dy = fvMax[1usize] - fvMin[1usize]; - dz = fvMax[2usize] - fvMin[2usize]; - channel = 0i32; + let dx = fvMax[0usize] - fvMin[0usize]; + let dy = fvMax[1usize] - fvMin[1usize]; + let dz = fvMax[2usize] - fvMin[2usize]; + let channel; if dy > dx && dy > dz { channel = 1i32 } else if dz > dx { channel = 2i32 + } else { + channel = 0i32 } - fSep = 0.5f32 * (fvMax[channel as usize] + fvMin[channel as usize]); + let fSep = 0.5f32 * (fvMax[channel as usize] + fvMin[channel as usize]); if fSep >= fvMax[channel as usize] || fSep <= fvMin[channel as usize] { - l = iL_in; - while l <= iR_in { + for l in iL_in..=iR_in { let mut i: i32 = (*pTmpVert.offset(l as isize)).index; let index: i32 = *piTriList_in_and_out.offset(i as isize); let vP = get_position(geometry, index as usize); @@ -1390,7 +1380,6 @@ unsafe fn MergeVertsFast( *piTriList_in_and_out.offset(i as isize) = *piTriList_in_and_out.offset(i2rec as isize) } - l += 1 } } else { let mut iL: i32 = iL_in; From 58c5dbcddecae29dfa6b1af05e970f226233ac93 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:05:02 +0100 Subject: [PATCH 19/44] Update GenerateInitialVerticesIndexList --- crates/bevy_mikktspace/src/generated.rs | 28 ++++++++++--------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index de14f3337bdec..5b93077691020 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -44,7 +44,6 @@ non_snake_case, non_upper_case_globals, unused_mut, - unused_assignments, unused_variables )] @@ -163,7 +162,7 @@ impl SGroup { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct SSubGroup { pub iNrFaces: i32, pub pTriMembers: Vec, @@ -178,15 +177,16 @@ impl SSubGroup { } } -#[derive(Copy, Clone)] -pub union SEdge { - pub unnamed: unnamed, - pub array: [i32; 3], +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct SEdge { + pub i0: i32, + pub i1: i32, + pub f: i32, } impl SEdge { fn zero() -> Self { - Self { array: [0, 0, 0] } + Self::default() } } @@ -1452,11 +1452,8 @@ unsafe fn GenerateInitialVerticesIndexList( iNrTrianglesIn: usize, ) -> usize { let mut iTSpacesOffs: usize = 0; - let mut f = 0; - let mut t: usize = 0; let mut iDstTriIndex = 0; - f = 0; - while f < geometry.num_faces() { + for f in 0..geometry.num_faces() { let verts = geometry.num_vertices_of_face(f); pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; @@ -1483,7 +1480,7 @@ unsafe fn GenerateInitialVerticesIndexList( let T3 = get_tex_coord(geometry, i3); let distSQ_02: f32 = (T2 - T0).length_squared(); let distSQ_13: f32 = (T3 - T1).length_squared(); - let mut bQuadDiagIs_02: bool = false; + let bQuadDiagIs_02: bool; if distSQ_02 < distSQ_13 { bQuadDiagIs_02 = true } else if distSQ_13 < distSQ_02 { @@ -1540,13 +1537,10 @@ unsafe fn GenerateInitialVerticesIndexList( } } iTSpacesOffs += verts.num_vertices(); - - f += 1 } - t = 0; - while t < iNrTrianglesIn { + + for t in 0..iNrTrianglesIn { pTriInfos[t].iFlag = TriangleFlags::empty(); - t += 1 } return iTSpacesOffs; } From 958ead9151d922e136a856a447d9154094873913 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 5 Jun 2022 20:43:50 +0100 Subject: [PATCH 20/44] Set iEntries properly --- crates/bevy_mikktspace/src/generated.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 5b93077691020..29e193816d076 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -985,6 +985,8 @@ unsafe fn BuildNeighborsFast( } pEdges.sort(); + let iEntries = iNrTrianglesIn * 3i32; + for i in 0..iEntries { let edge = pEdges[i as usize]; let i0_0: i32 = edge.i0; From 2083021dbadbb5f5628376fb52d7e1a5520bf8c6 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Mon, 6 Jun 2022 10:19:26 +0100 Subject: [PATCH 21/44] Remove unused variables Also replace `Normalize()` with `.normalize()` --- crates/bevy_mikktspace/src/generated.rs | 55 ++++++++----------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 29e193816d076..8d808f11a117e 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -43,8 +43,7 @@ non_camel_case_types, non_snake_case, non_upper_case_globals, - unused_mut, - unused_variables + unused_mut )] use std::ptr::null_mut; @@ -440,7 +439,6 @@ unsafe fn GenerateTSpaces( geometry: &impl Geometry, ) -> bool { let mut iMaxNrFaces: usize = 0; - let mut iUniqueTspaces = 0; for g in 0..iNrActiveGroups { if iMaxNrFaces < (*pGroups.offset(g as isize)).iNrFaces as usize { iMaxNrFaces = (*pGroups.offset(g as isize)).iNrFaces as usize @@ -454,12 +452,9 @@ unsafe fn GenerateTSpaces( let mut pUniSubGroups = vec![SSubGroup::zero(); iMaxNrFaces]; let mut pTmpMembers = vec![0i32; iMaxNrFaces]; - iUniqueTspaces = 0; - for g in 0..iNrActiveGroups { let mut pGroup: *const SGroup = &*pGroups.offset(g as isize) as *const SGroup; let mut iUniqueSubGroups = 0; - let mut s = 0; for i in 0..(*pGroup).iNrFaces { let f: i32 = *(*pGroup).pFaceIndices.offset(i as isize); @@ -468,8 +463,6 @@ unsafe fn GenerateTSpaces( iNrFaces: 0, pTriMembers: Vec::new(), }; - let mut vOs = Vec3::new(0.0, 0.0, 0.0); - let mut vOt = Vec3::new(0.0, 0.0, 0.0); if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] == pGroup as *mut SGroup { index = 0i32 } else if (*pTriInfos.offset(f as isize)).AssignedGroup[1usize] == pGroup as *mut SGroup @@ -486,10 +479,10 @@ unsafe fn GenerateTSpaces( let mut vOt = (*pTriInfos.offset(f as isize)).vOt - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); if VNotZero(vOs) { - vOs = Normalize(vOs) + vOs = vOs.normalize() } if VNotZero(vOt) { - vOt = Normalize(vOt) + vOt = vOt.normalize() } let iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; let mut iMembers = 0; @@ -502,10 +495,10 @@ unsafe fn GenerateTSpaces( let mut vOt2 = (*pTriInfos.offset(t as isize)).vOt - (n.dot((*pTriInfos.offset(t as isize)).vOt) * n); if VNotZero(vOs2) { - vOs2 = Normalize(vOs2) + vOs2 = vOs2.normalize() } if VNotZero(vOt2) { - vOt2 = Normalize(vOt2) + vOt2 = vOt2.normalize() } let bAny: bool = ((*pTriInfos.offset(f as isize)).iFlag | (*pTriInfos.offset(t as isize)).iFlag) @@ -564,7 +557,6 @@ unsafe fn GenerateTSpaces( (*pTS_out).bOrient = (*pGroup).bOrientPreservering } } - iUniqueTspaces += iUniqueSubGroups; } return true; } @@ -592,24 +584,20 @@ unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpa ts_res.vOs = (*pTS0).vOs + (*pTS1).vOs; ts_res.vOt = (*pTS0).vOt + (*pTS1).vOt; if VNotZero(ts_res.vOs) { - ts_res.vOs = Normalize(ts_res.vOs) + ts_res.vOs = ts_res.vOs.normalize(); } if VNotZero(ts_res.vOt) { - ts_res.vOt = Normalize(ts_res.vOt) + ts_res.vOt = ts_res.vOt.normalize(); } } return ts_res; } -unsafe fn Normalize(v: Vec3) -> Vec3 { - return (1.0 / v.length()) * v; -} - -unsafe fn VNotZero(v: Vec3) -> bool { +fn VNotZero(v: Vec3) -> bool { NotZero(v.x) || NotZero(v.y) || NotZero(v.z) } -unsafe fn NotZero(fX: f32) -> bool { +fn NotZero(fX: f32) -> bool { fX.abs() > 1.17549435e-38f32 } @@ -630,10 +618,6 @@ unsafe fn EvalTspace( .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { - let mut vOs = Vec3::new(0.0, 0.0, 0.0); - let mut vOt = Vec3::new(0.0, 0.0, 0.0); - - let mut fCos: f32 = 0.; let mut i: i32 = -1i32; if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive { @@ -650,10 +634,10 @@ unsafe fn EvalTspace( let mut vOt = (*pTriInfos.offset(f as isize)).vOt - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); if VNotZero(vOs) { - vOs = Normalize(vOs) + vOs = vOs.normalize(); } if VNotZero(vOt) { - vOt = Normalize(vOt) + vOt = vOt.normalize() } let i2 = *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); @@ -667,11 +651,11 @@ unsafe fn EvalTspace( let v2 = p2 - p1; let mut v1 = v1 - (n.dot(v1) * n); if VNotZero(v1) { - v1 = Normalize(v1) + v1 = v1.normalize() } let mut v2 = v2 - (n.dot(v2) * n); if VNotZero(v2) { - v2 = Normalize(v2) + v2 = v2.normalize() } let fCos = v1.dot(v2); @@ -693,10 +677,10 @@ unsafe fn EvalTspace( } } if VNotZero(res.vOs) { - res.vOs = Normalize(res.vOs) + res.vOs = res.vOs.normalize() } if VNotZero(res.vOt) { - res.vOt = Normalize(res.vOt) + res.vOt = res.vOt.normalize() } if fAngleSum > 0i32 as f32 { res.fMagS /= fAngleSum; @@ -712,7 +696,6 @@ unsafe fn Build4RuleGroups( mut piTriListIn: *const i32, iNrTrianglesIn: i32, ) -> i32 { - let iNrMaxGroups: i32 = iNrTrianglesIn * 3i32; let mut iNrActiveGroups: i32 = 0i32; let mut iOffset: i32 = 0i32; @@ -755,6 +738,7 @@ unsafe fn Build4RuleGroups( .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff: bool = if bOrPre != bOrPre2 { true } else { false }; + debug_assert!(bAnswer || bDiff) } if neigh_indexR >= 0i32 { let bAnswer_0: bool = AssignRecur( @@ -767,6 +751,7 @@ unsafe fn Build4RuleGroups( .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff_0: bool = if bOrPre != bOrPre2_0 { true } else { false }; + debug_assert!(bAnswer_0 || bDiff_0) } iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces } @@ -968,11 +953,6 @@ unsafe fn BuildNeighborsFast( iNrTrianglesIn: i32, ) { // build array of edges - // could replace with a random seed? - let mut uSeed: u32 = 39871946i32 as u32; - let mut iEntries: i32 = 0i32; - let mut iCurStartIndex: i32 = -1i32; - for f in 0..iNrTrianglesIn { for i in 0..3i32 { let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); @@ -1267,7 +1247,6 @@ unsafe fn GenerateSharedVerticesIndexList( vP_1.z }; let iCell_0 = FindGridCell(fMin, fMax, fVal_0); - let mut pTable: *mut i32 = 0 as *mut i32; let pTable = piHashTable .as_mut_ptr() .offset(piHashOffsets[iCell_0] as isize); From 2d69723d428b9241f415b143ae0c6264172b5e51 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Mon, 6 Jun 2022 12:00:51 +0100 Subject: [PATCH 22/44] Re-add asserts --- crates/bevy_mikktspace/src/generated.rs | 75 +++++++++++++++++-------- crates/bevy_mikktspace/src/lib.rs | 1 + 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 8d808f11a117e..5a7553b679573 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -458,21 +458,25 @@ unsafe fn GenerateTSpaces( for i in 0..(*pGroup).iNrFaces { let f: i32 = *(*pGroup).pFaceIndices.offset(i as isize); - let mut index: i32 = -1i32; let mut tmp_group: SSubGroup = SSubGroup { iNrFaces: 0, pTriMembers: Vec::new(), }; - if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] == pGroup as *mut SGroup { - index = 0i32 + let index = if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] + == pGroup as *mut SGroup + { + 0i32 } else if (*pTriInfos.offset(f as isize)).AssignedGroup[1usize] == pGroup as *mut SGroup { - index = 1i32 + 1i32 } else if (*pTriInfos.offset(f as isize)).AssignedGroup[2usize] == pGroup as *mut SGroup { - index = 2i32 - } + 2i32 + } else { + panic!() + }; let iVertIndex = *piTriListIn.offset((f * 3i32 + index) as isize); + assert!(iVertIndex == (*pGroup).iVertexRepresentitive); let n = get_normal(geometry, iVertIndex as usize); let mut vOs = (*pTriInfos.offset(f as isize)).vOs - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); @@ -506,6 +510,7 @@ unsafe fn GenerateTSpaces( let bSameOrgFace: bool = iOF_1 == iOF_2; let fCosS: f32 = vOs.dot(vOs2); let fCosT: f32 = vOt.dot(vOt2); + debug_assert!(f != t || bSameOrgFace); // sanity check if bAny || bSameOrgFace || fCosS > fThresCos && fCosT > fThresCos { let fresh0 = iMembers; iMembers = iMembers + 1; @@ -546,12 +551,20 @@ unsafe fn GenerateTSpaces( } let iOffs = (*pTriInfos.offset(f as isize)).iTSpacesOffs as usize; let iVert = (*pTriInfos.offset(f as isize)).vert_num[index as usize] as usize; - let mut pTS_out: *mut STSpace = &mut psTspace[iOffs + iVert] as *mut STSpace; + let mut pTS_out = &mut psTspace[iOffs + iVert]; + assert!(pTS_out.iCounter < 2); + debug_assert!( + (*pGroup).bOrientPreservering + == (*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING) + ); if (*pTS_out).iCounter == 1i32 { *pTS_out = AvgTSpace(pTS_out, &mut pSubGroupTspace[idx]); (*pTS_out).iCounter = 2i32; (*pTS_out).bOrient = (*pGroup).bOrientPreservering } else { + debug_assert!(pTS_out.iCounter == 0); *pTS_out = pSubGroupTspace[idx]; (*pTS_out).iCounter = 1i32; (*pTS_out).bOrient = (*pGroup).bOrientPreservering @@ -618,15 +631,16 @@ unsafe fn EvalTspace( .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { - let mut i: i32 = -1i32; - - if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive { - i = 0i32 + let i: i32 = if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive + { + 0i32 } else if *piTriListIn.offset((3i32 * f + 1i32) as isize) == iVertexRepresentitive { - i = 1i32 + 1i32 } else if *piTriListIn.offset((3i32 * f + 2i32) as isize) == iVertexRepresentitive { - i = 2i32 - } + 2i32 + } else { + panic!(); + }; let index = *piTriListIn.offset((3i32 * f + i) as isize); let n = get_normal(geometry, index as usize); let mut vOs = (*pTriInfos.offset(f as isize)).vOs @@ -698,6 +712,7 @@ unsafe fn Build4RuleGroups( ) -> i32 { let mut iNrActiveGroups: i32 = 0i32; let mut iOffset: i32 = 0i32; + let iNrMaxGroups = iNrTrianglesIn * 3; for f in 0..iNrTrianglesIn { for i in 0..3i32 { @@ -708,6 +723,7 @@ unsafe fn Build4RuleGroups( { let vert_index: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); let ref mut fresh2 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; + debug_assert!(iNrActiveGroups < iNrMaxGroups); *fresh2 = &mut *pGroups.offset(iNrActiveGroups as isize) as *mut SGroup; (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]) .iVertexRepresentitive = vert_index; @@ -753,7 +769,11 @@ unsafe fn Build4RuleGroups( let bDiff_0: bool = if bOrPre != bOrPre2_0 { true } else { false }; debug_assert!(bAnswer_0 || bDiff_0) } - iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces + iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces; + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + debug_assert!(iOffset <= iNrMaxGroups); } } } @@ -773,14 +793,15 @@ unsafe fn AssignRecur( let iVertRep: i32 = (*pGroup).iVertexRepresentitive; let mut pVerts: *const i32 = &*piTriListIn.offset((3i32 * iMyTriIndex + 0i32) as isize) as *const i32; - let mut i: i32 = -1i32; - if *pVerts.offset(0isize) == iVertRep { - i = 0i32 + let i = if *pVerts.offset(0isize) == iVertRep { + 0i32 } else if *pVerts.offset(1isize) == iVertRep { - i = 1i32 + 1i32 } else if *pVerts.offset(2isize) == iVertRep { - i = 2i32 - } + 2i32 + } else { + panic!(); + }; if (*pMyTriInfo).AssignedGroup[i as usize] == pGroup { return true; } else { @@ -1141,6 +1162,7 @@ unsafe fn DegenPrologue( let t0 = t; let t1 = iNextGoodTriangleSearchIndex; iNextGoodTriangleSearchIndex += 1; + debug_assert!(iNextGoodTriangleSearchIndex > (t + 1)); // Swap t0 and t1 if !bJustADegenerate { for i in 0..3i32 { @@ -1160,6 +1182,8 @@ unsafe fn DegenPrologue( t += 1 } } + debug_assert!(iNrTrianglesIn == t); + debug_assert!(bStillFindingGoodOnes); } unsafe fn GenerateSharedVerticesIndexList( // The input vertex index->face/vert mappings @@ -1365,29 +1389,35 @@ unsafe fn MergeVertsFast( } else { let mut iL: i32 = iL_in; let mut iR: i32 = iR_in; + debug_assert!(iR_in > iL_in); while iL < iR { let mut bReadyLeftSwap: bool = false; let mut bReadyRightSwap: bool = false; while !bReadyLeftSwap && iL < iR { + debug_assert!(iL >= iL_in && iL <= iR_in); bReadyLeftSwap = !((*pTmpVert.offset(iL as isize)).vert[channel as usize] < fSep); if !bReadyLeftSwap { iL += 1 } } while !bReadyRightSwap && iL < iR { + debug_assert!(iR >= iL_in && iR <= iR_in); bReadyRightSwap = (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; if !bReadyRightSwap { iR -= 1 } } + debug_assert!((iL < iR) || !(bReadyLeftSwap && bReadyRightSwap)); if bReadyLeftSwap && bReadyRightSwap { let sTmp: STmpVert = *pTmpVert.offset(iL as isize); + debug_assert!(iL < iR); *pTmpVert.offset(iL as isize) = *pTmpVert.offset(iR as isize); *pTmpVert.offset(iR as isize) = sTmp; iL += 1; iR -= 1 } } + debug_assert!(iL == (iR + 1) || (iL == iR)); if iL == iR { let bReadyRightSwap_0: bool = (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; @@ -1412,7 +1442,7 @@ const g_iCells: usize = 2048; // inlining could potentially reorder instructions and generate different // results for the same effective input value fVal. #[inline(never)] -unsafe fn FindGridCell(fMin: f32, fMax: f32, fVal: f32) -> usize { +fn FindGridCell(fMin: f32, fMax: f32, fVal: f32) -> usize { let fIndex = g_iCells as f32 * ((fVal - fMin) / (fMax - fMin)); let iIndex = fIndex as isize; return if iIndex < g_iCells as isize { @@ -1518,6 +1548,7 @@ unsafe fn GenerateInitialVerticesIndexList( } } iTSpacesOffs += verts.num_vertices(); + assert!(iDstTriIndex <= iNrTrianglesIn); } for t in 0..iNrTrianglesIn { diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index 835c9b3925ad3..20b2a9d108bde 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -96,5 +96,6 @@ fn index_to_face_vert(index: usize) -> (usize, usize) { } fn face_vert_to_index(face: usize, vert: usize) -> usize { + assert!(vert < 4); face << 2 | vert & 0x3 } From 85f04912bee2daeda196d447ae6e574f3967f10e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:16:32 +0100 Subject: [PATCH 23/44] Add some comments --- crates/bevy_mikktspace/src/generated.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 5a7553b679573..c415efa1dd6c0 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -178,8 +178,11 @@ impl SSubGroup { #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] pub struct SEdge { + // The first vertex's (global) index. This is the minimum index pub i0: i32, + // The second vertex's (global) index pub i1: i32, + // The face this edge is associated with pub f: i32, } From 93d4219a4b25bc91beb1d727f17f4e428bf01527 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 12 Jun 2022 11:51:43 +0100 Subject: [PATCH 24/44] Use a BTreeMap for duplicate detection --- crates/bevy_mikktspace/Cargo.toml | 1 + crates/bevy_mikktspace/src/generated.rs | 255 ++-------------------- crates/bevy_mikktspace/src/lib.rs | 1 + crates/bevy_mikktspace/src/ordered_vec.rs | 28 +++ 4 files changed, 52 insertions(+), 233 deletions(-) create mode 100644 crates/bevy_mikktspace/src/ordered_vec.rs diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index 0b0b8eddb4fc7..16cfc2c1ed688 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -19,6 +19,7 @@ glam = "0.20.0" bitflags = "1.3.2" # id-arena = "2.2.1" # smallvec = { version = "1.6", features = ["union"] } +ordered-float = "3.0.0" [[example]] name = "generate" diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index c415efa1dd6c0..f5abe28562ad5 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -46,12 +46,21 @@ unused_mut )] -use std::ptr::null_mut; +use std::{ + collections::{ + btree_map::Entry::{Occupied, Vacant}, + BTreeMap, + }, + ptr::null_mut, +}; use bitflags::bitflags; use glam::Vec3; -use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, FaceKind, Geometry}; +use crate::{ + face_vert_to_index, get_normal, get_position, get_tex_coord, ordered_vec::FiniteVec3, FaceKind, + Geometry, +}; #[derive(Copy, Clone)] pub struct STSpace { @@ -1200,245 +1209,25 @@ unsafe fn GenerateSharedVerticesIndexList( geometry: &impl Geometry, iNrTrianglesIn: usize, ) { - let mut vMin = get_position(geometry, 0); - let mut vMax = vMin; - + let mut map = BTreeMap::new(); for i in 0..(iNrTrianglesIn * 3) { let index: i32 = *piTriList_in_and_out.offset(i as isize); let vP = get_position(geometry, index as usize); - if vMin.x > vP.x { - vMin.x = vP.x - } else if vMax.x < vP.x { - vMax.x = vP.x - } - if vMin.y > vP.y { - vMin.y = vP.y - } else if vMax.y < vP.y { - vMax.y = vP.y - } - if vMin.z > vP.z { - vMin.z = vP.z - } else if vMax.z < vP.z { - vMax.z = vP.z - } - } - let vDim = vMax - vMin; - let iChannel; - let fMin; - let fMax; - if vDim.y > vDim.x && vDim.y > vDim.z { - iChannel = 1i32; - fMin = vMin.y; - fMax = vMax.y - } else if vDim.z > vDim.x { - iChannel = 2i32; - fMin = vMin.z; - fMax = vMax.z - } else { - iChannel = 0i32; - fMin = vMin.x; - fMax = vMax.x; - } - - let mut piHashTable = vec![0i32; iNrTrianglesIn * 3]; - let mut piHashOffsets = vec![0i32; g_iCells]; - let mut piHashCount = vec![0i32; g_iCells]; - let mut piHashCount2 = vec![0i32; g_iCells]; - - for i in 0..(iNrTrianglesIn * 3) { - let index_0: i32 = *piTriList_in_and_out.offset(i as isize); - let vP_0 = get_position(geometry, index_0 as usize); - let fVal: f32 = if iChannel == 0i32 { - vP_0.x - } else if iChannel == 1i32 { - vP_0.y - } else { - vP_0.z - }; - let iCell = FindGridCell(fMin, fMax, fVal); - piHashCount[iCell] += 1; - } - piHashOffsets[0] = 0i32; - - for k in 1..g_iCells { - piHashOffsets[k] = piHashOffsets[k - 1] + piHashCount[k - 1]; - } - for i in 0..(iNrTrianglesIn * 3) { - let index_1: i32 = *piTriList_in_and_out.offset(i as isize); - let vP_1 = get_position(geometry, index_1 as usize); - let fVal_0: f32 = if iChannel == 0i32 { - vP_1.x - } else if iChannel == 1i32 { - vP_1.y - } else { - vP_1.z - }; - let iCell_0 = FindGridCell(fMin, fMax, fVal_0); - let pTable = piHashTable - .as_mut_ptr() - .offset(piHashOffsets[iCell_0] as isize); - *pTable.offset(piHashCount2[iCell_0] as isize) = i as i32; - piHashCount2[iCell_0] += 1; - } - - debug_assert_eq!(piHashCount, piHashCount2); - drop(piHashCount2); - - let iMaxCount = piHashCount.iter().max().copied().unwrap() as usize; - - let mut pTmpVert = vec![STmpVert::zero(); iMaxCount]; - - for k in 0..g_iCells { - // extract table of cell k and amount of entries in it - let mut pTable_0 = &mut piHashTable[piHashOffsets[k] as usize] as *mut i32; - let iEntries = piHashCount[k] as usize; - if !(iEntries < 2) { - for e in 0..iEntries { - let mut i_0: i32 = *pTable_0.offset(e as isize); - let vP_2 = get_position( - geometry, - *piTriList_in_and_out.offset(i_0 as isize) as usize, - ); - pTmpVert[e].vert[0usize] = vP_2.x; - pTmpVert[e].vert[1usize] = vP_2.y; - pTmpVert[e].vert[2usize] = vP_2.z; - pTmpVert[e].index = i_0; + let vN = get_normal(geometry, index as usize); + let vT = get_tex_coord(geometry, index as usize); + let vP = FiniteVec3::new(vP).unwrap(); + let vN = FiniteVec3::new(vN).unwrap(); + let vT = FiniteVec3::new(vT).unwrap(); + + match map.entry((vP, vN, vT)) { + Vacant(entry) => { + entry.insert(index); } - MergeVertsFast( - piTriList_in_and_out, - pTmpVert.as_mut_ptr(), - geometry, - 0i32, - (iEntries - 1) as i32, - ); + Occupied(e) => *piTriList_in_and_out.offset(i as isize) = *e.get(), } } } -unsafe fn MergeVertsFast( - mut piTriList_in_and_out: *mut i32, - mut pTmpVert: *mut STmpVert, - geometry: &impl Geometry, - iL_in: i32, - iR_in: i32, -) { - // make bbox - let mut fvMin: [f32; 3] = [0.; 3]; - let mut fvMax: [f32; 3] = [0.; 3]; - - for c in 0..3i32 { - fvMin[c as usize] = (*pTmpVert.offset(iL_in as isize)).vert[c as usize]; - fvMax[c as usize] = fvMin[c as usize]; - } - - for l in (iL_in + 1i32)..=iR_in { - for c in 0..3i32 { - if fvMin[c as usize] > (*pTmpVert.offset(l as isize)).vert[c as usize] { - fvMin[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] - } else if fvMax[c as usize] < (*pTmpVert.offset(l as isize)).vert[c as usize] { - fvMax[c as usize] = (*pTmpVert.offset(l as isize)).vert[c as usize] - } - } - } - let dx = fvMax[0usize] - fvMin[0usize]; - let dy = fvMax[1usize] - fvMin[1usize]; - let dz = fvMax[2usize] - fvMin[2usize]; - let channel; - if dy > dx && dy > dz { - channel = 1i32 - } else if dz > dx { - channel = 2i32 - } else { - channel = 0i32 - } - let fSep = 0.5f32 * (fvMax[channel as usize] + fvMin[channel as usize]); - if fSep >= fvMax[channel as usize] || fSep <= fvMin[channel as usize] { - for l in iL_in..=iR_in { - let mut i: i32 = (*pTmpVert.offset(l as isize)).index; - let index: i32 = *piTriList_in_and_out.offset(i as isize); - let vP = get_position(geometry, index as usize); - let vN = get_normal(geometry, index as usize); - let vT = get_tex_coord(geometry, index as usize); - let mut bNotFound: bool = true; - let mut l2: i32 = iL_in; - let mut i2rec: i32 = -1i32; - while l2 < l && bNotFound { - let i2: i32 = (*pTmpVert.offset(l2 as isize)).index; - let index2: i32 = *piTriList_in_and_out.offset(i2 as isize); - let vP2 = get_position(geometry, index2 as usize); - let vN2 = get_normal(geometry, index2 as usize); - let vT2 = get_tex_coord(geometry, index2 as usize); - i2rec = i2; - if vP.x == vP2.x - && vP.y == vP2.y - && vP.z == vP2.z - && vN.x == vN2.x - && vN.y == vN2.y - && vN.z == vN2.z - && vT.x == vT2.x - && vT.y == vT2.y - && vT.z == vT2.z - { - bNotFound = false - } else { - l2 += 1 - } - } - if !bNotFound { - *piTriList_in_and_out.offset(i as isize) = - *piTriList_in_and_out.offset(i2rec as isize) - } - } - } else { - let mut iL: i32 = iL_in; - let mut iR: i32 = iR_in; - debug_assert!(iR_in > iL_in); - while iL < iR { - let mut bReadyLeftSwap: bool = false; - let mut bReadyRightSwap: bool = false; - while !bReadyLeftSwap && iL < iR { - debug_assert!(iL >= iL_in && iL <= iR_in); - bReadyLeftSwap = !((*pTmpVert.offset(iL as isize)).vert[channel as usize] < fSep); - if !bReadyLeftSwap { - iL += 1 - } - } - while !bReadyRightSwap && iL < iR { - debug_assert!(iR >= iL_in && iR <= iR_in); - bReadyRightSwap = (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; - if !bReadyRightSwap { - iR -= 1 - } - } - debug_assert!((iL < iR) || !(bReadyLeftSwap && bReadyRightSwap)); - if bReadyLeftSwap && bReadyRightSwap { - let sTmp: STmpVert = *pTmpVert.offset(iL as isize); - debug_assert!(iL < iR); - *pTmpVert.offset(iL as isize) = *pTmpVert.offset(iR as isize); - *pTmpVert.offset(iR as isize) = sTmp; - iL += 1; - iR -= 1 - } - } - debug_assert!(iL == (iR + 1) || (iL == iR)); - if iL == iR { - let bReadyRightSwap_0: bool = - (*pTmpVert.offset(iR as isize)).vert[channel as usize] < fSep; - if bReadyRightSwap_0 { - iL += 1 - } else { - iR -= 1 - } - } - if iL_in < iR { - MergeVertsFast(piTriList_in_and_out, pTmpVert, geometry, iL_in, iR); - } - if iL < iR_in { - MergeVertsFast(piTriList_in_and_out, pTmpVert, geometry, iL, iR_in); - } - }; -} - const g_iCells: usize = 2048; // it is IMPORTANT that this function is called to evaluate the hash since diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index 20b2a9d108bde..c665d60ed703c 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -3,6 +3,7 @@ use glam::{Vec2, Vec3}; mod generated; +pub(crate) mod ordered_vec; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FaceKind { diff --git a/crates/bevy_mikktspace/src/ordered_vec.rs b/crates/bevy_mikktspace/src/ordered_vec.rs new file mode 100644 index 0000000000000..54c4b5969e139 --- /dev/null +++ b/crates/bevy_mikktspace/src/ordered_vec.rs @@ -0,0 +1,28 @@ +use glam::Vec3; +use ordered_float::NotNan; + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct FiniteVec3 { + x: NotNan, + y: NotNan, + z: NotNan, +} + +impl FiniteVec3 { + pub fn new(val: Vec3) -> Result { + if val.is_finite() { + Ok(Self { + // Unwrapping here is fine, because is_finite guarantees that + // the values are not `Nan` + x: NotNan::new(val.x).unwrap(), + y: NotNan::new(val.y).unwrap(), + z: NotNan::new(val.z).unwrap(), + }) + } else { + Err(NotFinite) + } + } +} + +#[derive(Debug)] +pub struct NotFinite; From 8d9dc67d38062339e13d1db2dcfe25f96a4bcf38 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 12 Jun 2022 12:05:49 +0100 Subject: [PATCH 25/44] Comment for the unwrap --- crates/bevy_mikktspace/src/generated.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index f5abe28562ad5..186bb098959fe 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -1215,6 +1215,8 @@ unsafe fn GenerateSharedVerticesIndexList( let vP = get_position(geometry, index as usize); let vN = get_normal(geometry, index as usize); let vT = get_tex_coord(geometry, index as usize); + // Technically, these unwraps aren't ideal, but the original puts absolutely no thought into its handling of + // NaN and infinity, so it's probably *fine* let vP = FiniteVec3::new(vP).unwrap(); let vN = FiniteVec3::new(vN).unwrap(); let vT = FiniteVec3::new(vT).unwrap(); From 9541c81d7204387c9588b7337c03021f84a06642 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 12 Jun 2022 13:06:45 +0100 Subject: [PATCH 26/44] Add a `TriangleMap` --- crates/bevy_mikktspace/src/generated.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 186bb098959fe..527764173f604 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -64,7 +64,6 @@ use crate::{ #[derive(Copy, Clone)] pub struct STSpace { - // Normalised f pub vOs: Vec3, pub fMagS: f32, pub vOt: Vec3, @@ -223,6 +222,16 @@ impl STmpVert { } } +/// Stores a map of 'internal' triangle vertices to real 'faces' and vertices +/// This is used to deduplicate vertices with identical faces +struct TriangleMap { + /// Packed face/vertex index of each triangle + /// Note that this is an index to the first vertex + /// with the given properties, rather than necessarily + /// (Not impressed with this data layout) + triangles: Vec<[u32; 3]>, +} + pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { let iNrFaces = geometry.num_faces(); // TODO: Accept in radians by default here? From 3736c33b5c2b60c78348632f553df371f70ae194 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:11:23 +0100 Subject: [PATCH 27/44] Remove some unused code --- crates/bevy_mikktspace/src/generated.rs | 44 +++---------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 527764173f604..4741758d72930 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -130,7 +130,8 @@ pub struct STriInfo { pub iOrgFaceNumber: i32, pub iFlag: TriangleFlags, pub iTSpacesOffs: i32, - pub vert_num: [u8; 4], + // The vertices of the face 'iOrgFaceNumber' this triangle covers + pub vert_num: [u8; 3], } impl STriInfo { @@ -145,7 +146,7 @@ impl STriInfo { iOrgFaceNumber: 0, iFlag: TriangleFlags::empty(), iTSpacesOffs: 0, - vert_num: [0, 0, 0, 0], + vert_num: [0, 0, 0], } } } @@ -207,21 +208,6 @@ pub struct unnamed { pub f: i32, } -#[derive(Copy, Clone)] -pub struct STmpVert { - pub vert: [f32; 3], - pub index: i32, -} - -impl STmpVert { - fn zero() -> Self { - Self { - vert: [0.0, 0.0, 0.0], - index: 0, - } - } -} - /// Stores a map of 'internal' triangle vertices to real 'faces' and vertices /// This is used to deduplicate vertices with identical faces struct TriangleMap { @@ -288,7 +274,7 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) // C: Additionally, move all good triangles to the start of // C: pTriInfos[] and piTriListIn[] without changing order and // C: put the degenerate triangles last. - // Note: A quad can have degenerate traignles if two vertices are in the same location + // Note: A quad can have degenerate triangles if two vertices are in the same location DegenPrologue( pTriInfos.as_mut_ptr(), piTriListIn.as_mut_ptr(), @@ -632,7 +618,7 @@ fn VNotZero(v: Vec3) -> bool { } fn NotZero(fX: f32) -> bool { - fX.abs() > 1.17549435e-38f32 + fX.is_normal() } unsafe fn EvalTspace( @@ -1239,26 +1225,6 @@ unsafe fn GenerateSharedVerticesIndexList( } } -const g_iCells: usize = 2048; - -// it is IMPORTANT that this function is called to evaluate the hash since -// inlining could potentially reorder instructions and generate different -// results for the same effective input value fVal. -#[inline(never)] -fn FindGridCell(fMin: f32, fMax: f32, fVal: f32) -> usize { - let fIndex = g_iCells as f32 * ((fVal - fMin) / (fMax - fMin)); - let iIndex = fIndex as isize; - return if iIndex < g_iCells as isize { - if iIndex >= 0 { - iIndex as usize - } else { - 0 - } - } else { - g_iCells - 1 - }; -} - unsafe fn GenerateInitialVerticesIndexList( pTriInfos: &mut [STriInfo], piTriList_out: &mut [i32], From 4debf94aefc3c9233a1a27d65409beb3a718fc80 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:15:17 +0100 Subject: [PATCH 28/44] Replace if zero normalise with normalize_or_zero --- crates/bevy_mikktspace/src/generated.rs | 66 +++++++------------------ 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 4741758d72930..4a4475ce01d9e 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -489,12 +489,9 @@ unsafe fn GenerateTSpaces( - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); let mut vOt = (*pTriInfos.offset(f as isize)).vOt - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); - if VNotZero(vOs) { - vOs = vOs.normalize() - } - if VNotZero(vOt) { - vOt = vOt.normalize() - } + vOs = vOs.normalize_or_zero(); + vOt = vOt.normalize_or_zero(); + let iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; let mut iMembers = 0; @@ -505,12 +502,9 @@ unsafe fn GenerateTSpaces( - (n.dot((*pTriInfos.offset(t as isize)).vOs) * n); let mut vOt2 = (*pTriInfos.offset(t as isize)).vOt - (n.dot((*pTriInfos.offset(t as isize)).vOt) * n); - if VNotZero(vOs2) { - vOs2 = vOs2.normalize() - } - if VNotZero(vOt2) { - vOt2 = vOt2.normalize() - } + vOs2 = vOs2.normalize_or_zero(); + vOt2 = vOt2.normalize_or_zero(); + let bAny: bool = ((*pTriInfos.offset(f as isize)).iFlag | (*pTriInfos.offset(t as isize)).iFlag) .contains(TriangleFlags::GROUP_WITH_ANY); @@ -603,20 +597,12 @@ unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpa ts_res.fMagT = 0.5f32 * ((*pTS0).fMagT + (*pTS1).fMagT); ts_res.vOs = (*pTS0).vOs + (*pTS1).vOs; ts_res.vOt = (*pTS0).vOt + (*pTS1).vOt; - if VNotZero(ts_res.vOs) { - ts_res.vOs = ts_res.vOs.normalize(); - } - if VNotZero(ts_res.vOt) { - ts_res.vOt = ts_res.vOt.normalize(); - } + ts_res.vOs = ts_res.vOs.normalize_or_zero(); + ts_res.vOt = ts_res.vOt.normalize_or_zero(); } return ts_res; } -fn VNotZero(v: Vec3) -> bool { - NotZero(v.x) || NotZero(v.y) || NotZero(v.z) -} - fn NotZero(fX: f32) -> bool { fX.is_normal() } @@ -654,12 +640,9 @@ unsafe fn EvalTspace( - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); let mut vOt = (*pTriInfos.offset(f as isize)).vOt - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); - if VNotZero(vOs) { - vOs = vOs.normalize(); - } - if VNotZero(vOt) { - vOt = vOt.normalize() - } + vOs = vOs.normalize_or_zero(); + vOt = vOt.normalize_or_zero(); + let i2 = *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); let i1 = *piTriListIn.offset((3i32 * f + i) as isize); @@ -671,22 +654,12 @@ unsafe fn EvalTspace( let v1 = p0 - p1; let v2 = p2 - p1; let mut v1 = v1 - (n.dot(v1) * n); - if VNotZero(v1) { - v1 = v1.normalize() - } + v1 = v1.normalize_or_zero(); + let mut v2 = v2 - (n.dot(v2) * n); - if VNotZero(v2) { - v2 = v2.normalize() - } - let fCos = v1.dot(v2); + v2 = v2.normalize_or_zero(); + let fCos = v1.dot(v2).clamp(-1., 1.); - let fCos = if fCos > 1i32 as f32 { - 1i32 as f32 - } else if fCos < -1i32 as f32 { - -1i32 as f32 - } else { - fCos - }; let fAngle = (fCos as f64).acos() as f32; let fMagS = (*pTriInfos.offset(f as isize)).fMagS; let fMagT = (*pTriInfos.offset(f as isize)).fMagT; @@ -697,12 +670,9 @@ unsafe fn EvalTspace( fAngleSum += fAngle } } - if VNotZero(res.vOs) { - res.vOs = res.vOs.normalize() - } - if VNotZero(res.vOt) { - res.vOt = res.vOt.normalize() - } + res.vOs = res.vOs.normalize_or_zero(); + res.vOt = res.vOt.normalize_or_zero(); + if fAngleSum > 0i32 as f32 { res.fMagS /= fAngleSum; res.fMagT /= fAngleSum From 6e8b5e7ea6db661edb64838fa84361e17e9e276d Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:17:44 +0100 Subject: [PATCH 29/44] Inline `NotZero` --- crates/bevy_mikktspace/src/generated.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 4a4475ce01d9e..3772f67e2f44a 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -603,10 +603,6 @@ unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpa return ts_res; } -fn NotZero(fX: f32) -> bool { - fX.is_normal() -} - unsafe fn EvalTspace( mut face_indices: *mut i32, iFaces: i32, @@ -865,7 +861,7 @@ unsafe fn InitTriInfo( .iFlag .insert(TriangleFlags::ORIENT_PRESERVING); } - if NotZero(fSignedAreaSTx2) { + if fSignedAreaSTx2.is_normal() { let fAbsArea: f32 = fSignedAreaSTx2.abs(); let fLenOs: f32 = vOs.length(); let fLenOt: f32 = vOt.length(); @@ -877,16 +873,16 @@ unsafe fn InitTriInfo( } else { 1.0f32 }; - if NotZero(fLenOs) { + if fLenOs.is_normal() { (*pTriInfos.offset(f as isize)).vOs = (fS / fLenOs) * vOs } - if NotZero(fLenOt) { + if fLenOt.is_normal() { (*pTriInfos.offset(f as isize)).vOt = (fS / fLenOt) * vOt } (*pTriInfos.offset(f as isize)).fMagS = fLenOs / fAbsArea; (*pTriInfos.offset(f as isize)).fMagT = fLenOt / fAbsArea; - if NotZero((*pTriInfos.offset(f as isize)).fMagS) - && NotZero((*pTriInfos.offset(f as isize)).fMagT) + if ((*pTriInfos.offset(f as isize)).fMagS.is_normal()) + && (*pTriInfos.offset(f as isize)).fMagT.is_normal() { (*pTriInfos.offset(f as isize)) .iFlag From c49160f8df9cc580ff807abad6172dc7bb1422e6 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:44:13 +0100 Subject: [PATCH 30/44] Refactor `BuildNeighborsFast` --- crates/bevy_mikktspace/src/generated.rs | 89 ++++++++----------------- 1 file changed, 27 insertions(+), 62 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 3772f67e2f44a..2346f34e4d20e 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -218,6 +218,7 @@ struct TriangleMap { triangles: Vec<[u32; 3]>, } +// Entry point pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { let iNrFaces = geometry.num_faces(); // TODO: Accept in radians by default here? @@ -355,6 +356,7 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) return true; } + unsafe fn DegenEpilogue( mut psTspace: *mut STSpace, mut pTriInfos: *mut STriInfo, @@ -835,6 +837,7 @@ unsafe fn InitTriInfo( (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; + // C: assumed bad (*pTriInfos.offset(f as isize)) .iFlag .insert(TriangleFlags::GROUP_WITH_ANY); @@ -936,25 +939,26 @@ unsafe fn InitTriInfo( } } - let mut pEdges = vec![SEdge::zero(); iNrTrianglesIn * 3]; - BuildNeighborsFast(pTriInfos, &mut pEdges, piTriListIn, iNrTrianglesIn as i32); + BuildNeighborsFast(pTriInfos, piTriListIn, iNrTrianglesIn as i32); } unsafe fn BuildNeighborsFast( mut pTriInfos: *mut STriInfo, - mut pEdges: &mut [SEdge], mut piTriListIn: *const i32, iNrTrianglesIn: i32, ) { + let mut pEdges = Vec::with_capacity((iNrTrianglesIn * 3) as usize); // build array of edges for f in 0..iNrTrianglesIn { for i in 0..3i32 { let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let i1: i32 = - *piTriListIn.offset((f * 3i32 + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - pEdges[((f * 3i32 + i) as usize)].i0 = if i0 < i1 { i0 } else { i1 }; // put minimum index in i0 - (pEdges[(f * 3i32 + i) as usize]).i1 = if !(i0 < i1) { i0 } else { i1 }; // put maximum index in i1 - (pEdges[(f * 3i32 + i) as usize]).f = f; // record face number + let i1: i32 = *piTriListIn.offset((f * 3i32 + (i + 1) % 3) as isize); + // Ensure that the indices have a consistent order by making i0 the smaller + pEdges.push(SEdge { + i0: i0.min(i1), + i1: i0.max(i1), + f, + }); } } pEdges.sort(); @@ -967,84 +971,45 @@ unsafe fn BuildNeighborsFast( let i1_0: i32 = edge.i1; let f_0: i32 = edge.f; - let mut i0_A: i32 = 0; - let mut i1_A: i32 = 0; - let mut edgenum_A: i32 = 0; - let mut edgenum_B: i32 = 0i32; - GetEdge( - &mut i0_A, - &mut i1_A, - &mut edgenum_A, - &*piTriListIn.offset((f_0 * 3i32) as isize), - i0_0, - i1_0, - ); + let (i0_A, i1_A, edgenum_A) = + GetEdge(&*piTriListIn.offset((f_0 * 3i32) as isize), i0_0, i1_0); let bUnassigned_A = (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32; if bUnassigned_A { let mut j: i32 = i + 1i32; - let mut bNotFound: bool = true; - while j < iEntries - && i0_0 == pEdges[j as usize].i0 - && i1_0 == pEdges[j as usize].i1 - && bNotFound - { - let mut i0_B: i32 = 0; - let mut i1_B: i32 = 0; + while j < iEntries && i0_0 == pEdges[j as usize].i0 && i1_0 == pEdges[j as usize].i1 { let t = pEdges[j as usize].f; - GetEdge( - &mut i1_B, - &mut i0_B, - &mut edgenum_B, + // C: Flip i1 and i0 + let (i1_B, i0_B, edgenum_B) = GetEdge( &*piTriListIn.offset((t * 3i32) as isize), pEdges[j as usize].i0, pEdges[j as usize].i1, ); let bUnassigned_B = - if (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32 { - true - } else { - false - }; + (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32; if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { - bNotFound = false + let mut t_0: i32 = pEdges[j as usize].f; + (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; + (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0; + break; } else { j += 1 } } - if !bNotFound { - let mut t_0: i32 = pEdges[j as usize].f; - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; - (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0 - } } } } -unsafe fn GetEdge( - mut i0_out: *mut i32, - mut i1_out: *mut i32, - mut edgenum_out: *mut i32, - mut indices: *const i32, - i0_in: i32, - i1_in: i32, -) { - *edgenum_out = -1i32; +unsafe fn GetEdge(mut indices: *const i32, i0_in: i32, i1_in: i32) -> (i32, i32, i32) { if *indices.offset(0isize) == i0_in || *indices.offset(0isize) == i1_in { if *indices.offset(1isize) == i0_in || *indices.offset(1isize) == i1_in { - *edgenum_out.offset(0isize) = 0i32; - *i0_out.offset(0isize) = *indices.offset(0isize); - *i1_out.offset(0isize) = *indices.offset(1isize) + (*indices.offset(0isize), *indices.offset(1isize), 0) } else { - *edgenum_out.offset(0isize) = 2i32; - *i0_out.offset(0isize) = *indices.offset(2isize); - *i1_out.offset(0isize) = *indices.offset(0isize) + (*indices.offset(2isize), *indices.offset(0isize), 2) } } else { - *edgenum_out.offset(0isize) = 1i32; - *i0_out.offset(0isize) = *indices.offset(1isize); - *i1_out.offset(0isize) = *indices.offset(2isize) - }; + (*indices.offset(1isize), *indices.offset(2isize), 1) + } } // /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// From 4a5b4d211fa9a777a2ff06dbca87e1f7b51abc86 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 19 Jun 2022 16:20:14 +0100 Subject: [PATCH 31/44] Remove some unused code --- crates/bevy_mikktspace/src/generated.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 2346f34e4d20e..31084a9d60072 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -39,10 +39,8 @@ clippy::explicit_iter_loop, clippy::map_flatten, dead_code, - mutable_transmutes, non_camel_case_types, non_snake_case, - non_upper_case_globals, unused_mut )] @@ -195,19 +193,6 @@ pub struct SEdge { pub f: i32, } -impl SEdge { - fn zero() -> Self { - Self::default() - } -} - -#[derive(Copy, Clone)] -pub struct unnamed { - pub i0: i32, - pub i1: i32, - pub f: i32, -} - /// Stores a map of 'internal' triangle vertices to real 'faces' and vertices /// This is used to deduplicate vertices with identical faces struct TriangleMap { From 0d9cf5833587aa81b2bf1e47bc262a4bcbfcc3f6 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 19 Jun 2022 16:57:28 +0100 Subject: [PATCH 32/44] Fixup some comments --- crates/bevy_mikktspace/src/generated.rs | 36 ++++++++----------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 31084a9d60072..75fe9d640096d 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -83,34 +83,13 @@ impl STSpace { } } -// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the -// normal map sampler must use the exact inverse of the pixel shader transformation. -// The most efficient transformation we can possibly do in the pixel shader is -// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. -// pixel shader (fast transform out) -// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); -// where vNt is the tangent space normal. The normal map sampler must likewise use the -// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. -// sampler does (exact inverse of pixel shader): -// float3 row0 = cross(vB, vN); -// float3 row1 = cross(vN, vT); -// float3 row2 = cross(vT, vB); -// float fSign = dot(vT, row0)<0 ? -1 : 1; -// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); -// where vNout is the sampled normal in some chosen 3D space. -// -// Should you choose to reconstruct the bitangent in the pixel shader instead -// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. -// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of -// quads as your renderer then problems will occur since the interpolated tangent spaces will differ -// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before -// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. -// However, this must be used both by the sampler and your tools/rendering pipeline. -// internal structure - bitflags! { pub struct TriangleFlags: u8 { + /// This triangle has multiple vertices at the same point const DEGENERATE = 1; + /// This triangle is part of a quad where one (but not both) + /// of its triangles are degenerate (i.e. exactly two of the quad's + /// vertices are in the same location) const QUAD_ONE_DEGENERATE_TRI = 2; const GROUP_WITH_ANY = 4; const ORIENT_PRESERVING = 8; @@ -119,16 +98,23 @@ bitflags! { #[derive(Copy, Clone)] pub struct STriInfo { + /// Indices of neighbouring triangles across this triangle's edges pub FaceNeighbors: [i32; 3], + /// The group each vertex belongs to. TODO: Convert to index pub AssignedGroup: [*mut SGroup; 3], pub vOs: Vec3, pub vOt: Vec3, pub fMagS: f32, pub fMagT: f32, + /// The face in the user's module this triangle comes from pub iOrgFaceNumber: i32, + // Flags set for this triangle pub iFlag: TriangleFlags, pub iTSpacesOffs: i32, // The vertices of the face 'iOrgFaceNumber' this triangle covers + // This has only a limited set of valid values - as required for quads. + // - TODO: Convert to a repr(u8) enum to compress. + // In theory, this could be compressed in pub vert_num: [u8; 3], } From ce311758f1eb9772986347a491ce8df5b8d13794 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 19 Jun 2022 22:20:03 +0100 Subject: [PATCH 33/44] Remove an unused mut and unsafe --- crates/bevy_mikktspace/src/generated.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 75fe9d640096d..b4e40fefe6a28 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -1127,10 +1127,10 @@ unsafe fn GenerateSharedVerticesIndexList( } } -unsafe fn GenerateInitialVerticesIndexList( +fn GenerateInitialVerticesIndexList( pTriInfos: &mut [STriInfo], piTriList_out: &mut [i32], - geometry: &mut impl Geometry, + geometry: &impl Geometry, iNrTrianglesIn: usize, ) -> usize { let mut iTSpacesOffs: usize = 0; From cb8ca1b6a381e623aabcdb5e96cb8b664385cece Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:15:36 +0100 Subject: [PATCH 34/44] Refactor `GenerateSharedVerticesIndexList` --- crates/bevy_mikktspace/src/generated.rs | 47 ++++++++++--------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index b4e40fefe6a28..be547dc1c9ca9 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -44,13 +44,7 @@ unused_mut )] -use std::{ - collections::{ - btree_map::Entry::{Occupied, Vacant}, - BTreeMap, - }, - ptr::null_mut, -}; +use std::{collections::BTreeMap, ptr::null_mut}; use bitflags::bitflags; use glam::Vec3; @@ -114,7 +108,7 @@ pub struct STriInfo { // The vertices of the face 'iOrgFaceNumber' this triangle covers // This has only a limited set of valid values - as required for quads. // - TODO: Convert to a repr(u8) enum to compress. - // In theory, this could be compressed in + // In theory, this could be compressed inside TriangleFlags too. pub vert_num: [u8; 3], } @@ -191,10 +185,10 @@ struct TriangleMap { // Entry point pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { - let iNrFaces = geometry.num_faces(); // TODO: Accept in radians by default here? let fThresCos = (fAngularThreshold.to_radians()).cos(); + let iNrFaces = geometry.num_faces(); let mut iNrTrianglesIn = 0; for f in 0..iNrFaces { let verts = geometry.num_vertices_of_face(f); @@ -224,7 +218,8 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) iNrTrianglesIn, ); // C: Make a welded index list of identical positions and attributes (pos, norm, texc) - GenerateSharedVerticesIndexList(piTriListIn.as_mut_ptr(), geometry, iNrTrianglesIn); + GenerateSharedVerticesIndexList(&mut piTriListIn, geometry); + let iTotTris = iNrTrianglesIn; let mut iDegenTriangles = 0; // C: Mark all degenerate triangles @@ -1094,7 +1089,7 @@ unsafe fn DegenPrologue( debug_assert!(iNrTrianglesIn == t); debug_assert!(bStillFindingGoodOnes); } -unsafe fn GenerateSharedVerticesIndexList( +fn GenerateSharedVerticesIndexList( // The input vertex index->face/vert mappings // Identical face/verts will have each vertex index // point to the same (arbitrary?) face/vert @@ -1102,28 +1097,24 @@ unsafe fn GenerateSharedVerticesIndexList( // side channel seems much easier. // Hopefully implementation can be changed to just use a btreemap or // something too. - mut piTriList_in_and_out: *mut i32, + mut piTriList_in_and_out: &mut [i32], geometry: &impl Geometry, - iNrTrianglesIn: usize, ) { let mut map = BTreeMap::new(); - for i in 0..(iNrTrianglesIn * 3) { - let index: i32 = *piTriList_in_and_out.offset(i as isize); - let vP = get_position(geometry, index as usize); - let vN = get_normal(geometry, index as usize); - let vT = get_tex_coord(geometry, index as usize); + for vertex_index in piTriList_in_and_out { + let index = *vertex_index as usize; + let vertex_properties = [ + get_position(geometry, index), + get_normal(geometry, index), + get_tex_coord(geometry, index), + ] + // We need to make the vertex properties finite to be able to use them in a btreemap // Technically, these unwraps aren't ideal, but the original puts absolutely no thought into its handling of - // NaN and infinity, so it's probably *fine* - let vP = FiniteVec3::new(vP).unwrap(); - let vN = FiniteVec3::new(vN).unwrap(); - let vT = FiniteVec3::new(vT).unwrap(); + // NaN and infinity, so it's probably *fine*. (I strongly suspect that infinity or NaN would have + // lead to UB somewhere) + .map(|prop| FiniteVec3::new(prop).unwrap()); - match map.entry((vP, vN, vT)) { - Vacant(entry) => { - entry.insert(index); - } - Occupied(e) => *piTriList_in_and_out.offset(i as isize) = *e.get(), - } + *vertex_index = *(map.entry(vertex_properties).or_insert(*vertex_index)); } } From fb4f090fbc0e2c9e61dce08fe8c0ce31429e9bfb Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:22:01 +0100 Subject: [PATCH 35/44] Extract generating the index list into `setup` --- crates/bevy_mikktspace/src/generated.rs | 142 +---------------- crates/bevy_mikktspace/src/generated/setup.rs | 143 ++++++++++++++++++ 2 files changed, 149 insertions(+), 136 deletions(-) create mode 100644 crates/bevy_mikktspace/src/generated/setup.rs diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index be547dc1c9ca9..b87d4a183aa6f 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -44,15 +44,14 @@ unused_mut )] -use std::{collections::BTreeMap, ptr::null_mut}; +mod setup; + +use std::ptr::null_mut; use bitflags::bitflags; use glam::Vec3; -use crate::{ - face_vert_to_index, get_normal, get_position, get_tex_coord, ordered_vec::FiniteVec3, FaceKind, - Geometry, -}; +use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, FaceKind, Geometry}; #[derive(Copy, Clone)] pub struct STSpace { @@ -211,14 +210,14 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) // This also handles quads // TODO: Make this return triangle_info and tri_face_map // probably in a single structure. - let iNrTSPaces = GenerateInitialVerticesIndexList( + let iNrTSPaces = setup::GenerateInitialVerticesIndexList( &mut pTriInfos, &mut piTriListIn, geometry, iNrTrianglesIn, ); // C: Make a welded index list of identical positions and attributes (pos, norm, texc) - GenerateSharedVerticesIndexList(&mut piTriListIn, geometry); + setup::GenerateSharedVerticesIndexList(&mut piTriListIn, geometry); let iTotTris = iNrTrianglesIn; let mut iDegenTriangles = 0; @@ -1089,132 +1088,3 @@ unsafe fn DegenPrologue( debug_assert!(iNrTrianglesIn == t); debug_assert!(bStillFindingGoodOnes); } -fn GenerateSharedVerticesIndexList( - // The input vertex index->face/vert mappings - // Identical face/verts will have each vertex index - // point to the same (arbitrary?) face/vert - // TODO: This seems overly complicated - storing vertex properties in a - // side channel seems much easier. - // Hopefully implementation can be changed to just use a btreemap or - // something too. - mut piTriList_in_and_out: &mut [i32], - geometry: &impl Geometry, -) { - let mut map = BTreeMap::new(); - for vertex_index in piTriList_in_and_out { - let index = *vertex_index as usize; - let vertex_properties = [ - get_position(geometry, index), - get_normal(geometry, index), - get_tex_coord(geometry, index), - ] - // We need to make the vertex properties finite to be able to use them in a btreemap - // Technically, these unwraps aren't ideal, but the original puts absolutely no thought into its handling of - // NaN and infinity, so it's probably *fine*. (I strongly suspect that infinity or NaN would have - // lead to UB somewhere) - .map(|prop| FiniteVec3::new(prop).unwrap()); - - *vertex_index = *(map.entry(vertex_properties).or_insert(*vertex_index)); - } -} - -fn GenerateInitialVerticesIndexList( - pTriInfos: &mut [STriInfo], - piTriList_out: &mut [i32], - geometry: &impl Geometry, - iNrTrianglesIn: usize, -) -> usize { - let mut iTSpacesOffs: usize = 0; - let mut iDstTriIndex = 0; - for f in 0..geometry.num_faces() { - let verts = geometry.num_vertices_of_face(f); - - pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; - if let FaceKind::Triangle = verts { - let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts[0] = 0; - pVerts[1] = 1; - pVerts[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; - piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; - piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; - iDstTriIndex += 1 - } else { - pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; - pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; - let i0 = face_vert_to_index(f, 0); - let i1 = face_vert_to_index(f, 1); - let i2 = face_vert_to_index(f, 2); - let i3 = face_vert_to_index(f, 3); - let T0 = get_tex_coord(geometry, i0); - let T1 = get_tex_coord(geometry, i1); - let T2 = get_tex_coord(geometry, i2); - let T3 = get_tex_coord(geometry, i3); - let distSQ_02: f32 = (T2 - T0).length_squared(); - let distSQ_13: f32 = (T3 - T1).length_squared(); - let bQuadDiagIs_02: bool; - if distSQ_02 < distSQ_13 { - bQuadDiagIs_02 = true - } else if distSQ_13 < distSQ_02 { - bQuadDiagIs_02 = false - } else { - let P0 = get_position(geometry, i0); - let P1 = get_position(geometry, i1); - let P2 = get_position(geometry, i2); - let P3 = get_position(geometry, i3); - let distSQ_02_0: f32 = (P2 - P0).length_squared(); - let distSQ_13_0: f32 = (P3 - P1).length_squared(); - bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { - false - } else { - true - } - } - if bQuadDiagIs_02 { - let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A[0] = 0; - pVerts_A[1] = 1; - pVerts_A[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; - iDstTriIndex += 1; - - let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B[0] = 0; - pVerts_B[1] = 2; - pVerts_B[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } else { - let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_A_0[0] = 0; - pVerts_A_0[1] = 1; - pVerts_A_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1; - - let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; - pVerts_B_0[0] = 1; - pVerts_B_0[1] = 2; - pVerts_B_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; - piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; - piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 - } - } - iTSpacesOffs += verts.num_vertices(); - assert!(iDstTriIndex <= iNrTrianglesIn); - } - - for t in 0..iNrTrianglesIn { - pTriInfos[t].iFlag = TriangleFlags::empty(); - } - return iTSpacesOffs; -} diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs new file mode 100644 index 0000000000000..a19d808ef65fd --- /dev/null +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -0,0 +1,143 @@ +use super::STriInfo; +use super::TriangleFlags; + +use crate::face_vert_to_index; +use crate::ordered_vec::FiniteVec3; +use crate::FaceKind; + +use std::collections::BTreeMap; + +use crate::get_normal; +use crate::get_position; +use crate::get_tex_coord; +use crate::Geometry; + +pub(crate) fn GenerateSharedVerticesIndexList( + // The input vertex index->face/vert mappings + // Identical face/verts will have each vertex index + // point to the same (arbitrary?) face/vert + // TODO: This seems overly complicated - storing vertex properties in a + // side channel seems much easier. + // Hopefully implementation can be changed to just use a btreemap or + // something too. + mut piTriList_in_and_out: &mut [i32], + geometry: &impl Geometry, +) { + let mut map = BTreeMap::new(); + for vertex_index in piTriList_in_and_out { + let index = *vertex_index as usize; + let vertex_properties = [ + get_position(geometry, index), + get_normal(geometry, index), + get_tex_coord(geometry, index), + ] + // We need to make the vertex properties finite to be able to use them in a btreemap + // Technically, these unwraps aren't ideal, but the original puts absolutely no thought into its handling of + // NaN and infinity, so it's probably *fine*. (I strongly suspect that infinity or NaN would have + // lead to UB somewhere) + .map(|prop| FiniteVec3::new(prop).unwrap()); + + *vertex_index = *(map.entry(vertex_properties).or_insert(*vertex_index)); + } +} + +pub(crate) fn GenerateInitialVerticesIndexList( + pTriInfos: &mut [STriInfo], + piTriList_out: &mut [i32], + geometry: &impl Geometry, + iNrTrianglesIn: usize, +) -> usize { + let mut iTSpacesOffs: usize = 0; + let mut iDstTriIndex = 0; + for f in 0..geometry.num_faces() { + let verts = geometry.num_vertices_of_face(f); + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; + if let FaceKind::Triangle = verts { + let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts[0] = 0; + pVerts[1] = 1; + pVerts[2] = 2; + piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; + piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; + piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; + iDstTriIndex += 1 + } else { + pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; + pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; + let i0 = face_vert_to_index(f, 0); + let i1 = face_vert_to_index(f, 1); + let i2 = face_vert_to_index(f, 2); + let i3 = face_vert_to_index(f, 3); + let T0 = get_tex_coord(geometry, i0); + let T1 = get_tex_coord(geometry, i1); + let T2 = get_tex_coord(geometry, i2); + let T3 = get_tex_coord(geometry, i3); + let distSQ_02: f32 = (T2 - T0).length_squared(); + let distSQ_13: f32 = (T3 - T1).length_squared(); + let bQuadDiagIs_02: bool; + if distSQ_02 < distSQ_13 { + bQuadDiagIs_02 = true + } else if distSQ_13 < distSQ_02 { + bQuadDiagIs_02 = false + } else { + let P0 = get_position(geometry, i0); + let P1 = get_position(geometry, i1); + let P2 = get_position(geometry, i2); + let P3 = get_position(geometry, i3); + let distSQ_02_0: f32 = (P2 - P0).length_squared(); + let distSQ_13_0: f32 = (P3 - P1).length_squared(); + bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { + false + } else { + true + } + } + if bQuadDiagIs_02 { + let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_A[0] = 0; + pVerts_A[1] = 1; + pVerts_A[2] = 2; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; + iDstTriIndex += 1; + + let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_B[0] = 0; + pVerts_B[1] = 2; + pVerts_B[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1 + } else { + let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_A_0[0] = 0; + pVerts_A_0[1] = 1; + pVerts_A_0[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1; + + let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; + pVerts_B_0[0] = 1; + pVerts_B_0[1] = 2; + pVerts_B_0[2] = 3; + piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; + piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; + piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; + iDstTriIndex += 1 + } + } + iTSpacesOffs += verts.num_vertices(); + assert!(iDstTriIndex <= iNrTrianglesIn); + } + + for t in 0..iNrTrianglesIn { + pTriInfos[t].iFlag = TriangleFlags::empty(); + } + return iTSpacesOffs; +} From 5f4792bd81176945bca52df2779cb831b31ad47b Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:29:52 +0100 Subject: [PATCH 36/44] Extract further into modules --- crates/bevy_mikktspace/src/generated.rs | 395 +----------------- .../src/generated/degenerate.rs | 180 ++++++++ crates/bevy_mikktspace/src/generated/setup.rs | 213 ++++++++++ 3 files changed, 398 insertions(+), 390 deletions(-) create mode 100644 crates/bevy_mikktspace/src/generated/degenerate.rs diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index b87d4a183aa6f..d3f467a423f2a 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -44,6 +44,7 @@ unused_mut )] +mod degenerate; mod setup; use std::ptr::null_mut; @@ -51,7 +52,7 @@ use std::ptr::null_mut; use bitflags::bitflags; use glam::Vec3; -use crate::{face_vert_to_index, get_normal, get_position, get_tex_coord, FaceKind, Geometry}; +use crate::{get_normal, get_position, FaceKind, Geometry}; #[derive(Copy, Clone)] pub struct STSpace { @@ -241,14 +242,14 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) // C: pTriInfos[] and piTriListIn[] without changing order and // C: put the degenerate triangles last. // Note: A quad can have degenerate triangles if two vertices are in the same location - DegenPrologue( + degenerate::DegenPrologue( pTriInfos.as_mut_ptr(), piTriListIn.as_mut_ptr(), iNrTrianglesIn as i32, iTotTris as i32, ); // C: Evaluate triangle level attributes and neighbor list - InitTriInfo( + setup::InitTriInfo( pTriInfos.as_mut_ptr(), piTriListIn.as_ptr(), geometry, @@ -291,7 +292,7 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) if !bRes { return false; } - DegenEpilogue( + degenerate::DegenEpilogue( psTspace.as_mut_ptr(), pTriInfos.as_mut_ptr(), piTriListIn.as_mut_ptr(), @@ -322,87 +323,6 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) return true; } -unsafe fn DegenEpilogue( - mut psTspace: *mut STSpace, - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *mut i32, - geometry: &impl Geometry, - iNrTrianglesIn: i32, - iTotTris: i32, -) { - // For all degenerate triangles - for t in iNrTrianglesIn..iTotTris { - let bSkip: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); - if !bSkip { - for i in 0..3i32 { - // For all vertices on that triangle - let index1: i32 = *piTriListIn.offset((t * 3i32 + i) as isize); - for j in 0..(3i32 * iNrTrianglesIn) { - let index2: i32 = *piTriListIn.offset(j as isize); - // If the vertex properties are the same as another non-degenerate vertex - if index1 == index2 { - let iTri: i32 = j / 3i32; - let iVert: i32 = j % 3i32; - let iSrcVert: i32 = - (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; - let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; - let iDstVert: i32 = - (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; - let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - // Set the tangent space of this vertex to the tangent space of that vertex - // TODO: This is absurd - doing a linear search through all vertices for each - // degenerate triangle? - *psTspace.offset((iDstOffs + iDstVert) as isize) = - *psTspace.offset((iSrcOffs + iSrcVert) as isize); - break; - } - } - } - } - } - for t in 0..iNrTrianglesIn { - // Handle quads with a single degenerate triangle by - if (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) - { - let mut pV: *mut u8 = (*pTriInfos.offset(t as isize)).vert_num.as_mut_ptr(); - let mut iFlag: i32 = 1i32 << *pV.offset(0isize) as i32 - | 1i32 << *pV.offset(1isize) as i32 - | 1i32 << *pV.offset(2isize) as i32; - let mut iMissingIndex: i32 = 0i32; - if iFlag & 2i32 == 0i32 { - iMissingIndex = 1i32 - } else if iFlag & 4i32 == 0i32 { - iMissingIndex = 2i32 - } else if iFlag & 8i32 == 0i32 { - iMissingIndex = 3i32 - } - let iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let vDstP = get_position( - geometry, - face_vert_to_index(iOrgF as usize, iMissingIndex as usize), - ); - - for i_0 in 0..3i32 { - let iVert_0: i32 = *pV.offset(i_0 as isize) as i32; - let vSrcP = get_position( - geometry, - face_vert_to_index(iOrgF as usize, iVert_0 as usize), - ); - if vSrcP == vDstP { - let iOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - *psTspace.offset((iOffs + iMissingIndex) as isize) = - *psTspace.offset((iOffs + iVert_0) as isize); - break; - } - } - } - } -} - unsafe fn GenerateTSpaces( psTspace: &mut [STSpace], mut pTriInfos: *const STriInfo, @@ -783,308 +703,3 @@ unsafe fn AddTriToGroup(mut pGroup: *mut SGroup, iTriIndex: i32) { *(*pGroup).pFaceIndices.offset((*pGroup).iNrFaces as isize) = iTriIndex; (*pGroup).iNrFaces += 1; } -unsafe fn InitTriInfo( - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *const i32, - geometry: &impl Geometry, - iNrTrianglesIn: usize, -) { - for f in 0..iNrTrianglesIn { - for i in 0..3i32 { - (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize] = -1i32; - let ref mut fresh4 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; - *fresh4 = 0 as *mut SGroup; - (*pTriInfos.offset(f as isize)).vOs.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.z = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; - (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; - (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; - // C: assumed bad - (*pTriInfos.offset(f as isize)) - .iFlag - .insert(TriangleFlags::GROUP_WITH_ANY); - } - } - for f in 0..iNrTrianglesIn { - let v1 = get_position(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let v2 = get_position(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let v3 = get_position(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); - let t1 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let t2 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let t3 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); - let t21x: f32 = t2.x - t1.x; - let t21y: f32 = t2.y - t1.y; - let t31x: f32 = t3.x - t1.x; - let t31y: f32 = t3.y - t1.y; - let d1 = v2 - v1; - let d2 = v3 - v1; - let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - let mut vOs = (t31y * d1) - (t21y * d2); - let mut vOt = (-t31x * d1) + (t21x * d2); - if fSignedAreaSTx2 > 0.0 { - (*pTriInfos.offset(f as isize)) - .iFlag - .insert(TriangleFlags::ORIENT_PRESERVING); - } - if fSignedAreaSTx2.is_normal() { - let fAbsArea: f32 = fSignedAreaSTx2.abs(); - let fLenOs: f32 = vOs.length(); - let fLenOt: f32 = vOt.length(); - let fS: f32 = if !(*pTriInfos.offset(f as isize)) - .iFlag - .contains(TriangleFlags::ORIENT_PRESERVING) - { - -1.0f32 - } else { - 1.0f32 - }; - if fLenOs.is_normal() { - (*pTriInfos.offset(f as isize)).vOs = (fS / fLenOs) * vOs - } - if fLenOt.is_normal() { - (*pTriInfos.offset(f as isize)).vOt = (fS / fLenOt) * vOt - } - (*pTriInfos.offset(f as isize)).fMagS = fLenOs / fAbsArea; - (*pTriInfos.offset(f as isize)).fMagT = fLenOt / fAbsArea; - if ((*pTriInfos.offset(f as isize)).fMagS.is_normal()) - && (*pTriInfos.offset(f as isize)).fMagT.is_normal() - { - (*pTriInfos.offset(f as isize)) - .iFlag - .remove(TriangleFlags::GROUP_WITH_ANY); - } - } - } - let mut t = 0; - while t < iNrTrianglesIn - 1 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; - if iFO_a == iFO_b { - let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - let bIsDeg_b: bool = (*pTriInfos.offset((t + 1) as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - if !(bIsDeg_a || bIsDeg_b) { - let bOrientA: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::ORIENT_PRESERVING); - let bOrientB: bool = (*pTriInfos.offset((t + 1) as isize)) - .iFlag - .contains(TriangleFlags::ORIENT_PRESERVING); - if bOrientA != bOrientB { - let mut bChooseOrientFirstTri: bool = false; - if (*pTriInfos.offset((t + 1) as isize)) - .iFlag - .contains(TriangleFlags::GROUP_WITH_ANY) - { - bChooseOrientFirstTri = true - } else if CalcTexArea(geometry, &*piTriListIn.offset((t * 3 + 0) as isize)) - >= CalcTexArea(geometry, &*piTriListIn.offset(((t + 1) * 3 + 0) as isize)) - { - bChooseOrientFirstTri = true - } - let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; - let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; - (*pTriInfos.offset(t1_0 as isize)).iFlag.set( - TriangleFlags::ORIENT_PRESERVING, - (*pTriInfos.offset(t0 as isize)) - .iFlag - .contains(TriangleFlags::ORIENT_PRESERVING), - ); - } - } - t += 2 - } else { - t += 1 - } - } - - BuildNeighborsFast(pTriInfos, piTriListIn, iNrTrianglesIn as i32); -} - -unsafe fn BuildNeighborsFast( - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *const i32, - iNrTrianglesIn: i32, -) { - let mut pEdges = Vec::with_capacity((iNrTrianglesIn * 3) as usize); - // build array of edges - for f in 0..iNrTrianglesIn { - for i in 0..3i32 { - let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let i1: i32 = *piTriListIn.offset((f * 3i32 + (i + 1) % 3) as isize); - // Ensure that the indices have a consistent order by making i0 the smaller - pEdges.push(SEdge { - i0: i0.min(i1), - i1: i0.max(i1), - f, - }); - } - } - pEdges.sort(); - - let iEntries = iNrTrianglesIn * 3i32; - - for i in 0..iEntries { - let edge = pEdges[i as usize]; - let i0_0: i32 = edge.i0; - let i1_0: i32 = edge.i1; - let f_0: i32 = edge.f; - - let (i0_A, i1_A, edgenum_A) = - GetEdge(&*piTriListIn.offset((f_0 * 3i32) as isize), i0_0, i1_0); - let bUnassigned_A = - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32; - if bUnassigned_A { - let mut j: i32 = i + 1i32; - - while j < iEntries && i0_0 == pEdges[j as usize].i0 && i1_0 == pEdges[j as usize].i1 { - let t = pEdges[j as usize].f; - // C: Flip i1 and i0 - let (i1_B, i0_B, edgenum_B) = GetEdge( - &*piTriListIn.offset((t * 3i32) as isize), - pEdges[j as usize].i0, - pEdges[j as usize].i1, - ); - let bUnassigned_B = - (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32; - if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { - let mut t_0: i32 = pEdges[j as usize].f; - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; - (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0; - break; - } else { - j += 1 - } - } - } - } -} -unsafe fn GetEdge(mut indices: *const i32, i0_in: i32, i1_in: i32) -> (i32, i32, i32) { - if *indices.offset(0isize) == i0_in || *indices.offset(0isize) == i1_in { - if *indices.offset(1isize) == i0_in || *indices.offset(1isize) == i1_in { - (*indices.offset(0isize), *indices.offset(1isize), 0) - } else { - (*indices.offset(2isize), *indices.offset(0isize), 2) - } - } else { - (*indices.offset(1isize), *indices.offset(2isize), 1) - } -} -// /////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////// - -// returns the texture area times 2 -unsafe fn CalcTexArea(geometry: &impl Geometry, mut indices: *const i32) -> f32 { - let t1 = get_tex_coord(geometry, *indices.offset(0isize) as usize); - let t2 = get_tex_coord(geometry, *indices.offset(1isize) as usize); - let t3 = get_tex_coord(geometry, *indices.offset(2isize) as usize); - let t21x: f32 = t2.x - t1.x; - let t21y: f32 = t2.y - t1.y; - let t31x: f32 = t3.x - t1.x; - let t31y: f32 = t3.y - t1.y; - let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - return if fSignedAreaSTx2 < 0i32 as f32 { - -fSignedAreaSTx2 - } else { - fSignedAreaSTx2 - }; -} - -// degen triangles -unsafe fn DegenPrologue( - mut pTriInfos: *mut STriInfo, - mut piTriList_out: *mut i32, - iNrTrianglesIn: i32, - iTotTris: i32, -) { - // locate quads with only one good triangle - let mut t: i32 = 0i32; - while t < iTotTris - 1i32 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1i32) as isize)).iOrgFaceNumber; - if iFO_a == iFO_b { - let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - let bIsDeg_b: bool = (*pTriInfos.offset((t + 1i32) as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - // If exactly one is degenerate, mark both as QUAD_ONE_DEGENERATE_TRI, i.e. that the other triangle - // (If both are degenerate, this) - if bIsDeg_a ^ bIsDeg_b { - (*pTriInfos.offset(t as isize)) - .iFlag - .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); - (*pTriInfos.offset((t + 1i32) as isize)) - .iFlag - .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); - } - t += 2i32 - } else { - t += 1 - } - } - - // reorder list so all degen triangles are moved to the back - // without reordering the good triangles - // That is, a semi-stable partition, e.g. as described at - // https://dlang.org/library/std/algorithm/sorting/partition.html - // TODO: Use `Vec::retain` with a second vec here - not perfect, - // but good enough and safe. - // TODO: Consider using `sort_by_key` on Vec instead (which is stable) - it might be - // technically slower, but it's much easier to reason about - let mut iNextGoodTriangleSearchIndex = 1i32; - t = 0i32; - let mut bStillFindingGoodOnes = true; - while t < iNrTrianglesIn && bStillFindingGoodOnes { - let bIsGood: bool = !(*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - if bIsGood { - if iNextGoodTriangleSearchIndex < t + 2i32 { - iNextGoodTriangleSearchIndex = t + 2i32 - } - } else { - let mut bJustADegenerate: bool = true; - while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { - let bIsGood_0: bool = !(*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - if bIsGood_0 { - bJustADegenerate = false - } else { - iNextGoodTriangleSearchIndex += 1 - } - } - let t0 = t; - let t1 = iNextGoodTriangleSearchIndex; - iNextGoodTriangleSearchIndex += 1; - debug_assert!(iNextGoodTriangleSearchIndex > (t + 1)); - // Swap t0 and t1 - if !bJustADegenerate { - for i in 0..3i32 { - let index: i32 = *piTriList_out.offset((t0 * 3i32 + i) as isize); - *piTriList_out.offset((t0 * 3i32 + i) as isize) = - *piTriList_out.offset((t1 * 3i32 + i) as isize); - *piTriList_out.offset((t1 * 3i32 + i) as isize) = index; - } - let tri_info: STriInfo = *pTriInfos.offset(t0 as isize); - *pTriInfos.offset(t0 as isize) = *pTriInfos.offset(t1 as isize); - *pTriInfos.offset(t1 as isize) = tri_info - } else { - bStillFindingGoodOnes = false - } - } - if bStillFindingGoodOnes { - t += 1 - } - } - debug_assert!(iNrTrianglesIn == t); - debug_assert!(bStillFindingGoodOnes); -} diff --git a/crates/bevy_mikktspace/src/generated/degenerate.rs b/crates/bevy_mikktspace/src/generated/degenerate.rs new file mode 100644 index 0000000000000..59e343d17205c --- /dev/null +++ b/crates/bevy_mikktspace/src/generated/degenerate.rs @@ -0,0 +1,180 @@ +use crate::face_vert_to_index; +use crate::get_position; +use crate::Geometry; + +use super::STSpace; +use super::STriInfo; +use super::TriangleFlags; + +pub(crate) unsafe fn DegenPrologue( + mut pTriInfos: *mut STriInfo, + mut piTriList_out: *mut i32, + iNrTrianglesIn: i32, + iTotTris: i32, +) { + // locate quads with only one good triangle + let mut t: i32 = 0i32; + while t < iTotTris - 1i32 { + let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; + let iFO_b: i32 = (*pTriInfos.offset((t + 1i32) as isize)).iOrgFaceNumber; + if iFO_a == iFO_b { + let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = (*pTriInfos.offset((t + 1i32) as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + // If exactly one is degenerate, mark both as QUAD_ONE_DEGENERATE_TRI, i.e. that the other triangle + // (If both are degenerate, this) + if bIsDeg_a ^ bIsDeg_b { + (*pTriInfos.offset(t as isize)) + .iFlag + .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + (*pTriInfos.offset((t + 1i32) as isize)) + .iFlag + .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + } + t += 2i32 + } else { + t += 1 + } + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + // That is, a semi-stable partition, e.g. as described at + // https://dlang.org/library/std/algorithm/sorting/partition.html + // TODO: Use `Vec::retain` with a second vec here - not perfect, + // but good enough and safe. + // TODO: Consider using `sort_by_key` on Vec instead (which is stable) - it might be + // technically slower, but it's much easier to reason about + let mut iNextGoodTriangleSearchIndex = 1i32; + t = 0i32; + let mut bStillFindingGoodOnes = true; + while t < iNrTrianglesIn && bStillFindingGoodOnes { + let bIsGood: bool = !(*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + if bIsGood { + if iNextGoodTriangleSearchIndex < t + 2i32 { + iNextGoodTriangleSearchIndex = t + 2i32 + } + } else { + let mut bJustADegenerate: bool = true; + while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { + let bIsGood_0: bool = !(*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + if bIsGood_0 { + bJustADegenerate = false + } else { + iNextGoodTriangleSearchIndex += 1 + } + } + let t0 = t; + let t1 = iNextGoodTriangleSearchIndex; + iNextGoodTriangleSearchIndex += 1; + debug_assert!(iNextGoodTriangleSearchIndex > (t + 1)); + // Swap t0 and t1 + if !bJustADegenerate { + for i in 0..3i32 { + let index: i32 = *piTriList_out.offset((t0 * 3i32 + i) as isize); + *piTriList_out.offset((t0 * 3i32 + i) as isize) = + *piTriList_out.offset((t1 * 3i32 + i) as isize); + *piTriList_out.offset((t1 * 3i32 + i) as isize) = index; + } + let tri_info: STriInfo = *pTriInfos.offset(t0 as isize); + *pTriInfos.offset(t0 as isize) = *pTriInfos.offset(t1 as isize); + *pTriInfos.offset(t1 as isize) = tri_info + } else { + bStillFindingGoodOnes = false + } + } + if bStillFindingGoodOnes { + t += 1 + } + } + debug_assert!(iNrTrianglesIn == t); + debug_assert!(bStillFindingGoodOnes); +} + +pub(crate) unsafe fn DegenEpilogue( + mut psTspace: *mut STSpace, + mut pTriInfos: *mut STriInfo, + mut piTriListIn: *mut i32, + geometry: &impl Geometry, + iNrTrianglesIn: i32, + iTotTris: i32, +) { + // For all degenerate triangles + for t in iNrTrianglesIn..iTotTris { + let bSkip: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + if !bSkip { + for i in 0..3i32 { + // For all vertices on that triangle + let index1: i32 = *piTriListIn.offset((t * 3i32 + i) as isize); + for j in 0..(3i32 * iNrTrianglesIn) { + let index2: i32 = *piTriListIn.offset(j as isize); + // If the vertex properties are the same as another non-degenerate vertex + if index1 == index2 { + let iTri: i32 = j / 3i32; + let iVert: i32 = j % 3i32; + let iSrcVert: i32 = + (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; + let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; + let iDstVert: i32 = + (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; + let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; + // Set the tangent space of this vertex to the tangent space of that vertex + // TODO: This is absurd - doing a linear search through all vertices for each + // degenerate triangle? + *psTspace.offset((iDstOffs + iDstVert) as isize) = + *psTspace.offset((iSrcOffs + iSrcVert) as isize); + break; + } + } + } + } + } + for t in 0..iNrTrianglesIn { + // Handle quads with a single degenerate triangle by + if (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) + { + let mut pV: *mut u8 = (*pTriInfos.offset(t as isize)).vert_num.as_mut_ptr(); + let mut iFlag: i32 = 1i32 << *pV.offset(0isize) as i32 + | 1i32 << *pV.offset(1isize) as i32 + | 1i32 << *pV.offset(2isize) as i32; + let mut iMissingIndex: i32 = 0i32; + if iFlag & 2i32 == 0i32 { + iMissingIndex = 1i32 + } else if iFlag & 4i32 == 0i32 { + iMissingIndex = 2i32 + } else if iFlag & 8i32 == 0i32 { + iMissingIndex = 3i32 + } + let iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; + let vDstP = get_position( + geometry, + face_vert_to_index(iOrgF as usize, iMissingIndex as usize), + ); + + for i_0 in 0..3i32 { + let iVert_0: i32 = *pV.offset(i_0 as isize) as i32; + let vSrcP = get_position( + geometry, + face_vert_to_index(iOrgF as usize, iVert_0 as usize), + ); + if vSrcP == vDstP { + let iOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; + *psTspace.offset((iOffs + iMissingIndex) as isize) = + *psTspace.offset((iOffs + iVert_0) as isize); + break; + } + } + } + } +} diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs index a19d808ef65fd..4d7109466a656 100644 --- a/crates/bevy_mikktspace/src/generated/setup.rs +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -1,3 +1,5 @@ +use super::SEdge; +use super::SGroup; use super::STriInfo; use super::TriangleFlags; @@ -141,3 +143,214 @@ pub(crate) fn GenerateInitialVerticesIndexList( } return iTSpacesOffs; } + +pub(crate) unsafe fn InitTriInfo( + mut pTriInfos: *mut STriInfo, + mut piTriListIn: *const i32, + geometry: &impl Geometry, + iNrTrianglesIn: usize, +) { + for f in 0..iNrTrianglesIn { + for i in 0..3i32 { + (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize] = -1i32; + let ref mut fresh4 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; + *fresh4 = 0 as *mut SGroup; + (*pTriInfos.offset(f as isize)).vOs.x = 0.0f32; + (*pTriInfos.offset(f as isize)).vOs.y = 0.0f32; + (*pTriInfos.offset(f as isize)).vOs.z = 0.0f32; + (*pTriInfos.offset(f as isize)).vOt.x = 0.0f32; + (*pTriInfos.offset(f as isize)).vOt.y = 0.0f32; + (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; + (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; + (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; + // C: assumed bad + (*pTriInfos.offset(f as isize)) + .iFlag + .insert(TriangleFlags::GROUP_WITH_ANY); + } + } + for f in 0..iNrTrianglesIn { + let v1 = get_position(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); + let v2 = get_position(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); + let v3 = get_position(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); + let t1 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); + let t2 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); + let t3 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); + let t21x: f32 = t2.x - t1.x; + let t21y: f32 = t2.y - t1.y; + let t31x: f32 = t3.x - t1.x; + let t31y: f32 = t3.y - t1.y; + let d1 = v2 - v1; + let d2 = v3 - v1; + let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; + let mut vOs = (t31y * d1) - (t21y * d2); + let mut vOt = (-t31x * d1) + (t21x * d2); + if fSignedAreaSTx2 > 0.0 { + (*pTriInfos.offset(f as isize)) + .iFlag + .insert(TriangleFlags::ORIENT_PRESERVING); + } + if fSignedAreaSTx2.is_normal() { + let fAbsArea: f32 = fSignedAreaSTx2.abs(); + let fLenOs: f32 = vOs.length(); + let fLenOt: f32 = vOt.length(); + let fS: f32 = if !(*pTriInfos.offset(f as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING) + { + -1.0f32 + } else { + 1.0f32 + }; + if fLenOs.is_normal() { + (*pTriInfos.offset(f as isize)).vOs = (fS / fLenOs) * vOs + } + if fLenOt.is_normal() { + (*pTriInfos.offset(f as isize)).vOt = (fS / fLenOt) * vOt + } + (*pTriInfos.offset(f as isize)).fMagS = fLenOs / fAbsArea; + (*pTriInfos.offset(f as isize)).fMagT = fLenOt / fAbsArea; + if ((*pTriInfos.offset(f as isize)).fMagS.is_normal()) + && (*pTriInfos.offset(f as isize)).fMagT.is_normal() + { + (*pTriInfos.offset(f as isize)) + .iFlag + .remove(TriangleFlags::GROUP_WITH_ANY); + } + } + } + let mut t = 0; + while t < iNrTrianglesIn - 1 { + let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; + let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; + if iFO_a == iFO_b { + let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::DEGENERATE); + if !(bIsDeg_a || bIsDeg_b) { + let bOrientA: bool = (*pTriInfos.offset(t as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); + let bOrientB: bool = (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); + if bOrientA != bOrientB { + let mut bChooseOrientFirstTri: bool = false; + if (*pTriInfos.offset((t + 1) as isize)) + .iFlag + .contains(TriangleFlags::GROUP_WITH_ANY) + { + bChooseOrientFirstTri = true + } else if CalcTexArea(geometry, &*piTriListIn.offset((t * 3 + 0) as isize)) + >= CalcTexArea(geometry, &*piTriListIn.offset(((t + 1) * 3 + 0) as isize)) + { + bChooseOrientFirstTri = true + } + let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; + let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; + (*pTriInfos.offset(t1_0 as isize)).iFlag.set( + TriangleFlags::ORIENT_PRESERVING, + (*pTriInfos.offset(t0 as isize)) + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING), + ); + } + } + t += 2 + } else { + t += 1 + } + } + + BuildNeighborsFast(pTriInfos, piTriListIn, iNrTrianglesIn as i32); +} + +pub(crate) unsafe fn BuildNeighborsFast( + mut pTriInfos: *mut STriInfo, + mut piTriListIn: *const i32, + iNrTrianglesIn: i32, +) { + let mut pEdges = Vec::with_capacity((iNrTrianglesIn * 3) as usize); + // build array of edges + for f in 0..iNrTrianglesIn { + for i in 0..3i32 { + let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); + let i1: i32 = *piTriListIn.offset((f * 3i32 + (i + 1) % 3) as isize); + // Ensure that the indices have a consistent order by making i0 the smaller + pEdges.push(SEdge { + i0: i0.min(i1), + i1: i0.max(i1), + f, + }); + } + } + pEdges.sort(); + + let iEntries = iNrTrianglesIn * 3i32; + + for i in 0..iEntries { + let edge = pEdges[i as usize]; + let i0_0: i32 = edge.i0; + let i1_0: i32 = edge.i1; + let f_0: i32 = edge.f; + + let (i0_A, i1_A, edgenum_A) = + GetEdge(&*piTriListIn.offset((f_0 * 3i32) as isize), i0_0, i1_0); + let bUnassigned_A = + (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32; + if bUnassigned_A { + let mut j: i32 = i + 1i32; + + while j < iEntries && i0_0 == pEdges[j as usize].i0 && i1_0 == pEdges[j as usize].i1 { + let t = pEdges[j as usize].f; + // C: Flip i1 and i0 + let (i1_B, i0_B, edgenum_B) = GetEdge( + &*piTriListIn.offset((t * 3i32) as isize), + pEdges[j as usize].i0, + pEdges[j as usize].i1, + ); + let bUnassigned_B = + (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32; + if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { + let mut t_0: i32 = pEdges[j as usize].f; + (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; + (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0; + break; + } else { + j += 1 + } + } + } + } +} + +pub(crate) unsafe fn GetEdge(mut indices: *const i32, i0_in: i32, i1_in: i32) -> (i32, i32, i32) { + if *indices.offset(0isize) == i0_in || *indices.offset(0isize) == i1_in { + if *indices.offset(1isize) == i0_in || *indices.offset(1isize) == i1_in { + (*indices.offset(0isize), *indices.offset(1isize), 0) + } else { + (*indices.offset(2isize), *indices.offset(0isize), 2) + } + } else { + (*indices.offset(1isize), *indices.offset(2isize), 1) + } +} +// returns the texture area times 2 +unsafe fn CalcTexArea(geometry: &impl Geometry, mut indices: *const i32) -> f32 { + let t1 = get_tex_coord(geometry, *indices.offset(0isize) as usize); + let t2 = get_tex_coord(geometry, *indices.offset(1isize) as usize); + let t3 = get_tex_coord(geometry, *indices.offset(2isize) as usize); + let t21x: f32 = t2.x - t1.x; + let t21y: f32 = t2.y - t1.y; + let t31x: f32 = t3.x - t1.x; + let t31y: f32 = t3.y - t1.y; + let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; + return if fSignedAreaSTx2 < 0i32 as f32 { + -fSignedAreaSTx2 + } else { + fSignedAreaSTx2 + }; +} From fad05be423e63fc7f4ade61946aac8563511aa0e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:32:41 +0100 Subject: [PATCH 37/44] Tidy up the output code --- crates/bevy_mikktspace/src/generated.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index d3f467a423f2a..e9c20e7818ded 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -300,18 +300,18 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) iNrTrianglesIn as i32, iTotTris as i32, ); + + // Output generated triangles let mut index = 0; for f in 0..iNrFaces { let verts_0 = geometry.num_vertices_of_face(f); for i in 0..verts_0.num_vertices() { - let mut pTSpace: *const STSpace = &mut psTspace[index] as *mut STSpace; - let mut tang = Vec3::new((*pTSpace).vOs.x, (*pTSpace).vOs.y, (*pTSpace).vOs.z); - let mut bitang = Vec3::new((*pTSpace).vOt.x, (*pTSpace).vOt.y, (*pTSpace).vOt.z); + let mut pTSpace = &psTspace[index]; geometry.set_tangent( - tang.into(), - bitang.into(), - (*pTSpace).fMagS, - (*pTSpace).fMagT, + pTSpace.vOs.into(), + pTSpace.vOt.into(), + pTSpace.fMagS, + pTSpace.fMagT, (*pTSpace).bOrient, f, i, From 32295ec7d05e5bcfd6237f5d52322d18185cc86f Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 21 Jun 2022 12:53:35 +0100 Subject: [PATCH 38/44] Refactor `setup` to not use any unsafety --- crates/bevy_mikktspace/src/generated.rs | 9 +- crates/bevy_mikktspace/src/generated/setup.rs | 138 +++++++----------- 2 files changed, 58 insertions(+), 89 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index e9c20e7818ded..f53812f667908 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -115,7 +115,7 @@ pub struct STriInfo { impl STriInfo { fn zero() -> Self { Self { - FaceNeighbors: [0, 0, 0], + FaceNeighbors: [-1, -1, -1], AssignedGroup: [null_mut(), null_mut(), null_mut()], vOs: Default::default(), vOt: Default::default(), @@ -249,12 +249,7 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) iTotTris as i32, ); // C: Evaluate triangle level attributes and neighbor list - setup::InitTriInfo( - pTriInfos.as_mut_ptr(), - piTriListIn.as_ptr(), - geometry, - iNrTrianglesIn, - ); + setup::InitTriInfo(&mut pTriInfos, &piTriListIn, geometry, iNrTrianglesIn); //C: Based on the 4 rules, identify groups based on connectivity let iNrMaxGroups = iNrTrianglesIn * 3; diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs index 4d7109466a656..e072924ba4a91 100644 --- a/crates/bevy_mikktspace/src/generated/setup.rs +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -1,5 +1,4 @@ use super::SEdge; -use super::SGroup; use super::STriInfo; use super::TriangleFlags; @@ -144,38 +143,24 @@ pub(crate) fn GenerateInitialVerticesIndexList( return iTSpacesOffs; } -pub(crate) unsafe fn InitTriInfo( - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *const i32, +pub(crate) fn InitTriInfo( + mut pTriInfos: &mut [STriInfo], + mut piTriListIn: &[i32], geometry: &impl Geometry, iNrTrianglesIn: usize, ) { for f in 0..iNrTrianglesIn { - for i in 0..3i32 { - (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize] = -1i32; - let ref mut fresh4 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; - *fresh4 = 0 as *mut SGroup; - (*pTriInfos.offset(f as isize)).vOs.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOs.z = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.x = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.y = 0.0f32; - (*pTriInfos.offset(f as isize)).vOt.z = 0.0f32; - (*pTriInfos.offset(f as isize)).fMagS = 0i32 as f32; - (*pTriInfos.offset(f as isize)).fMagT = 0i32 as f32; - // C: assumed bad - (*pTriInfos.offset(f as isize)) - .iFlag - .insert(TriangleFlags::GROUP_WITH_ANY); - } + // C: assumed bad + pTriInfos[f].iFlag.insert(TriangleFlags::GROUP_WITH_ANY); } + for f in 0..iNrTrianglesIn { - let v1 = get_position(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let v2 = get_position(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let v3 = get_position(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); - let t1 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 0) as isize) as usize); - let t2 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 1) as isize) as usize); - let t3 = get_tex_coord(geometry, *piTriListIn.offset((f * 3 + 2) as isize) as usize); + let v1 = get_position(geometry, piTriListIn[(f * 3 + 0)] as usize); + let v2 = get_position(geometry, piTriListIn[f * 3 + 1] as usize); + let v3 = get_position(geometry, piTriListIn[f * 3 + 2] as usize); + let t1 = get_tex_coord(geometry, piTriListIn[f * 3 + 0] as usize); + let t2 = get_tex_coord(geometry, piTriListIn[f * 3 + 1] as usize); + let t3 = get_tex_coord(geometry, piTriListIn[f * 3 + 2] as usize); let t21x: f32 = t2.x - t1.x; let t21y: f32 = t2.y - t1.y; let t31x: f32 = t3.x - t1.x; @@ -186,15 +171,13 @@ pub(crate) unsafe fn InitTriInfo( let mut vOs = (t31y * d1) - (t21y * d2); let mut vOt = (-t31x * d1) + (t21x * d2); if fSignedAreaSTx2 > 0.0 { - (*pTriInfos.offset(f as isize)) - .iFlag - .insert(TriangleFlags::ORIENT_PRESERVING); + pTriInfos[f].iFlag.insert(TriangleFlags::ORIENT_PRESERVING); } if fSignedAreaSTx2.is_normal() { let fAbsArea: f32 = fSignedAreaSTx2.abs(); let fLenOs: f32 = vOs.length(); let fLenOt: f32 = vOt.length(); - let fS: f32 = if !(*pTriInfos.offset(f as isize)) + let fS: f32 = if !pTriInfos[f] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING) { @@ -203,57 +186,49 @@ pub(crate) unsafe fn InitTriInfo( 1.0f32 }; if fLenOs.is_normal() { - (*pTriInfos.offset(f as isize)).vOs = (fS / fLenOs) * vOs + pTriInfos[f].vOs = (fS / fLenOs) * vOs } if fLenOt.is_normal() { - (*pTriInfos.offset(f as isize)).vOt = (fS / fLenOt) * vOt + pTriInfos[f].vOt = (fS / fLenOt) * vOt } - (*pTriInfos.offset(f as isize)).fMagS = fLenOs / fAbsArea; - (*pTriInfos.offset(f as isize)).fMagT = fLenOt / fAbsArea; - if ((*pTriInfos.offset(f as isize)).fMagS.is_normal()) - && (*pTriInfos.offset(f as isize)).fMagT.is_normal() - { - (*pTriInfos.offset(f as isize)) - .iFlag - .remove(TriangleFlags::GROUP_WITH_ANY); + pTriInfos[f].fMagS = fLenOs / fAbsArea; + pTriInfos[f].fMagT = fLenOt / fAbsArea; + if (pTriInfos[f].fMagS.is_normal()) && (pTriInfos[f].fMagT.is_normal()) { + pTriInfos[f].iFlag.remove(TriangleFlags::GROUP_WITH_ANY); } } } let mut t = 0; while t < iNrTrianglesIn - 1 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1) as isize)).iOrgFaceNumber; + let iFO_a: i32 = pTriInfos[t].iOrgFaceNumber; + let iFO_b: i32 = pTriInfos[t + 1].iOrgFaceNumber; if iFO_a == iFO_b { - let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - let bIsDeg_b: bool = (*pTriInfos.offset((t + 1) as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); + let bIsDeg_a: bool = pTriInfos[t].iFlag.contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = pTriInfos[(t + 1)].iFlag.contains(TriangleFlags::DEGENERATE); if !(bIsDeg_a || bIsDeg_b) { - let bOrientA: bool = (*pTriInfos.offset(t as isize)) + let bOrientA: bool = pTriInfos[t] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - let bOrientB: bool = (*pTriInfos.offset((t + 1) as isize)) + let bOrientB: bool = pTriInfos[t + 1] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); if bOrientA != bOrientB { let mut bChooseOrientFirstTri: bool = false; - if (*pTriInfos.offset((t + 1) as isize)) + if pTriInfos[t + 1] .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { bChooseOrientFirstTri = true - } else if CalcTexArea(geometry, &*piTriListIn.offset((t * 3 + 0) as isize)) - >= CalcTexArea(geometry, &*piTriListIn.offset(((t + 1) * 3 + 0) as isize)) + } else if CalcTexArea(geometry, &piTriListIn[(t * 3)..]) + >= CalcTexArea(geometry, &piTriListIn[((t + 1) * 3)..]) { bChooseOrientFirstTri = true } let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; - (*pTriInfos.offset(t1_0 as isize)).iFlag.set( + pTriInfos[t1_0].iFlag.set( TriangleFlags::ORIENT_PRESERVING, - (*pTriInfos.offset(t0 as isize)) + pTriInfos[t0] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING), ); @@ -268,17 +243,17 @@ pub(crate) unsafe fn InitTriInfo( BuildNeighborsFast(pTriInfos, piTriListIn, iNrTrianglesIn as i32); } -pub(crate) unsafe fn BuildNeighborsFast( - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *const i32, +pub(crate) fn BuildNeighborsFast( + mut pTriInfos: &mut [STriInfo], + mut piTriListIn: &[i32], iNrTrianglesIn: i32, ) { let mut pEdges = Vec::with_capacity((iNrTrianglesIn * 3) as usize); // build array of edges for f in 0..iNrTrianglesIn { for i in 0..3i32 { - let i0: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let i1: i32 = *piTriListIn.offset((f * 3i32 + (i + 1) % 3) as isize); + let i0: i32 = piTriListIn[(f * 3 + i) as usize]; + let i1: i32 = piTriListIn[(f * 3 + (i + 1) % 3) as usize]; // Ensure that the indices have a consistent order by making i0 the smaller pEdges.push(SEdge { i0: i0.min(i1), @@ -297,10 +272,8 @@ pub(crate) unsafe fn BuildNeighborsFast( let i1_0: i32 = edge.i1; let f_0: i32 = edge.f; - let (i0_A, i1_A, edgenum_A) = - GetEdge(&*piTriListIn.offset((f_0 * 3i32) as isize), i0_0, i1_0); - let bUnassigned_A = - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] == -1i32; + let (i0_A, i1_A, edgenum_A) = GetEdge(&piTriListIn[(f_0 * 3) as usize..], i0_0, i1_0); + let bUnassigned_A = pTriInfos[f_0 as usize].FaceNeighbors[edgenum_A as usize] == -1i32; if bUnassigned_A { let mut j: i32 = i + 1i32; @@ -308,16 +281,16 @@ pub(crate) unsafe fn BuildNeighborsFast( let t = pEdges[j as usize].f; // C: Flip i1 and i0 let (i1_B, i0_B, edgenum_B) = GetEdge( - &*piTriListIn.offset((t * 3i32) as isize), + &piTriListIn[(t * 3) as usize..], pEdges[j as usize].i0, pEdges[j as usize].i1, ); let bUnassigned_B = - (*pTriInfos.offset(t as isize)).FaceNeighbors[edgenum_B as usize] == -1i32; + pTriInfos[t as usize].FaceNeighbors[edgenum_B as usize] == -1i32; if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { let mut t_0: i32 = pEdges[j as usize].f; - (*pTriInfos.offset(f_0 as isize)).FaceNeighbors[edgenum_A as usize] = t_0; - (*pTriInfos.offset(t_0 as isize)).FaceNeighbors[edgenum_B as usize] = f_0; + pTriInfos[f_0 as usize].FaceNeighbors[edgenum_A as usize] = t_0; + pTriInfos[t_0 as usize].FaceNeighbors[edgenum_B as usize] = f_0; break; } else { j += 1 @@ -327,22 +300,23 @@ pub(crate) unsafe fn BuildNeighborsFast( } } -pub(crate) unsafe fn GetEdge(mut indices: *const i32, i0_in: i32, i1_in: i32) -> (i32, i32, i32) { - if *indices.offset(0isize) == i0_in || *indices.offset(0isize) == i1_in { - if *indices.offset(1isize) == i0_in || *indices.offset(1isize) == i1_in { - (*indices.offset(0isize), *indices.offset(1isize), 0) - } else { - (*indices.offset(2isize), *indices.offset(0isize), 2) - } - } else { - (*indices.offset(1isize), *indices.offset(2isize), 1) +pub(crate) fn GetEdge(indices: &[i32], i0_in: i32, i1_in: i32) -> (i32, i32, i32) { + let indices_to_find = [i0_in, i1_in]; + match ( + indices_to_find.contains(&indices[0]), + indices_to_find.contains(&indices[1]), + ) { + (true, true) => (indices[0], indices[1], 0), + (true, false) => (indices[2], indices[0], 2), + (false, true) => (indices[1], indices[2], 1), + (false, false) => unreachable!(), } } // returns the texture area times 2 -unsafe fn CalcTexArea(geometry: &impl Geometry, mut indices: *const i32) -> f32 { - let t1 = get_tex_coord(geometry, *indices.offset(0isize) as usize); - let t2 = get_tex_coord(geometry, *indices.offset(1isize) as usize); - let t3 = get_tex_coord(geometry, *indices.offset(2isize) as usize); +fn CalcTexArea(geometry: &impl Geometry, mut indices: &[i32]) -> f32 { + let t1 = get_tex_coord(geometry, indices[0] as usize); + let t2 = get_tex_coord(geometry, indices[1] as usize); + let t3 = get_tex_coord(geometry, indices[2] as usize); let t21x: f32 = t2.x - t1.x; let t21y: f32 = t2.y - t1.y; let t31x: f32 = t3.x - t1.x; From c53b21a1229ef0b9ad821d3121e6e02f8663290c Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Wed, 22 Jun 2022 11:19:35 +0100 Subject: [PATCH 39/44] Make `DegenPrologue` safe --- crates/bevy_mikktspace/src/generated.rs | 4 +- .../src/generated/degenerate.rs | 74 ++++++++----------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index f53812f667908..72dec8bfcc87b 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -243,8 +243,8 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) // C: put the degenerate triangles last. // Note: A quad can have degenerate triangles if two vertices are in the same location degenerate::DegenPrologue( - pTriInfos.as_mut_ptr(), - piTriListIn.as_mut_ptr(), + &mut pTriInfos, + &mut piTriListIn, iNrTrianglesIn as i32, iTotTris as i32, ); diff --git a/crates/bevy_mikktspace/src/generated/degenerate.rs b/crates/bevy_mikktspace/src/generated/degenerate.rs index 59e343d17205c..e093df0d8530a 100644 --- a/crates/bevy_mikktspace/src/generated/degenerate.rs +++ b/crates/bevy_mikktspace/src/generated/degenerate.rs @@ -6,37 +6,32 @@ use super::STSpace; use super::STriInfo; use super::TriangleFlags; -pub(crate) unsafe fn DegenPrologue( - mut pTriInfos: *mut STriInfo, - mut piTriList_out: *mut i32, +pub(crate) fn DegenPrologue( + mut pTriInfos: &mut [STriInfo], + mut piTriList_out: &mut [i32], iNrTrianglesIn: i32, iTotTris: i32, ) { // locate quads with only one good triangle - let mut t: i32 = 0i32; - while t < iTotTris - 1i32 { - let iFO_a: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let iFO_b: i32 = (*pTriInfos.offset((t + 1i32) as isize)).iOrgFaceNumber; - if iFO_a == iFO_b { - let bIsDeg_a: bool = (*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); - let bIsDeg_b: bool = (*pTriInfos.offset((t + 1i32) as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); + let mut t = 0; + while t < (iTotTris as usize) - 1 { + let [a, b] = if let [a, b] = &mut pTriInfos[t..=t + 1] { + [a, b] + } else { + unreachable!() + }; + if a.iOrgFaceNumber == b.iOrgFaceNumber { + let bIsDeg_a: bool = a.iFlag.contains(TriangleFlags::DEGENERATE); + let bIsDeg_b: bool = b.iFlag.contains(TriangleFlags::DEGENERATE); // If exactly one is degenerate, mark both as QUAD_ONE_DEGENERATE_TRI, i.e. that the other triangle - // (If both are degenerate, this) + // (If both are degenerate, this doesn't matter ?) if bIsDeg_a ^ bIsDeg_b { - (*pTriInfos.offset(t as isize)) - .iFlag - .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); - (*pTriInfos.offset((t + 1i32) as isize)) - .iFlag - .insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + a.iFlag.insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); + b.iFlag.insert(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); } - t += 2i32 + t += 2; } else { - t += 1 + t += 1; } } @@ -48,21 +43,19 @@ pub(crate) unsafe fn DegenPrologue( // but good enough and safe. // TODO: Consider using `sort_by_key` on Vec instead (which is stable) - it might be // technically slower, but it's much easier to reason about - let mut iNextGoodTriangleSearchIndex = 1i32; - t = 0i32; + let mut iNextGoodTriangleSearchIndex = 1; + let mut t = 0; let mut bStillFindingGoodOnes = true; - while t < iNrTrianglesIn && bStillFindingGoodOnes { - let bIsGood: bool = !(*pTriInfos.offset(t as isize)) - .iFlag - .contains(TriangleFlags::DEGENERATE); + while t < iNrTrianglesIn as usize && bStillFindingGoodOnes { + let bIsGood: bool = !pTriInfos[t].iFlag.contains(TriangleFlags::DEGENERATE); if bIsGood { - if iNextGoodTriangleSearchIndex < t + 2i32 { - iNextGoodTriangleSearchIndex = t + 2i32 + if iNextGoodTriangleSearchIndex < t + 2 { + iNextGoodTriangleSearchIndex = t + 2 } } else { let mut bJustADegenerate: bool = true; - while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris { - let bIsGood_0: bool = !(*pTriInfos.offset(iNextGoodTriangleSearchIndex as isize)) + while bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris as usize { + let bIsGood_0: bool = !pTriInfos[iNextGoodTriangleSearchIndex] .iFlag .contains(TriangleFlags::DEGENERATE); if bIsGood_0 { @@ -77,15 +70,10 @@ pub(crate) unsafe fn DegenPrologue( debug_assert!(iNextGoodTriangleSearchIndex > (t + 1)); // Swap t0 and t1 if !bJustADegenerate { - for i in 0..3i32 { - let index: i32 = *piTriList_out.offset((t0 * 3i32 + i) as isize); - *piTriList_out.offset((t0 * 3i32 + i) as isize) = - *piTriList_out.offset((t1 * 3i32 + i) as isize); - *piTriList_out.offset((t1 * 3i32 + i) as isize) = index; - } - let tri_info: STriInfo = *pTriInfos.offset(t0 as isize); - *pTriInfos.offset(t0 as isize) = *pTriInfos.offset(t1 as isize); - *pTriInfos.offset(t1 as isize) = tri_info + let (start, end) = piTriList_out.split_at_mut(t1 * 3); + + start[t0 * 3..t0 * 3 + 3].swap_with_slice(&mut end[0..3]); + pTriInfos.swap(t0, t1); } else { bStillFindingGoodOnes = false } @@ -94,7 +82,7 @@ pub(crate) unsafe fn DegenPrologue( t += 1 } } - debug_assert!(iNrTrianglesIn == t); + debug_assert!(iNrTrianglesIn as usize == t); debug_assert!(bStillFindingGoodOnes); } From e69cea6dd4d43e698aa0b9a23a4498fdf18df379 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Wed, 22 Jun 2022 20:59:29 +0100 Subject: [PATCH 40/44] Make `DegenEpilogue` safe --- crates/bevy_mikktspace/src/generated.rs | 6 +- .../src/generated/degenerate.rs | 55 +++++++++---------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 72dec8bfcc87b..a7ceced962f0f 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -288,9 +288,9 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) return false; } degenerate::DegenEpilogue( - psTspace.as_mut_ptr(), - pTriInfos.as_mut_ptr(), - piTriListIn.as_mut_ptr(), + &mut psTspace, + &mut pTriInfos, + &mut piTriListIn, geometry, iNrTrianglesIn as i32, iTotTris as i32, diff --git a/crates/bevy_mikktspace/src/generated/degenerate.rs b/crates/bevy_mikktspace/src/generated/degenerate.rs index e093df0d8530a..e79abe0dc17d4 100644 --- a/crates/bevy_mikktspace/src/generated/degenerate.rs +++ b/crates/bevy_mikktspace/src/generated/degenerate.rs @@ -86,40 +86,39 @@ pub(crate) fn DegenPrologue( debug_assert!(bStillFindingGoodOnes); } -pub(crate) unsafe fn DegenEpilogue( - mut psTspace: *mut STSpace, - mut pTriInfos: *mut STriInfo, - mut piTriListIn: *mut i32, +pub(crate) fn DegenEpilogue( + mut psTspace: &mut [STSpace], + mut pTriInfos: &mut [STriInfo], + mut piTriListIn: &mut [i32], geometry: &impl Geometry, iNrTrianglesIn: i32, iTotTris: i32, ) { // For all degenerate triangles for t in iNrTrianglesIn..iTotTris { - let bSkip: bool = (*pTriInfos.offset(t as isize)) + let bSkip = pTriInfos[t as usize] .iFlag .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI); if !bSkip { for i in 0..3i32 { // For all vertices on that triangle - let index1: i32 = *piTriListIn.offset((t * 3i32 + i) as isize); - for j in 0..(3i32 * iNrTrianglesIn) { - let index2: i32 = *piTriListIn.offset(j as isize); + let index1 = piTriListIn[(t * 3 + i) as usize]; + for j in 0..(3 * iNrTrianglesIn) { + let index2 = piTriListIn[j as usize]; // If the vertex properties are the same as another non-degenerate vertex if index1 == index2 { - let iTri: i32 = j / 3i32; - let iVert: i32 = j % 3i32; - let iSrcVert: i32 = - (*pTriInfos.offset(iTri as isize)).vert_num[iVert as usize] as i32; - let iSrcOffs: i32 = (*pTriInfos.offset(iTri as isize)).iTSpacesOffs; - let iDstVert: i32 = - (*pTriInfos.offset(t as isize)).vert_num[i as usize] as i32; - let iDstOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; + // assert_eq!(j, index1); + let iTri = j / 3i32; + let iVert = j % 3i32; + let iSrcVert = pTriInfos[iTri as usize].vert_num[iVert as usize] as i32; + let iSrcOffs = pTriInfos[iTri as usize].iTSpacesOffs; + let iDstVert = pTriInfos[t as usize].vert_num[i as usize] as i32; + let iDstOffs: i32 = pTriInfos[t as usize].iTSpacesOffs; // Set the tangent space of this vertex to the tangent space of that vertex // TODO: This is absurd - doing a linear search through all vertices for each // degenerate triangle? - *psTspace.offset((iDstOffs + iDstVert) as isize) = - *psTspace.offset((iSrcOffs + iSrcVert) as isize); + psTspace[(iDstOffs + iDstVert) as usize] = + psTspace[(iSrcOffs + iSrcVert) as usize]; break; } } @@ -128,14 +127,12 @@ pub(crate) unsafe fn DegenEpilogue( } for t in 0..iNrTrianglesIn { // Handle quads with a single degenerate triangle by - if (*pTriInfos.offset(t as isize)) + if pTriInfos[t as usize] .iFlag .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) { - let mut pV: *mut u8 = (*pTriInfos.offset(t as isize)).vert_num.as_mut_ptr(); - let mut iFlag: i32 = 1i32 << *pV.offset(0isize) as i32 - | 1i32 << *pV.offset(1isize) as i32 - | 1i32 << *pV.offset(2isize) as i32; + let mut pV = &mut pTriInfos[t as usize].vert_num; + let mut iFlag: i32 = 1i32 << pV[0] as i32 | 1i32 << pV[1] as i32 | 1i32 << pV[2] as i32; let mut iMissingIndex: i32 = 0i32; if iFlag & 2i32 == 0i32 { iMissingIndex = 1i32 @@ -144,22 +141,22 @@ pub(crate) unsafe fn DegenEpilogue( } else if iFlag & 8i32 == 0i32 { iMissingIndex = 3i32 } - let iOrgF = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; + let iOrgF = pTriInfos[t as usize].iOrgFaceNumber; let vDstP = get_position( geometry, face_vert_to_index(iOrgF as usize, iMissingIndex as usize), ); - for i_0 in 0..3i32 { - let iVert_0: i32 = *pV.offset(i_0 as isize) as i32; + for i_0 in 0..3 { + let iVert_0 = pV[i_0]; let vSrcP = get_position( geometry, face_vert_to_index(iOrgF as usize, iVert_0 as usize), ); if vSrcP == vDstP { - let iOffs: i32 = (*pTriInfos.offset(t as isize)).iTSpacesOffs; - *psTspace.offset((iOffs + iMissingIndex) as isize) = - *psTspace.offset((iOffs + iVert_0) as isize); + let iOffs: i32 = pTriInfos[t as usize].iTSpacesOffs; + psTspace[(iOffs + iMissingIndex) as usize] = + psTspace[(iOffs + iVert_0 as i32) as usize]; break; } } From 8f094b606d3478a836f5537247db95fb0a658db3 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 23 Jun 2022 12:37:19 +0100 Subject: [PATCH 41/44] Finish making bevy_mikktspace safe --- crates/bevy_mikktspace/src/generated.rs | 299 ++++++++++++------------ crates/bevy_mikktspace/src/lib.rs | 2 +- 2 files changed, 146 insertions(+), 155 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index a7ceced962f0f..2ea9a121fa6fa 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -47,8 +47,6 @@ mod degenerate; mod setup; -use std::ptr::null_mut; - use bitflags::bitflags; use glam::Vec3; @@ -94,8 +92,9 @@ bitflags! { pub struct STriInfo { /// Indices of neighbouring triangles across this triangle's edges pub FaceNeighbors: [i32; 3], - /// The group each vertex belongs to. TODO: Convert to index - pub AssignedGroup: [*mut SGroup; 3], + /// The group each vertex belongs to. + /// This should be Option, but rustc hasn't added that yet + pub AssignedGroup: [usize; 3], pub vOs: Vec3, pub vOt: Vec3, pub fMagS: f32, @@ -116,7 +115,7 @@ impl STriInfo { fn zero() -> Self { Self { FaceNeighbors: [-1, -1, -1], - AssignedGroup: [null_mut(), null_mut(), null_mut()], + AssignedGroup: [usize::MAX; 3], vOs: Default::default(), vOt: Default::default(), fMagS: 0.0, @@ -132,7 +131,7 @@ impl STriInfo { #[derive(Copy, Clone)] pub struct SGroup { pub iNrFaces: i32, - pub pFaceIndices: *mut i32, + pub pFaceIndices: usize, pub iVertexRepresentitive: i32, pub bOrientPreservering: bool, } @@ -141,7 +140,7 @@ impl SGroup { fn zero() -> Self { Self { iNrFaces: 0, - pFaceIndices: null_mut(), + pFaceIndices: usize::MAX, iVertexRepresentitive: 0, bOrientPreservering: false, } @@ -184,7 +183,7 @@ struct TriangleMap { } // Entry point -pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { +pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { // TODO: Accept in radians by default here? let fThresCos = (fAngularThreshold.to_radians()).cos(); @@ -257,10 +256,10 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) let mut piGroupTrianglesBuffer = vec![0; iNrTrianglesIn * 3]; let iNrActiveGroups = Build4RuleGroups( - pTriInfos.as_mut_ptr(), - pGroups.as_mut_ptr(), - piGroupTrianglesBuffer.as_mut_ptr(), - piTriListIn.as_ptr(), + &mut pTriInfos, + &mut pGroups, + &mut piGroupTrianglesBuffer, + &piTriListIn, iNrTrianglesIn as i32, ); @@ -277,12 +276,13 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) let bRes = GenerateTSpaces( &mut psTspace, - pTriInfos.as_ptr(), - pGroups.as_ptr(), + &pTriInfos, + &pGroups, iNrActiveGroups, - piTriListIn.as_ptr(), + &piTriListIn, fThresCos, geometry, + &piGroupTrianglesBuffer, ); if !bRes { return false; @@ -318,77 +318,67 @@ pub unsafe fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) return true; } -unsafe fn GenerateTSpaces( +fn GenerateTSpaces( psTspace: &mut [STSpace], - mut pTriInfos: *const STriInfo, - mut pGroups: *const SGroup, + mut pTriInfos: &[STriInfo], + mut pGroups: &[SGroup], iNrActiveGroups: i32, - mut piTriListIn: *const i32, + mut piTriListIn: &[i32], fThresCos: f32, geometry: &impl Geometry, + piGroupTrianglesBuffer: &[i32], ) -> bool { - let mut iMaxNrFaces: usize = 0; - for g in 0..iNrActiveGroups { - if iMaxNrFaces < (*pGroups.offset(g as isize)).iNrFaces as usize { - iMaxNrFaces = (*pGroups.offset(g as isize)).iNrFaces as usize - } - } - if iMaxNrFaces == 0 { - return true; - } + let mut iMaxNrFaces = pGroups[..iNrActiveGroups as usize] + .iter() + .map(|it| it.iNrFaces) + .max(); + + let iMaxNrFaces = match iMaxNrFaces { + Some(0) | None => return true, + Some(iMaxNrFaces) => iMaxNrFaces as usize, + }; let mut pSubGroupTspace = vec![STSpace::zero(); iMaxNrFaces]; let mut pUniSubGroups = vec![SSubGroup::zero(); iMaxNrFaces]; let mut pTmpMembers = vec![0i32; iMaxNrFaces]; for g in 0..iNrActiveGroups { - let mut pGroup: *const SGroup = &*pGroups.offset(g as isize) as *const SGroup; + let mut pGroup: &SGroup = &pGroups[g as usize]; let mut iUniqueSubGroups = 0; - for i in 0..(*pGroup).iNrFaces { - let f: i32 = *(*pGroup).pFaceIndices.offset(i as isize); + for i in 0..pGroup.iNrFaces { + let f = piGroupTrianglesBuffer[pGroup.pFaceIndices + i as usize]; let mut tmp_group: SSubGroup = SSubGroup { iNrFaces: 0, pTriMembers: Vec::new(), }; - let index = if (*pTriInfos.offset(f as isize)).AssignedGroup[0usize] - == pGroup as *mut SGroup - { - 0i32 - } else if (*pTriInfos.offset(f as isize)).AssignedGroup[1usize] == pGroup as *mut SGroup - { - 1i32 - } else if (*pTriInfos.offset(f as isize)).AssignedGroup[2usize] == pGroup as *mut SGroup - { - 2i32 - } else { - panic!() - }; - let iVertIndex = *piTriListIn.offset((f * 3i32 + index) as isize); + let index = pTriInfos[f as usize] + .AssignedGroup + .iter() + .position(|&it| it == g as usize) + .unwrap(); + + let iVertIndex = piTriListIn[(f * 3 + index as i32) as usize]; assert!(iVertIndex == (*pGroup).iVertexRepresentitive); let n = get_normal(geometry, iVertIndex as usize); - let mut vOs = (*pTriInfos.offset(f as isize)).vOs - - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); - let mut vOt = (*pTriInfos.offset(f as isize)).vOt - - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); + let mut vOs = pTriInfos[f as usize].vOs - (n.dot(pTriInfos[f as usize].vOs) * n); + let mut vOt = pTriInfos[f as usize].vOt - (n.dot(pTriInfos[f as usize].vOt) * n); vOs = vOs.normalize_or_zero(); vOt = vOt.normalize_or_zero(); - let iOF_1 = (*pTriInfos.offset(f as isize)).iOrgFaceNumber; + let iOF_1 = pTriInfos[f as usize].iOrgFaceNumber; let mut iMembers = 0; - for j in 0..(*pGroup).iNrFaces { - let t: i32 = *(*pGroup).pFaceIndices.offset(j as isize); - let iOF_2: i32 = (*pTriInfos.offset(t as isize)).iOrgFaceNumber; - let mut vOs2 = (*pTriInfos.offset(t as isize)).vOs - - (n.dot((*pTriInfos.offset(t as isize)).vOs) * n); - let mut vOt2 = (*pTriInfos.offset(t as isize)).vOt - - (n.dot((*pTriInfos.offset(t as isize)).vOt) * n); + for j in 0..pGroup.iNrFaces { + let t: i32 = piGroupTrianglesBuffer[pGroup.pFaceIndices + j as usize]; + let tri = &pTriInfos[t as usize]; + let iOF_2: i32 = tri.iOrgFaceNumber; + let mut vOs2 = tri.vOs - (n.dot(tri.vOs) * n); + let mut vOt2 = tri.vOt - (n.dot(tri.vOt) * n); vOs2 = vOs2.normalize_or_zero(); vOt2 = vOt2.normalize_or_zero(); - let bAny: bool = ((*pTriInfos.offset(f as isize)).iFlag - | (*pTriInfos.offset(t as isize)).iFlag) + let bAny: bool = (pTriInfos[f as usize].iFlag | pTriInfos[t as usize].iFlag) .contains(TriangleFlags::GROUP_WITH_ANY); let bSameOrgFace: bool = iOF_1 == iOF_2; let fCosS: f32 = vOs.dot(vOs2); @@ -418,27 +408,27 @@ unsafe fn GenerateTSpaces( idx = it; } else { idx = iUniqueSubGroups; - // C: if no match was found we allocate a new subgroup - pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers as i32; - pUniSubGroups[iUniqueSubGroups].pTriMembers = tmp_group.pTriMembers.clone(); pSubGroupTspace[iUniqueSubGroups] = EvalTspace( - tmp_group.pTriMembers.as_mut_ptr(), + &mut tmp_group.pTriMembers, iMembers as i32, piTriListIn, pTriInfos, geometry, (*pGroup).iVertexRepresentitive, ); + // C: if no match was found we allocate a new subgroup + pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers as i32; + pUniSubGroups[iUniqueSubGroups].pTriMembers = tmp_group.pTriMembers; iUniqueSubGroups += 1 } - let iOffs = (*pTriInfos.offset(f as isize)).iTSpacesOffs as usize; - let iVert = (*pTriInfos.offset(f as isize)).vert_num[index as usize] as usize; + let iOffs = pTriInfos[f as usize].iTSpacesOffs as usize; + let iVert = pTriInfos[f as usize].vert_num[index as usize] as usize; let mut pTS_out = &mut psTspace[iOffs + iVert]; assert!(pTS_out.iCounter < 2); debug_assert!( (*pGroup).bOrientPreservering - == (*pTriInfos.offset(f as isize)) + == pTriInfos[f as usize] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING) ); @@ -456,7 +446,7 @@ unsafe fn GenerateTSpaces( } return true; } -unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpace { +fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { let mut ts_res: STSpace = STSpace { vOs: Vec3::new(0.0, 0.0, 0.0), fMagS: 0., @@ -485,11 +475,11 @@ unsafe fn AvgTSpace(mut pTS0: *const STSpace, mut pTS1: *const STSpace) -> STSpa return ts_res; } -unsafe fn EvalTspace( - mut face_indices: *mut i32, +fn EvalTspace( + mut face_indices: &mut [i32], iFaces: i32, - mut piTriListIn: *const i32, - mut pTriInfos: *const STriInfo, + mut piTriListIn: &[i32], + mut pTriInfos: &[STriInfo], geometry: &impl Geometry, iVertexRepresentitive: i32, ) -> STSpace { @@ -497,35 +487,30 @@ unsafe fn EvalTspace( let mut fAngleSum: f32 = 0i32 as f32; for face in 0..iFaces { - let f: i32 = *face_indices.offset(face as isize); - if !(*pTriInfos.offset(f as isize)) + let f: i32 = face_indices[face as usize]; + if !pTriInfos[f as usize] .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { - let i: i32 = if *piTriListIn.offset((3i32 * f + 0i32) as isize) == iVertexRepresentitive - { + let i: i32 = if piTriListIn[(3i32 * f + 0i32) as usize] == iVertexRepresentitive { 0i32 - } else if *piTriListIn.offset((3i32 * f + 1i32) as isize) == iVertexRepresentitive { + } else if piTriListIn[(3i32 * f + 1i32) as usize] == iVertexRepresentitive { 1i32 - } else if *piTriListIn.offset((3i32 * f + 2i32) as isize) == iVertexRepresentitive { + } else if piTriListIn[(3i32 * f + 2i32) as usize] == iVertexRepresentitive { 2i32 } else { panic!(); }; - let index = *piTriListIn.offset((3i32 * f + i) as isize); + let index = piTriListIn[(3i32 * f + i) as usize]; let n = get_normal(geometry, index as usize); - let mut vOs = (*pTriInfos.offset(f as isize)).vOs - - (n.dot((*pTriInfos.offset(f as isize)).vOs) * n); - let mut vOt = (*pTriInfos.offset(f as isize)).vOt - - (n.dot((*pTriInfos.offset(f as isize)).vOt) * n); + let mut vOs = pTriInfos[f as usize].vOs - (n.dot(pTriInfos[f as usize].vOs) * n); + let mut vOt = pTriInfos[f as usize].vOt - (n.dot(pTriInfos[f as usize].vOt) * n); vOs = vOs.normalize_or_zero(); vOt = vOt.normalize_or_zero(); - let i2 = - *piTriListIn.offset((3i32 * f + if i < 2i32 { i + 1i32 } else { 0i32 }) as isize); - let i1 = *piTriListIn.offset((3i32 * f + i) as isize); - let i0 = - *piTriListIn.offset((3i32 * f + if i > 0i32 { i - 1i32 } else { 2i32 }) as isize); + let i2 = piTriListIn[(3i32 * f + (i + 1) % 3) as usize]; + let i1 = piTriListIn[(3i32 * f + i) as usize]; + let i0 = piTriListIn[(3i32 * f + (i + 2) % 3) as usize]; let p0 = get_position(geometry, i0 as usize); let p1 = get_position(geometry, i1 as usize); let p2 = get_position(geometry, i2 as usize); @@ -539,8 +524,8 @@ unsafe fn EvalTspace( let fCos = v1.dot(v2).clamp(-1., 1.); let fAngle = (fCos as f64).acos() as f32; - let fMagS = (*pTriInfos.offset(f as isize)).fMagS; - let fMagT = (*pTriInfos.offset(f as isize)).fMagT; + let fMagS = pTriInfos[f as usize].fMagS; + let fMagT = pTriInfos[f as usize].fMagT; res.vOs = res.vOs + (fAngle * vOs); res.vOt = res.vOt + (fAngle * vOt); res.fMagS += fAngle * fMagS; @@ -558,11 +543,11 @@ unsafe fn EvalTspace( return res; } -unsafe fn Build4RuleGroups( - mut pTriInfos: *mut STriInfo, - mut pGroups: *mut SGroup, - mut piGroupTrianglesBuffer: *mut i32, - mut piTriListIn: *const i32, +fn Build4RuleGroups( + mut pTriInfos: &mut [STriInfo], + mut pGroups: &mut [SGroup], + mut piGroupTrianglesBuffer: &mut [i32], + mut piTriListIn: &[i32], iNrTrianglesIn: i32, ) -> i32 { let mut iNrActiveGroups: i32 = 0i32; @@ -571,60 +556,61 @@ unsafe fn Build4RuleGroups( for f in 0..iNrTrianglesIn { for i in 0..3i32 { - if !(*pTriInfos.offset(f as isize)) + if !pTriInfos[f as usize] .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) - && (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize].is_null() + && pTriInfos[f as usize].AssignedGroup[i as usize] == usize::MAX { - let vert_index: i32 = *piTriListIn.offset((f * 3i32 + i) as isize); - let ref mut fresh2 = (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]; + let vert_index: i32 = piTriListIn[(f * 3 + i) as usize]; debug_assert!(iNrActiveGroups < iNrMaxGroups); - *fresh2 = &mut *pGroups.offset(iNrActiveGroups as isize) as *mut SGroup; - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]) - .iVertexRepresentitive = vert_index; - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).bOrientPreservering = - (*pTriInfos.offset(f as isize)) - .iFlag - .contains(TriangleFlags::ORIENT_PRESERVING); - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces = 0i32; - let ref mut fresh3 = - (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).pFaceIndices; - *fresh3 = &mut *piGroupTrianglesBuffer.offset(iOffset as isize) as *mut i32; + pTriInfos[f as usize].AssignedGroup[i as usize] = iNrActiveGroups as usize; + let group = &mut pGroups[pTriInfos[f as usize].AssignedGroup[i as usize]]; + group.iVertexRepresentitive = vert_index; + group.bOrientPreservering = pTriInfos[f as usize] + .iFlag + .contains(TriangleFlags::ORIENT_PRESERVING); + group.iNrFaces = 0i32; + group.pFaceIndices = iOffset as usize; iNrActiveGroups += 1; - AddTriToGroup((*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], f); - let bOrPre = (*pTriInfos.offset(f as isize)) + AddTriToGroup(piGroupTrianglesBuffer, group, f); + let bOrPre = pTriInfos[f as usize] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - let mut neigh_indexL = (*pTriInfos.offset(f as isize)).FaceNeighbors[i as usize]; - let mut neigh_indexR = (*pTriInfos.offset(f as isize)).FaceNeighbors - [(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; + let mut neigh_indexL = pTriInfos[f as usize].FaceNeighbors[i as usize]; + let mut neigh_indexR = pTriInfos[f as usize].FaceNeighbors[((i + 2) % 3) as usize]; if neigh_indexL >= 0i32 { + let index = pTriInfos[f as usize].AssignedGroup[i as usize]; let bAnswer: bool = AssignRecur( piTriListIn, pTriInfos, neigh_indexL, - (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], + &mut pGroups[index], + index, + piGroupTrianglesBuffer, ); - let bOrPre2: bool = (*pTriInfos.offset(neigh_indexL as isize)) + let bOrPre2: bool = pTriInfos[neigh_indexL as usize] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - let bDiff: bool = if bOrPre != bOrPre2 { true } else { false }; + let bDiff: bool = bOrPre != bOrPre2; debug_assert!(bAnswer || bDiff) } if neigh_indexR >= 0i32 { + let index = pTriInfos[f as usize].AssignedGroup[i as usize]; let bAnswer_0: bool = AssignRecur( piTriListIn, pTriInfos, neigh_indexR, - (*pTriInfos.offset(f as isize)).AssignedGroup[i as usize], + &mut pGroups[index], + index, + piGroupTrianglesBuffer, ); - let bOrPre2_0: bool = (*pTriInfos.offset(neigh_indexR as isize)) + let bOrPre2_0: bool = pTriInfos[neigh_indexR as usize] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - let bDiff_0: bool = if bOrPre != bOrPre2_0 { true } else { false }; + let bDiff_0: bool = bOrPre != bOrPre2_0; debug_assert!(bAnswer_0 || bDiff_0) } - iOffset += (*(*pTriInfos.offset(f as isize)).AssignedGroup[i as usize]).iNrFaces; + iOffset += pGroups[pTriInfos[f as usize].AssignedGroup[i as usize]].iNrFaces; // since the groups are disjoint a triangle can never // belong to more than 3 groups. Subsequently something // is completely screwed if this assertion ever hits. @@ -636,38 +622,30 @@ unsafe fn Build4RuleGroups( } // /////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// -unsafe fn AssignRecur( - mut piTriListIn: *const i32, - mut psTriInfos: *mut STriInfo, +fn AssignRecur( + piTriListIn: &[i32], + psTriInfos: &mut [STriInfo], iMyTriIndex: i32, - mut pGroup: *mut SGroup, + pGroup: &mut SGroup, + group_idx: usize, + piGroupTrianglesBuffer: &mut [i32], ) -> bool { - let mut pMyTriInfo: *mut STriInfo = - &mut *psTriInfos.offset(iMyTriIndex as isize) as *mut STriInfo; + let mut pMyTriInfo = &mut psTriInfos[iMyTriIndex as usize]; // track down vertex - let iVertRep: i32 = (*pGroup).iVertexRepresentitive; - let mut pVerts: *const i32 = - &*piTriListIn.offset((3i32 * iMyTriIndex + 0i32) as isize) as *const i32; - let i = if *pVerts.offset(0isize) == iVertRep { - 0i32 - } else if *pVerts.offset(1isize) == iVertRep { - 1i32 - } else if *pVerts.offset(2isize) == iVertRep { - 2i32 - } else { - panic!(); - }; - if (*pMyTriInfo).AssignedGroup[i as usize] == pGroup { + let iVertRep: i32 = pGroup.iVertexRepresentitive; + let mut pVerts = &piTriListIn[3 * iMyTriIndex as usize..][..3]; + let i = pVerts.iter().position(|&it| it == iVertRep).unwrap(); + if pMyTriInfo.AssignedGroup[i as usize] == group_idx { return true; } else { - if !(*pMyTriInfo).AssignedGroup[i as usize].is_null() { + if !pMyTriInfo.AssignedGroup[i as usize] == usize::MAX { return false; } } if (*pMyTriInfo).iFlag.contains(TriangleFlags::GROUP_WITH_ANY) { - if (*pMyTriInfo).AssignedGroup[0usize].is_null() - && (*pMyTriInfo).AssignedGroup[1usize].is_null() - && (*pMyTriInfo).AssignedGroup[2usize].is_null() + if (*pMyTriInfo).AssignedGroup[0usize] == usize::MAX + && (*pMyTriInfo).AssignedGroup[1usize] == usize::MAX + && (*pMyTriInfo).AssignedGroup[2usize] == usize::MAX { (*pMyTriInfo).iFlag.set( TriangleFlags::ORIENT_PRESERVING, @@ -681,20 +659,33 @@ unsafe fn AssignRecur( if bOrient != (*pGroup).bOrientPreservering { return false; } - AddTriToGroup(pGroup, iMyTriIndex); - (*pMyTriInfo).AssignedGroup[i as usize] = pGroup; - let neigh_indexL: i32 = (*pMyTriInfo).FaceNeighbors[i as usize]; - let neigh_indexR: i32 = - (*pMyTriInfo).FaceNeighbors[(if i > 0i32 { i - 1i32 } else { 2i32 }) as usize]; + AddTriToGroup(piGroupTrianglesBuffer, pGroup, iMyTriIndex); + pMyTriInfo.AssignedGroup[i as usize] = group_idx; + let neigh_indexL = (*pMyTriInfo).FaceNeighbors[i as usize]; + let neigh_indexR = (*pMyTriInfo).FaceNeighbors[(if i > 0 { i - 1 } else { 2 }) as usize]; if neigh_indexL >= 0i32 { - AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); + AssignRecur( + piTriListIn, + psTriInfos, + neigh_indexL, + pGroup, + group_idx, + piGroupTrianglesBuffer, + ); } if neigh_indexR >= 0i32 { - AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); + AssignRecur( + piTriListIn, + psTriInfos, + neigh_indexR, + pGroup, + group_idx, + piGroupTrianglesBuffer, + ); } return true; } -unsafe fn AddTriToGroup(mut pGroup: *mut SGroup, iTriIndex: i32) { - *(*pGroup).pFaceIndices.offset((*pGroup).iNrFaces as isize) = iTriIndex; - (*pGroup).iNrFaces += 1; +fn AddTriToGroup(faces: &mut [i32], pGroup: &mut SGroup, iTriIndex: i32) { + faces[pGroup.iNrFaces as usize + pGroup.pFaceIndices] = iTriIndex; + pGroup.iNrFaces += 1; } diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index c665d60ed703c..e2dc56272dbb0 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -72,7 +72,7 @@ pub trait Geometry { /// Returns `false` if the geometry is unsuitable for tangent generation including, /// but not limited to, lack of vertices. pub fn generate_tangents(geometry: &mut impl Geometry) -> bool { - unsafe { generated::genTangSpace(geometry, 180.0) } + generated::genTangSpace(geometry, 180.0) } fn get_position(geometry: &impl Geometry, index: usize) -> Vec3 { From 425cbeea2e3a45b776a3dcc744c172255a98d83f Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 23 Jun 2022 12:52:53 +0100 Subject: [PATCH 42/44] Make clippy happy --- crates/bevy_mikktspace/src/generated.rs | 90 ++++++++----------- .../src/generated/degenerate.rs | 19 ++-- crates/bevy_mikktspace/src/generated/setup.rs | 67 ++++++-------- crates/bevy_mikktspace/src/lib.rs | 6 +- 4 files changed, 78 insertions(+), 104 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index 2ea9a121fa6fa..a98745de8fd01 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -30,19 +30,7 @@ // Comments starting with `C:` are copied as-is from the original // Note that some comments may originate from the original but not be marked as such -#![allow( - clippy::all, - clippy::doc_markdown, - clippy::redundant_else, - clippy::match_same_arms, - clippy::semicolon_if_nothing_returned, - clippy::explicit_iter_loop, - clippy::map_flatten, - dead_code, - non_camel_case_types, - non_snake_case, - unused_mut -)] +#![allow(dead_code, non_camel_case_types, non_snake_case, unused_mut)] mod degenerate; mod setup; @@ -197,7 +185,7 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo } } - if iNrTrianglesIn <= 0 { + if iNrTrianglesIn == 0 { // Easier if we can assume there's at least one face later // No tangents need to be generated return false; @@ -223,7 +211,7 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo let mut iDegenTriangles = 0; // C: Mark all degenerate triangles for t in 0..(iTotTris as usize) { - let i0 = piTriListIn[t * 3 + 0]; + let i0 = piTriListIn[t * 3]; let i1 = piTriListIn[t * 3 + 1]; let i2 = piTriListIn[t * 3 + 2]; let p0 = get_position(geometry, i0 as usize); @@ -231,7 +219,7 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo let p2 = get_position(geometry, i2 as usize); if p0 == p1 || p0 == p2 || p1 == p2 { pTriInfos[t].iFlag.insert(TriangleFlags::DEGENERATE); - iDegenTriangles += 1 + iDegenTriangles += 1; } } let iNrTrianglesIn = iTotTris - iDegenTriangles; @@ -315,7 +303,7 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo } } - return true; + true } fn GenerateTSpaces( @@ -385,18 +373,17 @@ fn GenerateTSpaces( let fCosT: f32 = vOt.dot(vOt2); debug_assert!(f != t || bSameOrgFace); // sanity check if bAny || bSameOrgFace || fCosS > fThresCos && fCosT > fThresCos { - let fresh0 = iMembers; - iMembers = iMembers + 1; - pTmpMembers[fresh0] = t + pTmpMembers[iMembers + 1] = t; } } if iMembers > 1 { - pTmpMembers[0..(iMembers - 1)].sort(); + pTmpMembers[0..(iMembers - 1)].sort_unstable(); } tmp_group.iNrFaces = iMembers as i32; tmp_group.pTriMembers = pTmpMembers.clone(); let mut found = None; + #[allow(clippy::needless_range_loop)] for l in 0..iUniqueSubGroups { if tmp_group == pUniSubGroups[l] { found = Some(l); @@ -420,7 +407,7 @@ fn GenerateTSpaces( // C: if no match was found we allocate a new subgroup pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers as i32; pUniSubGroups[iUniqueSubGroups].pTriMembers = tmp_group.pTriMembers; - iUniqueSubGroups += 1 + iUniqueSubGroups += 1; } let iOffs = pTriInfos[f as usize].iTSpacesOffs as usize; let iVert = pTriInfos[f as usize].vert_num[index as usize] as usize; @@ -433,18 +420,18 @@ fn GenerateTSpaces( .contains(TriangleFlags::ORIENT_PRESERVING) ); if (*pTS_out).iCounter == 1i32 { - *pTS_out = AvgTSpace(pTS_out, &mut pSubGroupTspace[idx]); + *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[idx]); (*pTS_out).iCounter = 2i32; - (*pTS_out).bOrient = (*pGroup).bOrientPreservering + (*pTS_out).bOrient = (*pGroup).bOrientPreservering; } else { debug_assert!(pTS_out.iCounter == 0); *pTS_out = pSubGroupTspace[idx]; (*pTS_out).iCounter = 1i32; - (*pTS_out).bOrient = (*pGroup).bOrientPreservering + (*pTS_out).bOrient = (*pGroup).bOrientPreservering; } } } - return true; + true } fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { let mut ts_res: STSpace = STSpace { @@ -463,7 +450,7 @@ fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { ts_res.fMagS = (*pTS0).fMagS; ts_res.fMagT = (*pTS0).fMagT; ts_res.vOs = (*pTS0).vOs; - ts_res.vOt = (*pTS0).vOt + ts_res.vOt = (*pTS0).vOt; } else { ts_res.fMagS = 0.5f32 * ((*pTS0).fMagS + (*pTS1).fMagS); ts_res.fMagT = 0.5f32 * ((*pTS0).fMagT + (*pTS1).fMagT); @@ -472,7 +459,7 @@ fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { ts_res.vOs = ts_res.vOs.normalize_or_zero(); ts_res.vOt = ts_res.vOt.normalize_or_zero(); } - return ts_res; + ts_res } fn EvalTspace( @@ -492,7 +479,7 @@ fn EvalTspace( .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) { - let i: i32 = if piTriListIn[(3i32 * f + 0i32) as usize] == iVertexRepresentitive { + let i: i32 = if piTriListIn[(3i32 * f) as usize] == iVertexRepresentitive { 0i32 } else if piTriListIn[(3i32 * f + 1i32) as usize] == iVertexRepresentitive { 1i32 @@ -526,11 +513,11 @@ fn EvalTspace( let fAngle = (fCos as f64).acos() as f32; let fMagS = pTriInfos[f as usize].fMagS; let fMagT = pTriInfos[f as usize].fMagT; - res.vOs = res.vOs + (fAngle * vOs); - res.vOt = res.vOt + (fAngle * vOt); + res.vOs += fAngle * vOs; + res.vOt += fAngle * vOt; res.fMagS += fAngle * fMagS; res.fMagT += fAngle * fMagT; - fAngleSum += fAngle + fAngleSum += fAngle; } } res.vOs = res.vOs.normalize_or_zero(); @@ -538,9 +525,9 @@ fn EvalTspace( if fAngleSum > 0i32 as f32 { res.fMagS /= fAngleSum; - res.fMagT /= fAngleSum + res.fMagT /= fAngleSum; } - return res; + res } fn Build4RuleGroups( @@ -592,7 +579,7 @@ fn Build4RuleGroups( .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff: bool = bOrPre != bOrPre2; - debug_assert!(bAnswer || bDiff) + debug_assert!(bAnswer || bDiff); } if neigh_indexR >= 0i32 { let index = pTriInfos[f as usize].AssignedGroup[i as usize]; @@ -608,7 +595,7 @@ fn Build4RuleGroups( .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); let bDiff_0: bool = bOrPre != bOrPre2_0; - debug_assert!(bAnswer_0 || bDiff_0) + debug_assert!(bAnswer_0 || bDiff_0); } iOffset += pGroups[pTriInfos[f as usize].AssignedGroup[i as usize]].iNrFaces; // since the groups are disjoint a triangle can never @@ -618,7 +605,7 @@ fn Build4RuleGroups( } } } - return iNrActiveGroups; + iNrActiveGroups } // /////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// @@ -637,21 +624,20 @@ fn AssignRecur( let i = pVerts.iter().position(|&it| it == iVertRep).unwrap(); if pMyTriInfo.AssignedGroup[i as usize] == group_idx { return true; - } else { - if !pMyTriInfo.AssignedGroup[i as usize] == usize::MAX { - return false; - } } - if (*pMyTriInfo).iFlag.contains(TriangleFlags::GROUP_WITH_ANY) { - if (*pMyTriInfo).AssignedGroup[0usize] == usize::MAX - && (*pMyTriInfo).AssignedGroup[1usize] == usize::MAX - && (*pMyTriInfo).AssignedGroup[2usize] == usize::MAX - { - (*pMyTriInfo).iFlag.set( - TriangleFlags::ORIENT_PRESERVING, - (*pGroup).bOrientPreservering, - ); - } + if !pMyTriInfo.AssignedGroup[i as usize] == usize::MAX { + return false; + } + + if (*pMyTriInfo).iFlag.contains(TriangleFlags::GROUP_WITH_ANY) + && (*pMyTriInfo).AssignedGroup[0usize] == usize::MAX + && (*pMyTriInfo).AssignedGroup[1usize] == usize::MAX + && (*pMyTriInfo).AssignedGroup[2usize] == usize::MAX + { + (*pMyTriInfo).iFlag.set( + TriangleFlags::ORIENT_PRESERVING, + (*pGroup).bOrientPreservering, + ); } let bOrient: bool = (*pMyTriInfo) .iFlag @@ -683,7 +669,7 @@ fn AssignRecur( piGroupTrianglesBuffer, ); } - return true; + true } fn AddTriToGroup(faces: &mut [i32], pGroup: &mut SGroup, iTriIndex: i32) { faces[pGroup.iNrFaces as usize + pGroup.pFaceIndices] = iTriIndex; diff --git a/crates/bevy_mikktspace/src/generated/degenerate.rs b/crates/bevy_mikktspace/src/generated/degenerate.rs index e79abe0dc17d4..3766510827f5d 100644 --- a/crates/bevy_mikktspace/src/generated/degenerate.rs +++ b/crates/bevy_mikktspace/src/generated/degenerate.rs @@ -50,7 +50,7 @@ pub(crate) fn DegenPrologue( let bIsGood: bool = !pTriInfos[t].iFlag.contains(TriangleFlags::DEGENERATE); if bIsGood { if iNextGoodTriangleSearchIndex < t + 2 { - iNextGoodTriangleSearchIndex = t + 2 + iNextGoodTriangleSearchIndex = t + 2; } } else { let mut bJustADegenerate: bool = true; @@ -59,9 +59,9 @@ pub(crate) fn DegenPrologue( .iFlag .contains(TriangleFlags::DEGENERATE); if bIsGood_0 { - bJustADegenerate = false + bJustADegenerate = false; } else { - iNextGoodTriangleSearchIndex += 1 + iNextGoodTriangleSearchIndex += 1; } } let t0 = t; @@ -75,11 +75,11 @@ pub(crate) fn DegenPrologue( start[t0 * 3..t0 * 3 + 3].swap_with_slice(&mut end[0..3]); pTriInfos.swap(t0, t1); } else { - bStillFindingGoodOnes = false + bStillFindingGoodOnes = false; } } if bStillFindingGoodOnes { - t += 1 + t += 1; } } debug_assert!(iNrTrianglesIn as usize == t); @@ -135,11 +135,11 @@ pub(crate) fn DegenEpilogue( let mut iFlag: i32 = 1i32 << pV[0] as i32 | 1i32 << pV[1] as i32 | 1i32 << pV[2] as i32; let mut iMissingIndex: i32 = 0i32; if iFlag & 2i32 == 0i32 { - iMissingIndex = 1i32 + iMissingIndex = 1i32; } else if iFlag & 4i32 == 0i32 { - iMissingIndex = 2i32 + iMissingIndex = 2i32; } else if iFlag & 8i32 == 0i32 { - iMissingIndex = 3i32 + iMissingIndex = 3i32; } let iOrgF = pTriInfos[t as usize].iOrgFaceNumber; let vDstP = get_position( @@ -147,8 +147,7 @@ pub(crate) fn DegenEpilogue( face_vert_to_index(iOrgF as usize, iMissingIndex as usize), ); - for i_0 in 0..3 { - let iVert_0 = pV[i_0]; + for &iVert_0 in pV.iter().take(3) { let vSrcP = get_position( geometry, face_vert_to_index(iOrgF as usize, iVert_0 as usize), diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs index e072924ba4a91..9ac7b3cee9ac5 100644 --- a/crates/bevy_mikktspace/src/generated/setup.rs +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -60,10 +60,10 @@ pub(crate) fn GenerateInitialVerticesIndexList( pVerts[0] = 0; pVerts[1] = 1; pVerts[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = face_vert_to_index(f, 0) as i32; + piTriList_out[iDstTriIndex * 3] = face_vert_to_index(f, 0) as i32; piTriList_out[iDstTriIndex * 3 + 1] = face_vert_to_index(f, 1) as i32; piTriList_out[iDstTriIndex * 3 + 2] = face_vert_to_index(f, 2) as i32; - iDstTriIndex += 1 + iDstTriIndex += 1; } else { pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f as i32; pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs as i32; @@ -79,9 +79,9 @@ pub(crate) fn GenerateInitialVerticesIndexList( let distSQ_13: f32 = (T3 - T1).length_squared(); let bQuadDiagIs_02: bool; if distSQ_02 < distSQ_13 { - bQuadDiagIs_02 = true + bQuadDiagIs_02 = true; } else if distSQ_13 < distSQ_02 { - bQuadDiagIs_02 = false + bQuadDiagIs_02 = false; } else { let P0 = get_position(geometry, i0); let P1 = get_position(geometry, i1); @@ -89,18 +89,14 @@ pub(crate) fn GenerateInitialVerticesIndexList( let P3 = get_position(geometry, i3); let distSQ_02_0: f32 = (P2 - P0).length_squared(); let distSQ_13_0: f32 = (P3 - P1).length_squared(); - bQuadDiagIs_02 = if distSQ_13_0 < distSQ_02_0 { - false - } else { - true - } + bQuadDiagIs_02 = distSQ_13_0 > distSQ_02_0; } if bQuadDiagIs_02 { let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_A[0] = 0; pVerts_A[1] = 1; pVerts_A[2] = 2; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3] = i0 as i32; piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; iDstTriIndex += 1; @@ -109,16 +105,16 @@ pub(crate) fn GenerateInitialVerticesIndexList( pVerts_B[0] = 0; pVerts_B[1] = 2; pVerts_B[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3] = i0 as i32; piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 + iDstTriIndex += 1; } else { let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_A_0[0] = 0; pVerts_A_0[1] = 1; pVerts_A_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i0 as i32; + piTriList_out[iDstTriIndex * 3] = i0 as i32; piTriList_out[iDstTriIndex * 3 + 1] = i1 as i32; piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; iDstTriIndex += 1; @@ -127,20 +123,20 @@ pub(crate) fn GenerateInitialVerticesIndexList( pVerts_B_0[0] = 1; pVerts_B_0[1] = 2; pVerts_B_0[2] = 3; - piTriList_out[iDstTriIndex * 3 + 0] = i1 as i32; + piTriList_out[iDstTriIndex * 3] = i1 as i32; piTriList_out[iDstTriIndex * 3 + 1] = i2 as i32; piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; - iDstTriIndex += 1 + iDstTriIndex += 1; } } iTSpacesOffs += verts.num_vertices(); assert!(iDstTriIndex <= iNrTrianglesIn); } - for t in 0..iNrTrianglesIn { - pTriInfos[t].iFlag = TriangleFlags::empty(); + for triangle in pTriInfos.iter_mut().take(iNrTrianglesIn) { + triangle.iFlag = TriangleFlags::empty(); } - return iTSpacesOffs; + iTSpacesOffs } pub(crate) fn InitTriInfo( @@ -149,16 +145,16 @@ pub(crate) fn InitTriInfo( geometry: &impl Geometry, iNrTrianglesIn: usize, ) { - for f in 0..iNrTrianglesIn { + for triangle in pTriInfos.iter_mut().take(iNrTrianglesIn) { // C: assumed bad - pTriInfos[f].iFlag.insert(TriangleFlags::GROUP_WITH_ANY); + triangle.iFlag.insert(TriangleFlags::GROUP_WITH_ANY); } for f in 0..iNrTrianglesIn { - let v1 = get_position(geometry, piTriListIn[(f * 3 + 0)] as usize); + let v1 = get_position(geometry, piTriListIn[f * 3] as usize); let v2 = get_position(geometry, piTriListIn[f * 3 + 1] as usize); let v3 = get_position(geometry, piTriListIn[f * 3 + 2] as usize); - let t1 = get_tex_coord(geometry, piTriListIn[f * 3 + 0] as usize); + let t1 = get_tex_coord(geometry, piTriListIn[f * 3] as usize); let t2 = get_tex_coord(geometry, piTriListIn[f * 3 + 1] as usize); let t3 = get_tex_coord(geometry, piTriListIn[f * 3 + 2] as usize); let t21x: f32 = t2.x - t1.x; @@ -186,10 +182,10 @@ pub(crate) fn InitTriInfo( 1.0f32 }; if fLenOs.is_normal() { - pTriInfos[f].vOs = (fS / fLenOs) * vOs + pTriInfos[f].vOs = (fS / fLenOs) * vOs; } if fLenOt.is_normal() { - pTriInfos[f].vOt = (fS / fLenOt) * vOt + pTriInfos[f].vOt = (fS / fLenOt) * vOt; } pTriInfos[f].fMagS = fLenOs / fAbsArea; pTriInfos[f].fMagT = fLenOt / fAbsArea; @@ -213,17 +209,11 @@ pub(crate) fn InitTriInfo( .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); if bOrientA != bOrientB { - let mut bChooseOrientFirstTri: bool = false; - if pTriInfos[t + 1] + let bChooseOrientFirstTri = pTriInfos[t + 1] .iFlag .contains(TriangleFlags::GROUP_WITH_ANY) - { - bChooseOrientFirstTri = true - } else if CalcTexArea(geometry, &piTriListIn[(t * 3)..]) - >= CalcTexArea(geometry, &piTriListIn[((t + 1) * 3)..]) - { - bChooseOrientFirstTri = true - } + || (CalcTexArea(geometry, &piTriListIn[(t * 3)..]) + >= CalcTexArea(geometry, &piTriListIn[((t + 1) * 3)..])); let t0 = if bChooseOrientFirstTri { t } else { t + 1 }; let t1_0 = if bChooseOrientFirstTri { t + 1 } else { t }; pTriInfos[t1_0].iFlag.set( @@ -234,9 +224,9 @@ pub(crate) fn InitTriInfo( ); } } - t += 2 + t += 2; } else { - t += 1 + t += 1; } } @@ -292,9 +282,8 @@ pub(crate) fn BuildNeighborsFast( pTriInfos[f_0 as usize].FaceNeighbors[edgenum_A as usize] = t_0; pTriInfos[t_0 as usize].FaceNeighbors[edgenum_B as usize] = f_0; break; - } else { - j += 1 } + j += 1; } } } @@ -322,9 +311,9 @@ fn CalcTexArea(geometry: &impl Geometry, mut indices: &[i32]) -> f32 { let t31x: f32 = t3.x - t1.x; let t31y: f32 = t3.y - t1.y; let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - return if fSignedAreaSTx2 < 0i32 as f32 { + if fSignedAreaSTx2 < 0i32 as f32 { -fSignedAreaSTx2 } else { fSignedAreaSTx2 - }; + } } diff --git a/crates/bevy_mikktspace/src/lib.rs b/crates/bevy_mikktspace/src/lib.rs index e2dc56272dbb0..1be40a03832a7 100644 --- a/crates/bevy_mikktspace/src/lib.rs +++ b/crates/bevy_mikktspace/src/lib.rs @@ -1,4 +1,5 @@ -#![allow(clippy::all)] +#![forbid(unsafe_code)] +#![allow(clippy::too_many_arguments)] use glam::{Vec2, Vec3}; @@ -83,8 +84,7 @@ fn get_position(geometry: &impl Geometry, index: usize) -> Vec3 { fn get_tex_coord(geometry: &impl Geometry, index: usize) -> Vec3 { let (face, vert) = index_to_face_vert(index); let tex_coord: Vec2 = geometry.tex_coord(face, vert).into(); - let val = tex_coord.extend(1.0); - val + tex_coord.extend(1.0) } fn get_normal(geometry: &impl Geometry, index: usize) -> Vec3 { From 9e7ff7f56465202b1cbf7c5080bcca025720bb50 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 23 Jun 2022 12:55:55 +0100 Subject: [PATCH 43/44] Fix remaining non-case lints --- crates/bevy_mikktspace/src/generated.rs | 46 ++++++++----------- .../src/generated/degenerate.rs | 14 +++--- crates/bevy_mikktspace/src/generated/setup.rs | 24 +++++----- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index a98745de8fd01..aeb0336d811c1 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -30,7 +30,7 @@ // Comments starting with `C:` are copied as-is from the original // Note that some comments may originate from the original but not be marked as such -#![allow(dead_code, non_camel_case_types, non_snake_case, unused_mut)] +#![allow(non_camel_case_types, non_snake_case)] mod degenerate; mod setup; @@ -160,16 +160,6 @@ pub struct SEdge { pub f: i32, } -/// Stores a map of 'internal' triangle vertices to real 'faces' and vertices -/// This is used to deduplicate vertices with identical faces -struct TriangleMap { - /// Packed face/vertex index of each triangle - /// Note that this is an index to the first vertex - /// with the given properties, rather than necessarily - /// (Not impressed with this data layout) - triangles: Vec<[u32; 3]>, -} - // Entry point pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> bool { // TODO: Accept in radians by default here? @@ -289,7 +279,7 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo for f in 0..iNrFaces { let verts_0 = geometry.num_vertices_of_face(f); for i in 0..verts_0.num_vertices() { - let mut pTSpace = &psTspace[index]; + let pTSpace = &psTspace[index]; geometry.set_tangent( pTSpace.vOs.into(), pTSpace.vOt.into(), @@ -308,15 +298,15 @@ pub fn genTangSpace(geometry: &mut impl Geometry, fAngularThreshold: f32) -> boo fn GenerateTSpaces( psTspace: &mut [STSpace], - mut pTriInfos: &[STriInfo], - mut pGroups: &[SGroup], + pTriInfos: &[STriInfo], + pGroups: &[SGroup], iNrActiveGroups: i32, - mut piTriListIn: &[i32], + piTriListIn: &[i32], fThresCos: f32, geometry: &impl Geometry, piGroupTrianglesBuffer: &[i32], ) -> bool { - let mut iMaxNrFaces = pGroups[..iNrActiveGroups as usize] + let iMaxNrFaces = pGroups[..iNrActiveGroups as usize] .iter() .map(|it| it.iNrFaces) .max(); @@ -331,7 +321,7 @@ fn GenerateTSpaces( let mut pTmpMembers = vec![0i32; iMaxNrFaces]; for g in 0..iNrActiveGroups { - let mut pGroup: &SGroup = &pGroups[g as usize]; + let pGroup: &SGroup = &pGroups[g as usize]; let mut iUniqueSubGroups = 0; for i in 0..pGroup.iNrFaces { @@ -355,7 +345,7 @@ fn GenerateTSpaces( vOt = vOt.normalize_or_zero(); let iOF_1 = pTriInfos[f as usize].iOrgFaceNumber; - let mut iMembers = 0; + let iMembers = 0; for j in 0..pGroup.iNrFaces { let t: i32 = piGroupTrianglesBuffer[pGroup.pFaceIndices + j as usize]; @@ -433,7 +423,7 @@ fn GenerateTSpaces( } true } -fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { +fn AvgTSpace(pTS0: &STSpace, pTS1: &STSpace) -> STSpace { let mut ts_res: STSpace = STSpace { vOs: Vec3::new(0.0, 0.0, 0.0), fMagS: 0., @@ -463,10 +453,10 @@ fn AvgTSpace(mut pTS0: &STSpace, mut pTS1: &STSpace) -> STSpace { } fn EvalTspace( - mut face_indices: &mut [i32], + face_indices: &mut [i32], iFaces: i32, - mut piTriListIn: &[i32], - mut pTriInfos: &[STriInfo], + piTriListIn: &[i32], + pTriInfos: &[STriInfo], geometry: &impl Geometry, iVertexRepresentitive: i32, ) -> STSpace { @@ -532,9 +522,9 @@ fn EvalTspace( fn Build4RuleGroups( mut pTriInfos: &mut [STriInfo], - mut pGroups: &mut [SGroup], - mut piGroupTrianglesBuffer: &mut [i32], - mut piTriListIn: &[i32], + pGroups: &mut [SGroup], + piGroupTrianglesBuffer: &mut [i32], + piTriListIn: &[i32], iNrTrianglesIn: i32, ) -> i32 { let mut iNrActiveGroups: i32 = 0i32; @@ -563,8 +553,8 @@ fn Build4RuleGroups( let bOrPre = pTriInfos[f as usize] .iFlag .contains(TriangleFlags::ORIENT_PRESERVING); - let mut neigh_indexL = pTriInfos[f as usize].FaceNeighbors[i as usize]; - let mut neigh_indexR = pTriInfos[f as usize].FaceNeighbors[((i + 2) % 3) as usize]; + let neigh_indexL = pTriInfos[f as usize].FaceNeighbors[i as usize]; + let neigh_indexR = pTriInfos[f as usize].FaceNeighbors[((i + 2) % 3) as usize]; if neigh_indexL >= 0i32 { let index = pTriInfos[f as usize].AssignedGroup[i as usize]; let bAnswer: bool = AssignRecur( @@ -620,7 +610,7 @@ fn AssignRecur( let mut pMyTriInfo = &mut psTriInfos[iMyTriIndex as usize]; // track down vertex let iVertRep: i32 = pGroup.iVertexRepresentitive; - let mut pVerts = &piTriListIn[3 * iMyTriIndex as usize..][..3]; + let pVerts = &piTriListIn[3 * iMyTriIndex as usize..][..3]; let i = pVerts.iter().position(|&it| it == iVertRep).unwrap(); if pMyTriInfo.AssignedGroup[i as usize] == group_idx { return true; diff --git a/crates/bevy_mikktspace/src/generated/degenerate.rs b/crates/bevy_mikktspace/src/generated/degenerate.rs index 3766510827f5d..1ee38ee24dc67 100644 --- a/crates/bevy_mikktspace/src/generated/degenerate.rs +++ b/crates/bevy_mikktspace/src/generated/degenerate.rs @@ -7,8 +7,8 @@ use super::STriInfo; use super::TriangleFlags; pub(crate) fn DegenPrologue( - mut pTriInfos: &mut [STriInfo], - mut piTriList_out: &mut [i32], + pTriInfos: &mut [STriInfo], + piTriList_out: &mut [i32], iNrTrianglesIn: i32, iTotTris: i32, ) { @@ -87,9 +87,9 @@ pub(crate) fn DegenPrologue( } pub(crate) fn DegenEpilogue( - mut psTspace: &mut [STSpace], - mut pTriInfos: &mut [STriInfo], - mut piTriListIn: &mut [i32], + psTspace: &mut [STSpace], + pTriInfos: &mut [STriInfo], + piTriListIn: &mut [i32], geometry: &impl Geometry, iNrTrianglesIn: i32, iTotTris: i32, @@ -131,8 +131,8 @@ pub(crate) fn DegenEpilogue( .iFlag .contains(TriangleFlags::QUAD_ONE_DEGENERATE_TRI) { - let mut pV = &mut pTriInfos[t as usize].vert_num; - let mut iFlag: i32 = 1i32 << pV[0] as i32 | 1i32 << pV[1] as i32 | 1i32 << pV[2] as i32; + let pV = &mut pTriInfos[t as usize].vert_num; + let iFlag: i32 = 1i32 << pV[0] as i32 | 1i32 << pV[1] as i32 | 1i32 << pV[2] as i32; let mut iMissingIndex: i32 = 0i32; if iFlag & 2i32 == 0i32 { iMissingIndex = 1i32; diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs index 9ac7b3cee9ac5..63b34251db5e3 100644 --- a/crates/bevy_mikktspace/src/generated/setup.rs +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -21,7 +21,7 @@ pub(crate) fn GenerateSharedVerticesIndexList( // side channel seems much easier. // Hopefully implementation can be changed to just use a btreemap or // something too. - mut piTriList_in_and_out: &mut [i32], + piTriList_in_and_out: &mut [i32], geometry: &impl Geometry, ) { let mut map = BTreeMap::new(); @@ -56,7 +56,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( pTriInfos[iDstTriIndex].iOrgFaceNumber = f as i32; pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs as i32; if let FaceKind::Triangle = verts { - let mut pVerts = &mut pTriInfos[iDstTriIndex].vert_num; + let pVerts = &mut pTriInfos[iDstTriIndex].vert_num; pVerts[0] = 0; pVerts[1] = 1; pVerts[2] = 2; @@ -92,7 +92,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( bQuadDiagIs_02 = distSQ_13_0 > distSQ_02_0; } if bQuadDiagIs_02 { - let mut pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; + let pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_A[0] = 0; pVerts_A[1] = 1; pVerts_A[2] = 2; @@ -101,7 +101,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( piTriList_out[iDstTriIndex * 3 + 2] = i2 as i32; iDstTriIndex += 1; - let mut pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; + let pVerts_B = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_B[0] = 0; pVerts_B[1] = 2; pVerts_B[2] = 3; @@ -110,7 +110,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; iDstTriIndex += 1; } else { - let mut pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; + let pVerts_A_0 = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_A_0[0] = 0; pVerts_A_0[1] = 1; pVerts_A_0[2] = 3; @@ -119,7 +119,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( piTriList_out[iDstTriIndex * 3 + 2] = i3 as i32; iDstTriIndex += 1; - let mut pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; + let pVerts_B_0 = &mut pTriInfos[iDstTriIndex].vert_num; pVerts_B_0[0] = 1; pVerts_B_0[1] = 2; pVerts_B_0[2] = 3; @@ -141,7 +141,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( pub(crate) fn InitTriInfo( mut pTriInfos: &mut [STriInfo], - mut piTriListIn: &[i32], + piTriListIn: &[i32], geometry: &impl Geometry, iNrTrianglesIn: usize, ) { @@ -164,8 +164,8 @@ pub(crate) fn InitTriInfo( let d1 = v2 - v1; let d2 = v3 - v1; let fSignedAreaSTx2: f32 = t21x * t31y - t21y * t31x; - let mut vOs = (t31y * d1) - (t21y * d2); - let mut vOt = (-t31x * d1) + (t21x * d2); + let vOs = (t31y * d1) - (t21y * d2); + let vOt = (-t31x * d1) + (t21x * d2); if fSignedAreaSTx2 > 0.0 { pTriInfos[f].iFlag.insert(TriangleFlags::ORIENT_PRESERVING); } @@ -235,7 +235,7 @@ pub(crate) fn InitTriInfo( pub(crate) fn BuildNeighborsFast( mut pTriInfos: &mut [STriInfo], - mut piTriListIn: &[i32], + piTriListIn: &[i32], iNrTrianglesIn: i32, ) { let mut pEdges = Vec::with_capacity((iNrTrianglesIn * 3) as usize); @@ -278,7 +278,7 @@ pub(crate) fn BuildNeighborsFast( let bUnassigned_B = pTriInfos[t as usize].FaceNeighbors[edgenum_B as usize] == -1i32; if i0_A == i0_B && i1_A == i1_B && bUnassigned_B { - let mut t_0: i32 = pEdges[j as usize].f; + let t_0: i32 = pEdges[j as usize].f; pTriInfos[f_0 as usize].FaceNeighbors[edgenum_A as usize] = t_0; pTriInfos[t_0 as usize].FaceNeighbors[edgenum_B as usize] = f_0; break; @@ -302,7 +302,7 @@ pub(crate) fn GetEdge(indices: &[i32], i0_in: i32, i1_in: i32) -> (i32, i32, i32 } } // returns the texture area times 2 -fn CalcTexArea(geometry: &impl Geometry, mut indices: &[i32]) -> f32 { +fn CalcTexArea(geometry: &impl Geometry, indices: &[i32]) -> f32 { let t1 = get_tex_coord(geometry, indices[0] as usize); let t2 = get_tex_coord(geometry, indices[1] as usize); let t3 = get_tex_coord(geometry, indices[2] as usize); From 8c0be14442606ab76cb2a9a6f210f866f1398413 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 23 Jun 2022 13:13:19 +0100 Subject: [PATCH 44/44] Fix behaviour changes --- crates/bevy_mikktspace/src/generated.rs | 5 +++-- crates/bevy_mikktspace/src/generated/setup.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/bevy_mikktspace/src/generated.rs b/crates/bevy_mikktspace/src/generated.rs index aeb0336d811c1..e147568ad238f 100644 --- a/crates/bevy_mikktspace/src/generated.rs +++ b/crates/bevy_mikktspace/src/generated.rs @@ -345,7 +345,7 @@ fn GenerateTSpaces( vOt = vOt.normalize_or_zero(); let iOF_1 = pTriInfos[f as usize].iOrgFaceNumber; - let iMembers = 0; + let mut iMembers = 0; for j in 0..pGroup.iNrFaces { let t: i32 = piGroupTrianglesBuffer[pGroup.pFaceIndices + j as usize]; @@ -363,7 +363,8 @@ fn GenerateTSpaces( let fCosT: f32 = vOt.dot(vOt2); debug_assert!(f != t || bSameOrgFace); // sanity check if bAny || bSameOrgFace || fCosS > fThresCos && fCosT > fThresCos { - pTmpMembers[iMembers + 1] = t; + pTmpMembers[iMembers] = t; + iMembers += 1; } } if iMembers > 1 { diff --git a/crates/bevy_mikktspace/src/generated/setup.rs b/crates/bevy_mikktspace/src/generated/setup.rs index 63b34251db5e3..1d826bd833807 100644 --- a/crates/bevy_mikktspace/src/generated/setup.rs +++ b/crates/bevy_mikktspace/src/generated/setup.rs @@ -89,7 +89,7 @@ pub(crate) fn GenerateInitialVerticesIndexList( let P3 = get_position(geometry, i3); let distSQ_02_0: f32 = (P2 - P0).length_squared(); let distSQ_13_0: f32 = (P3 - P1).length_squared(); - bQuadDiagIs_02 = distSQ_13_0 > distSQ_02_0; + bQuadDiagIs_02 = distSQ_13_0 >= distSQ_02_0; } if bQuadDiagIs_02 { let pVerts_A = &mut pTriInfos[iDstTriIndex].vert_num;