From 45e2a00f209e94f4985dd597700c5179425e959e Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 16 Mar 2026 22:24:45 -0500 Subject: [PATCH 01/18] client projectile origin tweak on the client, start the projectile simulation starting point at the rendered muzzlepoint (reminder server corrective packets will force it to converge as it goes along) origional report/revision suggestion couressy loljester: https://discord.com/channels/358091480004558848/358091480004558849/1476994844005109893 --- Engine/source/T3D/projectile.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index 4476d70dd..a6f4c5ef6 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -873,8 +873,11 @@ bool Projectile::onAdd() } } if (mSourceObject.isValid()) + { processAfter(mSourceObject); - + if (isClientObject()) + mSourceObject->getRenderMuzzlePoint(mSourceObjectSlot, &mCurrPosition); + } // Setup our bounding box if (bool(mDataBlock->getProjectileShape()) == true) mObjBox = mDataBlock->getProjectileShape()->mBounds; From ae67aaba4a6e2e49ad132f6e71d427b375ad0665 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 16 Mar 2026 22:48:12 -0500 Subject: [PATCH 02/18] controler hardening work towards better handling of tightly overlapping corners and degenerate polysoup faces --- Engine/source/T3D/player.cpp | 88 ++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index c72dd94fa..8b25e9866 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -264,7 +264,7 @@ IMPLEMENT_CALLBACK( PlayerData, onLeaveLiquid, void, ( Player* obj, const char* "@param obj The Player object\n" "@param type The type of liquid the player has left\n" ); -IMPLEMENT_CALLBACK( PlayerData, animationDone, void, ( Player* obj, const char * animName), ( obj, animName), +IMPLEMENT_CALLBACK( PlayerData, animationDone, void, ( Player* obj,const char * animName), ( obj, animName), "@brief Called on the server when a scripted animation completes.\n\n" "@param obj The Player object\n" "@see Player::setActionThread() for setting a scripted animation and its 'hold' parameter to " @@ -4805,7 +4805,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol ) static Polyhedron sBoxPolyhedron; static ExtrudedPolyList sExtrudedPolyList; static ExtrudedPolyList sPhysZonePolyList; - + Vector norms; for (; count < sMoveRetryCount; count++) { F32 speed = mVelocity.len(); if (!speed && !mDeath.haveVelocity()) @@ -4931,7 +4931,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol ) mFalling = false; // Back off... - if ( velLen > 0.f ) { + if ( velLen > POINT_EPSILON) { F32 newT = getMin(0.01f / velLen, dt); start -= mVelocity * newT; totalMotion -= velLen * newT; @@ -4983,30 +4983,82 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol ) // Subtract out velocity VectorF dv = collision->normal * (bd + sNormalElasticity); mVelocity += dv; + + bool blocked = false; if (count == 0) { firstNormal = collision->normal; } else { - if (count == 1) + bool uniqueNorm = true; + for (U32 norm = 0; norm < norms.size(); norm++) { - // Re-orient velocity along the crease. - if (mDot(dv,firstNormal) < 0.0f && - mDot(collision->normal,firstNormal) < 0.0f) + if (mFabs(mDot(collision->normal, norms[norm])) > (1.0f - POINT_EPSILON)) { - VectorF nv; - mCross(collision->normal,firstNormal,&nv); - F32 nvl = nv.len(); - if (nvl) - { - if (mDot(nv,mVelocity) < 0.0f) - nvl = -nvl; - nv *= mVelocity.len() / nvl; - mVelocity = nv; - } + uniqueNorm = false; + break; } } + if (uniqueNorm) + { + VectorF n = collision->normal; + n.normalizeSafe(); + norms.push_back(n); + } + // Use the number of unique normals to determine how to project velocity + if (norms.size() == 1) + { + VectorF n = norms[0]; + mVelocity -= mDot(mVelocity, n) * n; + if (mVelocity.lenSquared() < POINT_EPSILON) + blocked = true; + } + else if (norms.size() == 2) + { + VectorF nv; + mCross(norms[0], norms[1], &nv); + F32 nvl = nv.len(); + if (nvl > POINT_EPSILON) + { + nv /= nvl; + F32 vel = mClampF(mDot(mVelocity, nv), -speed, speed); + mVelocity = nv * vel; + if (mVelocity.lenSquared() < POINT_EPSILON) + blocked = true; + } + else blocked = true; + } + else // 3 or more unique normals: project off all using a Gram-Schmidt variant + { + Vector orthoNorms; + for (U32 i = 0; i < norms.size(); ++i) + { + VectorF n = norms[i]; + for (U32 j = 0; j < orthoNorms.size(); ++j) + n -= mDot(n, orthoNorms[j]) * orthoNorms[j]; + if (n.lenSquared() > POINT_EPSILON) + { + n.normalize(); + orthoNorms.push_back(n); + } + } + for (U32 i = 0; i < orthoNorms.size(); ++i) + mVelocity -= mDot(mVelocity, orthoNorms[i]) * orthoNorms[i]; + if (mVelocity.lenSquared() < POINT_EPSILON) + blocked = true; + } + } + if (blocked) + { + mVelocity.zero(); + return start; + } + F32 newSpeed = mVelocity.len(); + if (newSpeed > speed) + { + mVelocity.normalize(); + mVelocity *= speed; } } else @@ -5017,7 +5069,7 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol ) } } - if (count == sMoveRetryCount) + if (count == sMoveRetryCount || mVelocity.lenSquared() < POINT_EPSILON) { // Failed to move start = initialPosition; From a64cc6a512584bc616f8100b9df2f14d04d3b151 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 17 Mar 2026 12:59:45 -0500 Subject: [PATCH 03/18] revert some of the more experimental matrix math from marauder: Fixing transform plane as some descrepencies between the simd function and the c math caused issues with precision. Use c math for inverse functions until a proper simd implementation can be found. --- Engine/source/math/impl/mat44_impl.inl | 230 ++++++++++++++----------- 1 file changed, 128 insertions(+), 102 deletions(-) diff --git a/Engine/source/math/impl/mat44_impl.inl b/Engine/source/math/impl/mat44_impl.inl index da6971d0d..d688c6184 100644 --- a/Engine/source/math/impl/mat44_impl.inl +++ b/Engine/source/math/impl/mat44_impl.inl @@ -15,8 +15,13 @@ namespace math_backend::mat44 inline float mat44_get_determinant(const float* m) { - f32x4x4 ma = m_load(m); - return v_extract0(m_determinant_affine(ma)); + f32x4 r0 = v_load3_vec(m + 0); // row0 xyz + f32x4 r1 = v_load3_vec(m + 4); // row1 xyz + f32x4 r2 = v_load3_vec(m + 8); // row2 xyz + + f32x4 c0 = v_cross(r1, r2); // cofactor for row0 + f32x4 det = v_dot3(r0, c0); // splatted determinant + return v_extract0(det); } // Matrix Scale: Float3 (assume w = 1.0f) @@ -32,51 +37,81 @@ namespace math_backend::mat44 m_store(m, ma); } - inline void mat44_transform_plane_impl(const float* m, const float* scale, const float* plane, float* plane_result) + inline void mat44_transform_plane_impl(const float* m, const float* scale, const float* plane, float* presult) { - f32x4x4 M = m_load(m); - f32x4 plane_v = v_load(plane); f32x4 scale_v = v_load3_vec(scale); f32x4 invScale = v_rcp_nr(scale_v); - // normal = plane.xyz - f32x4 normal = plane_v; + f32x4x4 M = m_load(m); - // apply Inv(s) + f32x4 normal = plane_v; normal = v_mul(normal, invScale); - // multiply by Inv(Tr(m)) (only the rotation part matters) - f32x4 nx = v_mul(v_swizzle_singular_mask(normal, 0), M.r0); - f32x4 ny = v_mul(v_swizzle_singular_mask(normal, 1), M.r1); - f32x4 nz = v_mul(v_swizzle_singular_mask(normal, 2), M.r2); + //--------------------------------------------------------- + // Extract translation column (tx ty tz) + //--------------------------------------------------------- + f32x4 shear = v_set( + v_extract0(v_swizzle_singular_mask(M.r0, 3)), + v_extract0(v_swizzle_singular_mask(M.r1, 3)), + v_extract0(v_swizzle_singular_mask(M.r2, 3)), + 0.0f + ); + + float A = -v_extract0(v_dot3(M.r0, shear)); + float B = -v_extract0(v_dot3(M.r1, shear)); + float C = -v_extract0(v_dot3(M.r2, shear)); + + //--------------------------------------------------------- + // Build columns of rotation + //--------------------------------------------------------- + + f32x4 col0 = v_set( + v_extract0(v_swizzle_singular_mask(M.r0, 0)), + v_extract0(v_swizzle_singular_mask(M.r1, 0)), + v_extract0(v_swizzle_singular_mask(M.r2, 0)), + 0.0f + ); + + f32x4 col1 = v_set( + v_extract0(v_swizzle_singular_mask(M.r0, 1)), + v_extract0(v_swizzle_singular_mask(M.r1, 1)), + v_extract0(v_swizzle_singular_mask(M.r2, 1)), + 0.0f + ); + + f32x4 col2 = v_set( + v_extract0(v_swizzle_singular_mask(M.r0, 2)), + v_extract0(v_swizzle_singular_mask(M.r1, 2)), + v_extract0(v_swizzle_singular_mask(M.r2, 2)), + 0.0f + ); + + f32x4 nx = v_mul(v_swizzle_singular_mask(normal, 0), col0); + f32x4 ny = v_mul(v_swizzle_singular_mask(normal, 1), col1); + f32x4 nz = v_mul(v_swizzle_singular_mask(normal, 2), col2); normal = v_add(v_add(nx, ny), nz); - + normal = v_add(normal, v_set(A, B, C, 0.0f)); normal = v_normalize3(normal); - // compute point on plane float d = v_extract0(v_swizzle_singular_mask(plane_v, 3)); - f32x4 point = v_mul(plane_v, v_set1(-d)); - point = v_preserve_w(point, v_set1(1.0f)); + f32x4 origNormal = plane_v; + f32x4 point = v_mul(origNormal, v_set1(-d)); + point = v_insert_w(point, v_set1(1.0f)); - // apply scale point = v_mul(point, scale_v); - - // transform point by matrix point = m_mul_vec4(M, point); - - // compute new plane distance float newD = -v_extract0(v_dot3(point, normal)); alignas(16) float n[4]; v_store(n, normal); - plane_result[0] = n[0]; - plane_result[1] = n[1]; - plane_result[2] = n[2]; - plane_result[3] = newD; + presult[0] = n[0]; + presult[1] = n[1]; + presult[2] = n[2]; + presult[3] = newD; } inline void mat44_get_scale_impl(const float* m, float* s) @@ -109,92 +144,92 @@ namespace math_backend::mat44 m_store(m, ma); } + // Vector Multiply: m * v (assume w = 0.0f) + inline void mat44_mul_vec3_impl(const float* m, const float* v, float* r) + { + f32x4x4 ma = m_load(m); + f32x4 va = v_load3_vec(v); + f32x4 vr = m_mul_vec3(ma, va); + v_store3(r, vr); + } + + // Matrix Inverse inline void mat44_inverse_impl(float* m) { - f32x4x4 ma = m_load(m); + // using Cramers Rule find the Inverse + // Minv = (1/det(M)) * adjoint(M) + float det = mat44_get_determinant(m); + float invDet = 1.0f / det; + float temp[16]; + temp[0] = (m[5] * m[10] - m[6] * m[9]) * invDet; + temp[1] = (m[9] * m[2] - m[10] * m[1]) * invDet; + temp[2] = (m[1] * m[6] - m[2] * m[5]) * invDet; - // Compute cofactors using cross products - f32x4x4 mTemp; - mTemp.r0 = v_cross(ma.r1, ma.r2); - mTemp.r1 = v_cross(ma.r2, ma.r0); - mTemp.r2 = v_cross(ma.r0, ma.r1); + temp[4] = (m[6] * m[8] - m[4] * m[10]) * invDet; + temp[5] = (m[10] * m[0] - m[8] * m[2]) * invDet; + temp[6] = (m[2] * m[4] - m[0] * m[6]) * invDet; - // Determinant = dot(ma.r0, c0) - f32x4 det = v_dot3(ma.r0, mTemp.r0); - f32x4 invDet = v_rcp_nr(det); + temp[8] = (m[4] * m[9] - m[5] * m[8]) * invDet; + temp[9] = (m[8] * m[1] - m[9] * m[0]) * invDet; + temp[10] = (m[0] * m[5] - m[1] * m[4]) * invDet; - // Scale cofactors - mTemp.r0 = v_mul(mTemp.r0, invDet); - mTemp.r1 = v_mul(mTemp.r1, invDet); - mTemp.r2 = v_mul(mTemp.r2, invDet); + m[0] = temp[0]; + m[1] = temp[1]; + m[2] = temp[2]; - // Store inverse 3x3 (transpose of cofactor matrix) + m[4] = temp[4]; + m[5] = temp[5]; + m[6] = temp[6]; - mTemp = m_transpose(mTemp); - mTemp.r3 = ma.r3; + m[8] = temp[8]; + m[9] = temp[9]; + m[10] = temp[10]; - // ---- Translation ---- - - // Load original translation - f32x4 T = v_set(m[3], m[7], m[11], 0.0f); - - // Compute -(Tx*ma.r0 + Ty*ma.r1 + Tz*ma.r2) - f32x4 result = v_mul(ma.r0, v_swizzle_singular_mask(T, 0)); - result = v_add(result, v_mul(ma.r1, v_swizzle_singular_mask(T, 1))); - result = v_add(result, v_mul(ma.r2, v_swizzle_singular_mask(T, 2))); - result = v_mul(result, v_set1(-1.0f)); - - m_store(m, mTemp); - - // Store translation - m[3] = v_extract0(result); - m[7] = v_extract0(v_swizzle_singular_mask(result, 1)); - m[11] = v_extract0(v_swizzle_singular_mask(result, 2)); + // invert the translation + temp[0] = -m[3]; + temp[1] = -m[7]; + temp[2] = -m[11]; + mat44_mul_vec3_impl(m, temp, &temp[4]); + m[3] = temp[4]; + m[7] = temp[5]; + m[11] = temp[6]; } // Matrix Inverse - inline void mat44_inverse_to_impl(const float* m, float* dst) + inline void mat44_inverse_to_impl(const float* m, float* d) { - f32x4x4 ma = m_load(m); + // using Cramers Rule find the Inverse + // Minv = (1/det(M)) * adjoint(M) + float det = mat44_get_determinant(m); - // Compute cofactors using cross products - f32x4x4 mTemp; - mTemp.r0 = v_cross(ma.r1, ma.r2); - mTemp.r1 = v_cross(ma.r2, ma.r0); - mTemp.r2 = v_cross(ma.r0, ma.r1); + float invDet = 1.0f / det; - // Determinant = dot(ma.r0, c0) - f32x4 det = v_dot3(ma.r0, mTemp.r0); - f32x4 invDet = v_rcp_nr(det); + d[0] = (m[5] * m[10] - m[6] * m[9]) * invDet; + d[1] = (m[9] * m[2] - m[10] * m[1]) * invDet; + d[2] = (m[1] * m[6] - m[2] * m[5]) * invDet; - // Scale cofactors - mTemp.r0 = v_mul(mTemp.r0, invDet); - mTemp.r1 = v_mul(mTemp.r1, invDet); - mTemp.r2 = v_mul(mTemp.r2, invDet); + d[4] = (m[6] * m[8] - m[4] * m[10]) * invDet; + d[5] = (m[10] * m[0] - m[8] * m[2]) * invDet; + d[6] = (m[2] * m[4] - m[0] * m[6]) * invDet; - // Store inverse 3x3 (transpose of cofactor matrix) + d[8] = (m[4] * m[9] - m[5] * m[8]) * invDet; + d[9] = (m[8] * m[1] - m[9] * m[0]) * invDet; + d[10] = (m[0] * m[5] - m[1] * m[4]) * invDet; - mTemp = m_transpose(mTemp); - mTemp.r3 = ma.r3; - - // ---- Translation ---- - - // Load original translation - f32x4 T = v_set(m[3], m[7], m[11], 0.0f); - - // Compute -(Tx*ma.r0 + Ty*ma.r1 + Tz*ma.r2) - f32x4 result = v_mul(ma.r0, v_swizzle_singular_mask(T, 0)); - result = v_add(result, v_mul(ma.r1, v_swizzle_singular_mask(T, 1))); - result = v_add(result, v_mul(ma.r2, v_swizzle_singular_mask(T, 2))); - result = v_mul(result, v_set1(-1.0f)); - - m_store(dst, mTemp); - - // Store translation - dst[3] = v_extract0(result); - dst[7] = v_extract0(v_swizzle_singular_mask(result, 1)); - dst[11] = v_extract0(v_swizzle_singular_mask(result, 2)); + // invert the translation + float temp[6]; + temp[0] = -m[3]; + temp[1] = -m[7]; + temp[2] = -m[11]; + mat44_mul_vec3_impl(d, temp, &temp[3]); + d[3] = temp[3]; + d[7] = temp[4]; + d[11] = temp[5]; + d[12] = m[12]; + d[13] = m[13]; + d[14] = m[14]; + d[15] = m[15]; } // Matrix Affine Inverse @@ -275,15 +310,6 @@ namespace math_backend::mat44 v_store3(r, vr); } - // Vector Multiply: m * v (assume w = 0.0f) - inline void mat44_mul_vec3_impl(const float* m, const float* v, float* r) - { - f32x4x4 ma = m_load(m); - f32x4 va = v_load3_vec(v); - f32x4 vr = m_mul_vec3(ma, va); - v_store3(r, vr); - } - // Vector Multiply: m * p (full [4x4] * [1x4]) inline void mat44_mul_float4_impl(const float* m, const float* p, float* r) { From ce8ee9462496df793171e0d52d497d2b3cb40320 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 17 Mar 2026 13:15:40 -0500 Subject: [PATCH 04/18] fix CI --- Tools/CMake/torque_macros.cmake | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Tools/CMake/torque_macros.cmake b/Tools/CMake/torque_macros.cmake index fe0cec4c6..ca1a65325 100644 --- a/Tools/CMake/torque_macros.cmake +++ b/Tools/CMake/torque_macros.cmake @@ -176,7 +176,27 @@ function(add_math_backend name compile_defs) elseif(name STREQUAL "avx2") target_compile_options(math_${name} PRIVATE -mavx2 -mfma) elseif(name STREQUAL "neon") - target_compile_options(math_${name} PRIVATE -march=armv8-a) + if(APPLE) + set_target_properties(math_${name} PROPERTIES OSX_ARCHITECTURES "arm64") + else() + target_compile_options(math_${name} PRIVATE -march=armv8-a) + endif() + endif() + endif() + + if(APPLE) + # ARM-only backend + if(name STREQUAL "neon") + set_target_properties(math_${name} PROPERTIES + OSX_ARCHITECTURES "arm64" + ) + endif() + + # x86-only backends + if(name MATCHES "sse2|sse41|avx|avx2") + set_target_properties(math_${name} PROPERTIES + OSX_ARCHITECTURES "x86_64" + ) endif() endif() From ff1b4d47e5c2961bf430e64686f83eb9161f2300 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 17 Mar 2026 14:04:54 -0500 Subject: [PATCH 05/18] further followups to CI compilation config --- Tools/CMake/torqueMacOSconfigs.cmake | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Tools/CMake/torqueMacOSconfigs.cmake b/Tools/CMake/torqueMacOSconfigs.cmake index 793771c13..1d3ba7fbc 100644 --- a/Tools/CMake/torqueMacOSconfigs.cmake +++ b/Tools/CMake/torqueMacOSconfigs.cmake @@ -9,22 +9,22 @@ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,") # minimum for multi arch build is 11. set(CMAKE_OSX_DEPLOYMENT_TARGET "11" CACHE STRING "" FORCE) -set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "" FORCE) +set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Architectures to build" FORCE) set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET[arch=arm64] "11.0" CACHE STRING "arm 64 minimum deployment target" FORCE) -if(CMAKE_OSX_ARCHITECTURES MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") - set(CMAKE_C_SIZEOF_DATA_PTR 8) - set(CMAKE_CXX_SIZEOF_DATA_PTR 8) - if(CMAKE_OSX_ARCHITECTURES MATCHES "((^|;|, )(arm64|arm64e))+") - set(CMAKE_SYSTEM_PROCESSOR "aarch64") - else() - set(CMAKE_SYSTEM_PROCESSOR "x86_64") - endif() -else() - set(CMAKE_C_SIZEOF_DATA_PTR 4) - set(CMAKE_CXX_SIZEOF_DATA_PTR 4) - set(CMAKE_SYSTEM_PROCESSOR "arm") -endif() +# if(CMAKE_OSX_ARCHITECTURES MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") +# set(CMAKE_C_SIZEOF_DATA_PTR 8) +# set(CMAKE_CXX_SIZEOF_DATA_PTR 8) +# if(CMAKE_OSX_ARCHITECTURES MATCHES "((^|;|, )(arm64|arm64e))+") +# set(CMAKE_SYSTEM_PROCESSOR "aarch64") +# else() +# set(CMAKE_SYSTEM_PROCESSOR "x86_64") +# endif() +# else() +# set(CMAKE_C_SIZEOF_DATA_PTR 4) +# set(CMAKE_CXX_SIZEOF_DATA_PTR 4) +# set(CMAKE_SYSTEM_PROCESSOR "arm") +# endif() # Enable codesigning with secure timestamp when not in Debug configuration (required for Notarization) set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS[variant=Release] "--timestamp") From 832d1afec4dfeec70b83be95669d61a242ceceac Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 17 Mar 2026 14:55:23 -0500 Subject: [PATCH 06/18] further followups to CI compilation config --- Engine/source/CMakeLists.txt | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index d439a06e2..2ca86a2f7 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -501,12 +501,23 @@ string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH) set(IS_X86 FALSE) set(IS_ARM FALSE) -if(ARCH MATCHES "x86_64|amd64|i[3-6]86") - set(IS_X86 TRUE) -endif() - -if(ARCH MATCHES "arm64|aarch64") - set(IS_ARM TRUE) +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Use the CMAKE_OSX_ARCHITECTURES list for universal builds + foreach(arch IN LISTS CMAKE_OSX_ARCHITECTURES) + if(arch STREQUAL "x86_64") + set(IS_X86 TRUE) + elseif(arch STREQUAL "arm64") + set(IS_ARM TRUE) + endif() + endforeach() +else() + # Non-macOS detection + if(ARCH MATCHES "arm64|aarch64") + set(IS_ARM TRUE) + endif() + if(ARCH MATCHES "x86_64|amd64|i[3-6]86") + set(IS_X86 TRUE) + endif() endif() # always available From 11d8df4866e2c04eb46d4a5a27589ed580d833aa Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 18 Mar 2026 19:32:37 -0500 Subject: [PATCH 07/18] matrix work --- Engine/source/math/impl/mat44_impl.inl | 283 +++++++++++++++---------- 1 file changed, 170 insertions(+), 113 deletions(-) diff --git a/Engine/source/math/impl/mat44_impl.inl b/Engine/source/math/impl/mat44_impl.inl index da6971d0d..e021b6fb1 100644 --- a/Engine/source/math/impl/mat44_impl.inl +++ b/Engine/source/math/impl/mat44_impl.inl @@ -15,8 +15,13 @@ namespace math_backend::mat44 inline float mat44_get_determinant(const float* m) { - f32x4x4 ma = m_load(m); - return v_extract0(m_determinant_affine(ma)); + f32x4 r0 = v_load3_vec(m + 0); // row0 xyz + f32x4 r1 = v_load3_vec(m + 4); // row1 xyz + f32x4 r2 = v_load3_vec(m + 8); // row2 xyz + + f32x4 c0 = v_cross(r1, r2); // cofactor for row0 + f32x4 det = v_dot3(r0, c0); // splatted determinant + return v_extract0(det); } // Matrix Scale: Float3 (assume w = 1.0f) @@ -32,51 +37,66 @@ namespace math_backend::mat44 m_store(m, ma); } - inline void mat44_transform_plane_impl(const float* m, const float* scale, const float* plane, float* plane_result) + inline void mat44_transform_plane_impl(const float* m, const float* s, const float* p, float* presult) { + f32x4 scale = v_load3_pos(s); + f32x4 invScale = v_div(v_set1(1.0f), scale); + + //-------------------------------------------------- + // Load affine 3x3 rows and translation + //-------------------------------------------------- + f32x4 row0 = v_load3_vec(m + 0); + f32x4 row1 = v_load3_vec(m + 4); + f32x4 row2 = v_load3_vec(m + 8); + f32x4 shear = v_set(m[3], m[7], m[11], 1.0); + + //-------------------------------------------------- + // Compute A, B, C = -dot(row, shear) + //-------------------------------------------------- + f32x4 A = v_mul(v_dot3(row0, shear), v_set1(-1.0f)); + f32x4 B = v_mul(v_dot3(row1, shear), v_set1(-1.0f)); + f32x4 C = v_mul(v_dot3(row2, shear), v_set1(-1.0f)); + + + f32x4x4 invTrMatrix; + invTrMatrix.r0 = v_set(m[0], m[1], m[2], v_extract0(A)); + invTrMatrix.r1 = v_set(m[4], m[5], m[6], v_extract0(B)); + invTrMatrix.r2 = v_set(m[8], m[9], m[10], v_extract0(C)); + invTrMatrix.r3 = v_set(0.0f, 0.0f, 0.0f, 1.0f); + + // Apply inverse scale to upper-left 3x3 + invTrMatrix.r0 = v_mul(invTrMatrix.r0, invScale); + invTrMatrix.r1 = v_mul(invTrMatrix.r1, invScale); + invTrMatrix.r2 = v_mul(invTrMatrix.r2, invScale); + + + f32x4 normal = v_load3_pos(p); // plane normal {x,y,z,1} + f32x4 point = v_mul(normal, v_set1(-p[3])); // point = -d * normal + + // Apply transform to normal + f32x4 normTransformed = m_mul_vec3(invTrMatrix, normal); + normTransformed = v_normalize3(normTransformed); + + // transform point with original + f32x4 scaleVec = v_load3_pos(s); // scale vector + f32x4 pointScaled = v_mul(point, scaleVec); + + pointScaled = v_insert_w(pointScaled, v_set1(1.0f)); + f32x4x4 M = m_load(m); + // Transform point + f32x4 pointTransformed = m_mul_vec4(M, pointScaled); - f32x4 plane_v = v_load(plane); - f32x4 scale_v = v_load3_vec(scale); - f32x4 invScale = v_rcp_nr(scale_v); + //-------------------------------------------------- + // Compute plane d = -dot(normal, transformedPoint) + //-------------------------------------------------- + f32x4 dp = v_dot3( pointTransformed, normTransformed); + float planeD = -v_extract0(dp); - // normal = plane.xyz - f32x4 normal = plane_v; - - // apply Inv(s) - normal = v_mul(normal, invScale); - - // multiply by Inv(Tr(m)) (only the rotation part matters) - f32x4 nx = v_mul(v_swizzle_singular_mask(normal, 0), M.r0); - f32x4 ny = v_mul(v_swizzle_singular_mask(normal, 1), M.r1); - f32x4 nz = v_mul(v_swizzle_singular_mask(normal, 2), M.r2); - - normal = v_add(v_add(nx, ny), nz); - - normal = v_normalize3(normal); - - // compute point on plane - float d = v_extract0(v_swizzle_singular_mask(plane_v, 3)); - - f32x4 point = v_mul(plane_v, v_set1(-d)); - point = v_preserve_w(point, v_set1(1.0f)); - - // apply scale - point = v_mul(point, scale_v); - - // transform point by matrix - point = m_mul_vec4(M, point); - - // compute new plane distance - float newD = -v_extract0(v_dot3(point, normal)); - - alignas(16) float n[4]; - v_store(n, normal); - - plane_result[0] = n[0]; - plane_result[1] = n[1]; - plane_result[2] = n[2]; - plane_result[3] = newD; + presult[0] = v_extract0(normTransformed); + presult[1] = v_extract0(v_swizzle_mask(normTransformed, 1, 1, 1, 1)); + presult[2] = v_extract0(v_swizzle_mask(normTransformed, 2, 2, 2, 2)); + presult[3] = planeD; } inline void mat44_get_scale_impl(const float* m, float* s) @@ -109,92 +129,138 @@ namespace math_backend::mat44 m_store(m, ma); } + // Vector Multiply: m * v (assume w = 0.0f) + inline void mat44_mul_vec3_impl(const float* m, const float* v, float* r) + { + f32x4x4 ma = m_load(m); + f32x4 va = v_load3_vec(v); + f32x4 vr = m_mul_vec3(ma, va); + v_store3(r, vr); + } + + // Matrix Inverse inline void mat44_inverse_impl(float* m) { - f32x4x4 ma = m_load(m); + //// using Cramers Rule find the Inverse + //// Minv = (1/det(M)) * adjoint(M) + f32x4 r0 = v_load3_vec(m + 0); // row 0: m00 m01 m02 + f32x4 r1 = v_load3_vec(m + 4); // row 1: m10 m11 m12 + f32x4 r2 = v_load3_vec(m + 8); // row 2: m20 m21 m22 + float det = mat44_get_determinant(m); + f32x4 invDet = v_set1(1.0f / det); - // Compute cofactors using cross products - f32x4x4 mTemp; - mTemp.r0 = v_cross(ma.r1, ma.r2); - mTemp.r1 = v_cross(ma.r2, ma.r0); - mTemp.r2 = v_cross(ma.r0, ma.r1); + f32x4x4 temp; - // Determinant = dot(ma.r0, c0) - f32x4 det = v_dot3(ma.r0, mTemp.r0); - f32x4 invDet = v_rcp_nr(det); + temp.r0 = v_set( + (m[5] * m[10] - m[6] * m[9]), + (m[9] * m[2] - m[10] * m[1]), + (m[1] * m[6] - m[2] * m[5]), + 0 + ); - // Scale cofactors - mTemp.r0 = v_mul(mTemp.r0, invDet); - mTemp.r1 = v_mul(mTemp.r1, invDet); - mTemp.r2 = v_mul(mTemp.r2, invDet); + temp.r1 = v_set( + (m[6] * m[8] - m[4] * m[10]), + (m[10] * m[0] - m[8] * m[2]), + (m[2] * m[4] - m[0] * m[6]), + 0 + ); - // Store inverse 3x3 (transpose of cofactor matrix) + temp.r2 = v_set( + (m[4] * m[9] - m[5] * m[8]), + (m[8] * m[1] - m[9] * m[0]), + (m[0] * m[5] - m[1] * m[4]), + 0 + ); - mTemp = m_transpose(mTemp); - mTemp.r3 = ma.r3; + temp.r0 = v_mul(temp.r0, invDet); + temp.r1 = v_mul(temp.r1, invDet); + temp.r2 = v_mul(temp.r2, invDet); - // ---- Translation ---- + // Compute new translation: -R^-1 * T + f32x4 t = v_set(m[3], m[7], m[11], 0.0f); // row-major: last element in row + f32x4 t_new; - // Load original translation - f32x4 T = v_set(m[3], m[7], m[11], 0.0f); - - // Compute -(Tx*ma.r0 + Ty*ma.r1 + Tz*ma.r2) - f32x4 result = v_mul(ma.r0, v_swizzle_singular_mask(T, 0)); - result = v_add(result, v_mul(ma.r1, v_swizzle_singular_mask(T, 1))); - result = v_add(result, v_mul(ma.r2, v_swizzle_singular_mask(T, 2))); - result = v_mul(result, v_set1(-1.0f)); + t_new = v_set( + -v_extract0(v_dot3(temp.r0, t)), + -v_extract0(v_dot3(temp.r1, t)), + -v_extract0(v_dot3(temp.r2, t)), + 0.0f + ); - m_store(m, mTemp); + // Store back rotation + m[0] = v_extract0(temp.r0); m[1] = v_extract0(v_swizzle_mask(temp.r0, 1, 1, 1, 1)); m[2] = v_extract0(v_swizzle_mask(temp.r0, 2, 2, 2, 2)); + m[4] = v_extract0(temp.r1); m[5] = v_extract0(v_swizzle_mask(temp.r1, 1, 1, 1, 1)); m[6] = v_extract0(v_swizzle_mask(temp.r1, 2, 2, 2, 2)); + m[8] = v_extract0(temp.r2); m[9] = v_extract0(v_swizzle_mask(temp.r2, 1, 1, 1, 1)); m[10] = v_extract0(v_swizzle_mask(temp.r2, 2, 2, 2, 2)); - // Store translation - m[3] = v_extract0(result); - m[7] = v_extract0(v_swizzle_singular_mask(result, 1)); - m[11] = v_extract0(v_swizzle_singular_mask(result, 2)); + // Store translation + m[3] = v_extract0(t_new); + m[7] = v_extract0(v_swizzle_mask(t_new, 1, 1, 1, 1)); + m[11] = v_extract0(v_swizzle_mask(t_new, 2, 2, 2, 2)); } // Matrix Inverse - inline void mat44_inverse_to_impl(const float* m, float* dst) + inline void mat44_inverse_to_impl(const float* m, float* d) { - f32x4x4 ma = m_load(m); + //// using Cramers Rule find the Inverse + //// Minv = (1/det(M)) * adjoint(M) + f32x4 r0 = v_load3_vec(m + 0); // row 0: m00 m01 m02 + f32x4 r1 = v_load3_vec(m + 4); // row 1: m10 m11 m12 + f32x4 r2 = v_load3_vec(m + 8); // row 2: m20 m21 m22 + float det = mat44_get_determinant(m); + f32x4 invDet = v_set1(1.0f / det); - // Compute cofactors using cross products - f32x4x4 mTemp; - mTemp.r0 = v_cross(ma.r1, ma.r2); - mTemp.r1 = v_cross(ma.r2, ma.r0); - mTemp.r2 = v_cross(ma.r0, ma.r1); + f32x4x4 temp; - // Determinant = dot(ma.r0, c0) - f32x4 det = v_dot3(ma.r0, mTemp.r0); - f32x4 invDet = v_rcp_nr(det); + temp.r0 = v_set( + (m[5] * m[10] - m[6] * m[9]), + (m[9] * m[2] - m[10] * m[1]), + (m[1] * m[6] - m[2] * m[5]), + 0 + ); - // Scale cofactors - mTemp.r0 = v_mul(mTemp.r0, invDet); - mTemp.r1 = v_mul(mTemp.r1, invDet); - mTemp.r2 = v_mul(mTemp.r2, invDet); + temp.r1 = v_set( + (m[6] * m[8] - m[4] * m[10]), + (m[10] * m[0] - m[8] * m[2]), + (m[2] * m[4] - m[0] * m[6]), + 0 + ); - // Store inverse 3x3 (transpose of cofactor matrix) + temp.r2 = v_set( + (m[4] * m[9] - m[5] * m[8]), + (m[8] * m[1] - m[9] * m[0]), + (m[0] * m[5] - m[1] * m[4]), + 0 + ); - mTemp = m_transpose(mTemp); - mTemp.r3 = ma.r3; + temp.r0 = v_mul(temp.r0, invDet); + temp.r1 = v_mul(temp.r1, invDet); + temp.r2 = v_mul(temp.r2, invDet); - // ---- Translation ---- + // Compute new translation: -R^-1 * T + f32x4 t = v_set(m[3], m[7], m[11], 0.0f); // row-major: last element in row + f32x4 t_new; - // Load original translation - f32x4 T = v_set(m[3], m[7], m[11], 0.0f); + t_new = v_set( + -v_extract0(v_dot3(temp.r0, t)), + -v_extract0(v_dot3(temp.r1, t)), + -v_extract0(v_dot3(temp.r2, t)), + 0.0f + ); - // Compute -(Tx*ma.r0 + Ty*ma.r1 + Tz*ma.r2) - f32x4 result = v_mul(ma.r0, v_swizzle_singular_mask(T, 0)); - result = v_add(result, v_mul(ma.r1, v_swizzle_singular_mask(T, 1))); - result = v_add(result, v_mul(ma.r2, v_swizzle_singular_mask(T, 2))); - result = v_mul(result, v_set1(-1.0f)); + // Store back rotation + d[0] = v_extract0(temp.r0); d[1] = v_extract0(v_swizzle_mask(temp.r0, 1, 1, 1, 1)); d[2] = v_extract0(v_swizzle_mask(temp.r0, 2, 2, 2, 2)); + d[4] = v_extract0(temp.r1); d[5] = v_extract0(v_swizzle_mask(temp.r1, 1, 1, 1, 1)); d[6] = v_extract0(v_swizzle_mask(temp.r1, 2, 2, 2, 2)); + d[8] = v_extract0(temp.r2); d[9] = v_extract0(v_swizzle_mask(temp.r2, 1, 1, 1, 1)); d[10] = v_extract0(v_swizzle_mask(temp.r2, 2, 2, 2, 2)); - m_store(dst, mTemp); - - // Store translation - dst[3] = v_extract0(result); - dst[7] = v_extract0(v_swizzle_singular_mask(result, 1)); - dst[11] = v_extract0(v_swizzle_singular_mask(result, 2)); + // Store translation + d[3] = v_extract0(t_new); + d[7] = v_extract0(v_swizzle_mask(t_new, 1, 1, 1, 1)); + d[11] = v_extract0(v_swizzle_mask(t_new, 2, 2, 2, 2)); + d[12] = m[12]; + d[13] = m[13]; + d[14] = m[14]; + d[15] = m[15]; } // Matrix Affine Inverse @@ -275,15 +341,6 @@ namespace math_backend::mat44 v_store3(r, vr); } - // Vector Multiply: m * v (assume w = 0.0f) - inline void mat44_mul_vec3_impl(const float* m, const float* v, float* r) - { - f32x4x4 ma = m_load(m); - f32x4 va = v_load3_vec(v); - f32x4 vr = m_mul_vec3(ma, va); - v_store3(r, vr); - } - // Vector Multiply: m * p (full [4x4] * [1x4]) inline void mat44_mul_float4_impl(const float* m, const float* p, float* r) { From 64ceec1060d11b1ca297c6035b268cb65352722d Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 18 Mar 2026 20:21:48 -0500 Subject: [PATCH 08/18] emtpy char* check correction --- Engine/source/gui/buttons/guiBitmapButtonCtrl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h index ec96e9344..5a5f56ee0 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h @@ -123,7 +123,7 @@ private: String mBitmapFile; public: void _setBitmap(StringTableEntry _in) { - if (_in == NULL || _in == StringTable->EmptyString() || _in == "") + if (_in == NULL || _in == StringTable->EmptyString() || _in[0] == '\0') { mBitmapAsset = NULL; mBitmapFile = ""; From decab9210b3a221335cfcd03ec520fa218169572 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 19 Mar 2026 10:04:23 -0500 Subject: [PATCH 09/18] add missing v_swizzle_mask --- Engine/source/math/isa/neon/neon_intrinsics.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Engine/source/math/isa/neon/neon_intrinsics.h b/Engine/source/math/isa/neon/neon_intrinsics.h index e118b1600..fdd291e48 100644 --- a/Engine/source/math/isa/neon/neon_intrinsics.h +++ b/Engine/source/math/isa/neon/neon_intrinsics.h @@ -59,6 +59,24 @@ namespace ); } + inline f32x4 v_swizzle_mask(f32x4 v, const int x, const int y, const int z, const int w) + { + uint8x16_t table = vreinterpretq_u8_f32(v); + + // Each float = 4 bytes, so build byte indices + uint8_t idx_data[16] = { + x * 4 + 0, x * 4 + 1, x * 4 + 2, x * 4 + 3, + y * 4 + 0, y * 4 + 1, y * 4 + 2, y * 4 + 3, + z * 4 + 0, z * 4 + 1, z * 4 + 2, z * 4 + 3, + w * 4 + 0, w * 4 + 1, w * 4 + 2, w * 4 + 3 + }; + + uint8x16_t idx = vld1q_u8(idx_data); + + uint8x16_t result = vqtbl1q_u8(table, idx); + return vreinterpretq_f32_u8(result); + } + inline f32x4 v_swizzle_singular_mask(f32x4 v, int x) { // base byte index of the float lane From 135f59ab8274ce00d2fe934916b3e6fa870ce97a Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 19 Mar 2026 11:01:20 -0500 Subject: [PATCH 10/18] Revert "add missing v_swizzle_mask" This reverts commit decab9210b3a221335cfcd03ec520fa218169572. --- Engine/source/math/isa/neon/neon_intrinsics.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Engine/source/math/isa/neon/neon_intrinsics.h b/Engine/source/math/isa/neon/neon_intrinsics.h index fdd291e48..e118b1600 100644 --- a/Engine/source/math/isa/neon/neon_intrinsics.h +++ b/Engine/source/math/isa/neon/neon_intrinsics.h @@ -59,24 +59,6 @@ namespace ); } - inline f32x4 v_swizzle_mask(f32x4 v, const int x, const int y, const int z, const int w) - { - uint8x16_t table = vreinterpretq_u8_f32(v); - - // Each float = 4 bytes, so build byte indices - uint8_t idx_data[16] = { - x * 4 + 0, x * 4 + 1, x * 4 + 2, x * 4 + 3, - y * 4 + 0, y * 4 + 1, y * 4 + 2, y * 4 + 3, - z * 4 + 0, z * 4 + 1, z * 4 + 2, z * 4 + 3, - w * 4 + 0, w * 4 + 1, w * 4 + 2, w * 4 + 3 - }; - - uint8x16_t idx = vld1q_u8(idx_data); - - uint8x16_t result = vqtbl1q_u8(table, idx); - return vreinterpretq_f32_u8(result); - } - inline f32x4 v_swizzle_singular_mask(f32x4 v, int x) { // base byte index of the float lane From f04f387bc43bbf3228a9651504bbdf18694ca136 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 19 Mar 2026 11:03:12 -0500 Subject: [PATCH 11/18] ditch general swizzle mask. use the singular --- Engine/source/math/impl/mat44_impl.inl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Engine/source/math/impl/mat44_impl.inl b/Engine/source/math/impl/mat44_impl.inl index e021b6fb1..3c47b2c8a 100644 --- a/Engine/source/math/impl/mat44_impl.inl +++ b/Engine/source/math/impl/mat44_impl.inl @@ -189,9 +189,9 @@ namespace math_backend::mat44 ); // Store back rotation - m[0] = v_extract0(temp.r0); m[1] = v_extract0(v_swizzle_mask(temp.r0, 1, 1, 1, 1)); m[2] = v_extract0(v_swizzle_mask(temp.r0, 2, 2, 2, 2)); - m[4] = v_extract0(temp.r1); m[5] = v_extract0(v_swizzle_mask(temp.r1, 1, 1, 1, 1)); m[6] = v_extract0(v_swizzle_mask(temp.r1, 2, 2, 2, 2)); - m[8] = v_extract0(temp.r2); m[9] = v_extract0(v_swizzle_mask(temp.r2, 1, 1, 1, 1)); m[10] = v_extract0(v_swizzle_mask(temp.r2, 2, 2, 2, 2)); + m[0] = v_extract0(temp.r0); m[1] = v_extract0(v_swizzle_singular_mask(temp.r0, 1)); m[2] = v_extract0(v_swizzle_singular_mask(temp.r0, 2)); + m[4] = v_extract0(temp.r1); m[5] = v_extract0(v_swizzle_singular_mask(temp.r1, 1)); m[6] = v_extract0(v_swizzle_singular_mask(temp.r1, 2)); + m[8] = v_extract0(temp.r2); m[9] = v_extract0(v_swizzle_singular_mask(temp.r2, 1)); m[10] = v_extract0(v_swizzle_singular_mask(temp.r2, 2)); // Store translation m[3] = v_extract0(t_new); @@ -249,14 +249,14 @@ namespace math_backend::mat44 ); // Store back rotation - d[0] = v_extract0(temp.r0); d[1] = v_extract0(v_swizzle_mask(temp.r0, 1, 1, 1, 1)); d[2] = v_extract0(v_swizzle_mask(temp.r0, 2, 2, 2, 2)); - d[4] = v_extract0(temp.r1); d[5] = v_extract0(v_swizzle_mask(temp.r1, 1, 1, 1, 1)); d[6] = v_extract0(v_swizzle_mask(temp.r1, 2, 2, 2, 2)); - d[8] = v_extract0(temp.r2); d[9] = v_extract0(v_swizzle_mask(temp.r2, 1, 1, 1, 1)); d[10] = v_extract0(v_swizzle_mask(temp.r2, 2, 2, 2, 2)); + d[0] = v_extract0(temp.r0); d[1] = v_extract0(v_swizzle_singular_mask(temp.r0, 1)); d[2] = v_extract0(v_swizzle_singular_mask(temp.r0, 2)); + d[4] = v_extract0(temp.r1); d[5] = v_extract0(v_swizzle_singular_mask(temp.r1, 1)); d[6] = v_extract0(v_swizzle_singular_mask(temp.r1, 2)); + d[8] = v_extract0(temp.r2); d[9] = v_extract0(v_swizzle_singular_mask(temp.r2, 1)); d[10] = v_extract0(v_swizzle_singular_mask(temp.r2, 2)); // Store translation d[3] = v_extract0(t_new); - d[7] = v_extract0(v_swizzle_mask(t_new, 1, 1, 1, 1)); - d[11] = v_extract0(v_swizzle_mask(t_new, 2, 2, 2, 2)); + d[7] = v_extract0(v_swizzle_singular_mask(t_new, 1)); + d[11] = v_extract0(v_swizzle_singular_mask(t_new, 2)); d[12] = m[12]; d[13] = m[13]; d[14] = m[14]; From 00057740758d86a4dc852fb18170aadc551e268c Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 19 Mar 2026 12:06:30 -0500 Subject: [PATCH 12/18] pick up missed strays --- Engine/source/math/impl/mat44_impl.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/source/math/impl/mat44_impl.inl b/Engine/source/math/impl/mat44_impl.inl index 3c47b2c8a..abe0e4cbb 100644 --- a/Engine/source/math/impl/mat44_impl.inl +++ b/Engine/source/math/impl/mat44_impl.inl @@ -94,8 +94,8 @@ namespace math_backend::mat44 float planeD = -v_extract0(dp); presult[0] = v_extract0(normTransformed); - presult[1] = v_extract0(v_swizzle_mask(normTransformed, 1, 1, 1, 1)); - presult[2] = v_extract0(v_swizzle_mask(normTransformed, 2, 2, 2, 2)); + presult[1] = v_extract0(v_swizzle_singular_mask(normTransformed, 1)); + presult[2] = v_extract0(v_swizzle_singular_mask(normTransformed, 2)); presult[3] = planeD; } @@ -195,8 +195,8 @@ namespace math_backend::mat44 // Store translation m[3] = v_extract0(t_new); - m[7] = v_extract0(v_swizzle_mask(t_new, 1, 1, 1, 1)); - m[11] = v_extract0(v_swizzle_mask(t_new, 2, 2, 2, 2)); + m[7] = v_extract0(v_swizzle_singular_mask(t_new, 1)); + m[11] = v_extract0(v_swizzle_singular_mask(t_new, 2)); } // Matrix Inverse From dbea2bc63621fe189c1b8afded6ed3d16187eabf Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 19 Mar 2026 13:45:17 -0500 Subject: [PATCH 13/18] supress oversenstivie apple-only check on the al side --- Tools/CMake/modules/openal.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tools/CMake/modules/openal.cmake b/Tools/CMake/modules/openal.cmake index 7bf8e4453..8e6ebe2c2 100644 --- a/Tools/CMake/modules/openal.cmake +++ b/Tools/CMake/modules/openal.cmake @@ -24,4 +24,7 @@ if(TORQUE_SFX_OPENAL) set(ALSOFT_UPDATE_BUILD_VERSION OFF CACHE BOOL "Update build Version" UPDATE) add_subdirectory("${TORQUE_LIB_ROOT_DIRECTORY}/openal-soft" ${TORQUE_LIB_TARG_DIRECTORY}/openal-soft EXCLUDE_FROM_ALL) + if(APPLE) + target_compile_options(OpenAL PRIVATE -Wno-error=undef) + endif() endif(TORQUE_SFX_OPENAL) From 46b912a481b61365263068dc28abcd93b595da36 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sun, 22 Mar 2026 11:47:20 -0500 Subject: [PATCH 14/18] ssao typofix hat tip: steve_yorkshire- https://discord.com/channels/358091480004558848/783127087820439582/1485316295888077020 --- .../BaseGame/game/core/postFX/scripts/SSAO/SSAOPostFx.tscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Templates/BaseGame/game/core/postFX/scripts/SSAO/SSAOPostFx.tscript b/Templates/BaseGame/game/core/postFX/scripts/SSAO/SSAOPostFx.tscript index c9a5bec3c..602243639 100644 --- a/Templates/BaseGame/game/core/postFX/scripts/SSAO/SSAOPostFx.tscript +++ b/Templates/BaseGame/game/core/postFX/scripts/SSAO/SSAOPostFx.tscript @@ -173,7 +173,7 @@ function PostEffectEditorInspector::toggleSSAOPostFx(%this) function SSAOPostFx::applyFromPreset(%this) { - if($PostFXManager::PostFX::Enable && $pref::PostFX::EnableSSAO) + if($PostFX::SSAOPostFx::Enabled && $pref::PostFX::EnableSSAO) %this.enable(); else %this.disable(); From 7d95bfdd0f4d30a9c979c4c37aa6f07495022453 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sun, 22 Mar 2026 16:26:43 -0500 Subject: [PATCH 15/18] fix particle editor from steve_yorkshire - https://discord.com/channels/358091480004558848/783127087820439582/1485388241224863848 --- .../scripts/particleParticleEditor.ed.tscript | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Templates/BaseGame/game/tools/particleEditor/scripts/particleParticleEditor.ed.tscript b/Templates/BaseGame/game/tools/particleEditor/scripts/particleParticleEditor.ed.tscript index e234ffa70..43dc020f0 100644 --- a/Templates/BaseGame/game/tools/particleEditor/scripts/particleParticleEditor.ed.tscript +++ b/Templates/BaseGame/game/tools/particleEditor/scripts/particleParticleEditor.ed.tscript @@ -173,15 +173,15 @@ function PE_ParticleEditor::updateParticle(%this, %propertyField, %value, %isSli function PE_ParticleEditor::setDirty( %this ) { - this.text = "*Particle"; - this.dirty = true; + %this.text = "*Particle"; + %this.dirty = true; if(!startsWith(%this-->PopupMenu.text, "*")) { %this-->PopupMenu.text = "*" @ %this-->PopupMenu.text; } - %particle = this.currParticle; + %particle = %this.currParticle; %filename = %particle.getFilename(); %editorFilename = "tools/particleEditor/scripts/particleParticleEditor.ed." @ $TorqueScriptFileExtension; @@ -211,17 +211,17 @@ function PE_ParticleEditor::setNotDirty( %this ) function PE_ParticleEditor::showNewDialog( %this, %replaceSlot ) { // Open a dialog if the current Particle is dirty - if( this.dirty ) + if( %this.dirty ) { toolsMessageBoxYesNoCancel("Save Particle Changes?", "Do you wish to save the changes made to the
current particle before changing the particle?", - "PE_ParticleEditor.saveParticle( " @ this.currParticle.getName() @ " ); PE_ParticleEditor.createParticle( " @ %replaceSlot @ " );", - "PE_ParticleEditor.saveParticleDialogDontSave( " @ this.currParticle.getName() @ " ); PE_ParticleEditor.createParticle( " @ %replaceSlot @ " );" + "PE_ParticleEditor.saveParticle( " @ %this.currParticle.getName() @ " ); PE_ParticleEditor.createParticle( " @ %replaceSlot @ " );", + "PE_ParticleEditor.saveParticleDialogDontSave( " @ %this.currParticle.getName() @ " ); PE_ParticleEditor.createParticle( " @ %replaceSlot @ " );" ); } else { - this.createParticle( %replaceSlot ); + %this.createParticle( %replaceSlot ); } } @@ -263,7 +263,7 @@ function PE_ParticleEditor::pickedNewParticleTargetModule( %this, %module ) ParticleEditorCreatePrompt.show("Particle", "ParticleData", "PE_ParticleEditor.doCreateNewParticle(\"" @ %module @ "\");" ); } -function PE_ParticleEditor::doCreateNewEmitter(%this, %module) +function PE_ParticleEditor::doCreateNewParticle(%this, %module) { //Sanity checks %newName = ParticleEditorCreatePrompt-->nameText.getText(); From 215830ca552b15a59847510dd587c7a400f99f98 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sun, 22 Mar 2026 21:31:39 -0500 Subject: [PATCH 16/18] fix decal editor bounds and decalmanager raycast we weren't accounting for texRects for decal atlases --- Engine/source/T3D/decal/decalManager.cpp | 12 +++++++----- Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp | 11 +++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Engine/source/T3D/decal/decalManager.cpp b/Engine/source/T3D/decal/decalManager.cpp index 1dc6ff236..7a21cd5e0 100644 --- a/Engine/source/T3D/decal/decalManager.cpp +++ b/Engine/source/T3D/decal/decalManager.cpp @@ -660,12 +660,14 @@ DecalInstance* DecalManager::raycast( const Point3F &start, const Point3F &end, RayInfo ri; bool containsPoint = false; if ( gServerContainer.castRayRendered( start, end, STATIC_COLLISION_TYPEMASK, &ri ) ) - { + { + RectF rect = inst->mDataBlock->texRect[inst->mTextureRectIdx]; + rect.extent *= inst->mSize * 0.5f; Point2F poly[4]; - poly[0].set( inst->mPosition.x - (inst->mSize / 2), inst->mPosition.y + (inst->mSize / 2)); - poly[1].set( inst->mPosition.x - (inst->mSize / 2), inst->mPosition.y - (inst->mSize / 2)); - poly[2].set( inst->mPosition.x + (inst->mSize / 2), inst->mPosition.y - (inst->mSize / 2)); - poly[3].set( inst->mPosition.x + (inst->mSize / 2), inst->mPosition.y + (inst->mSize / 2)); + poly[0].set(inst->mPosition.x - rect.extent.x, inst->mPosition.y + rect.extent.y); + poly[1].set( inst->mPosition.x - rect.extent.x, inst->mPosition.y - rect.extent.y); + poly[2].set( inst->mPosition.x + rect.extent.x, inst->mPosition.y - rect.extent.y); + poly[3].set( inst->mPosition.x + rect.extent.x, inst->mPosition.y + rect.extent.y); if ( MathUtils::pointInPolygon( poly, 4, Point2F(ri.point.x, ri.point.y) ) ) containsPoint = true; diff --git a/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp b/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp index abb778ca0..26d6f742a 100644 --- a/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp +++ b/Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp @@ -516,11 +516,12 @@ void GuiDecalEditorCtrl::renderScene(const RectI & updateRect) if ( gDecalManager->clipDecal( mSELDecal, &mSELEdgeVerts ) ) _renderDecalEdge( mSELEdgeVerts, ColorI( 255, 255, 255, 255 ) ); - const F32 &decalSize = mSELDecal->mSize; + const F32 &decalSize = mSELDecal->mSize * 0.5; Point3F boxSize( decalSize, decalSize, decalSize ); - MatrixF worldMat( true ); - mSELDecal->getWorldMatrix( &worldMat, true ); + mSELDecal->getWorldMatrix( &worldMat, true ); + RectF rect = mSELDecal->mDataBlock->texRect[mSELDecal->mTextureRectIdx]; + worldMat.scale(Point3F(rect.extent.x, rect.extent.y, 0.25f)); drawUtil->drawObjectBox( desc, boxSize, mSELDecal->mPosition, worldMat, ColorI( 255, 255, 255, 255 ) ); } @@ -531,11 +532,13 @@ void GuiDecalEditorCtrl::renderScene(const RectI & updateRect) if ( gDecalManager->clipDecal( mHLDecal, &mHLEdgeVerts ) ) _renderDecalEdge( mHLEdgeVerts, ColorI( 255, 255, 255, 255 ) ); - const F32 &decalSize = mHLDecal->mSize; + const F32 &decalSize = mHLDecal->mSize * 0.5; Point3F boxSize( decalSize, decalSize, decalSize ); MatrixF worldMat( true ); mHLDecal->getWorldMatrix( &worldMat, true ); + RectF rect = mHLDecal->mDataBlock->texRect[mHLDecal->mTextureRectIdx]; + worldMat.scale(Point3F(rect.extent.x, rect.extent.y, 0.25f)); drawUtil->drawObjectBox( desc, boxSize, mHLDecal->mPosition, worldMat, ColorI( 255, 255, 255, 255 ) ); } From 4a0a7d2b1006b7356e564a683823f789dbdf0076 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 23 Mar 2026 12:22:54 +0000 Subject: [PATCH 17/18] fix for hasaccumulation exception There is an exception on teardown usually during a debug build that is caused during shapeBase onRemove calling hasAccumulation. This fix reorders the hasAccumulation check to be before shapebase calls Parent::onRemove, and also hard sets the mMaterialList to NULL when setMaterialList is called --- Engine/source/T3D/shapeBase.cpp | 14 +++++++------- Engine/source/ts/tsShapeInstance.cpp | 8 +++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 96fadaf6e..44fe70382 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -1164,13 +1164,6 @@ void ShapeBase::onRemove() { mConvexList->nukeList(); - Parent::onRemove(); - - // Stop any running sounds on the client - if (isGhost()) - for (S32 i = 0; i < MaxSoundThreads; i++) - stopAudio(i); - // Accumulation and environment mapping if (isClientObject() && mShapeInstance) { @@ -1178,6 +1171,13 @@ void ShapeBase::onRemove() AccumulationVolume::removeObject(this); } + Parent::onRemove(); + + // Stop any running sounds on the client + if (isGhost()) + for (S32 i = 0; i < MaxSoundThreads; i++) + stopAudio(i); + if ( isClientObject() ) { if (mCubeReflector) diff --git a/Engine/source/ts/tsShapeInstance.cpp b/Engine/source/ts/tsShapeInstance.cpp index 2a7cb9c35..337e432fc 100644 --- a/Engine/source/ts/tsShapeInstance.cpp +++ b/Engine/source/ts/tsShapeInstance.cpp @@ -239,8 +239,11 @@ void TSShapeInstance::initMeshObjects() void TSShapeInstance::setMaterialList( TSMaterialList *matList ) { // get rid of old list - if ( mOwnMaterialList ) + if (mOwnMaterialList) + { delete mMaterialList; + mMaterialList = NULL; + } mMaterialList = matList; mOwnMaterialList = false; @@ -891,6 +894,9 @@ void TSShapeInstance::prepCollision() // Returns true is the shape contains any materials with accumulation enabled. bool TSShapeInstance::hasAccumulation() { + if (!mOwnMaterialList || mMaterialList == NULL) + return false; + bool result = false; for ( U32 i = 0; i < mMaterialList->size(); ++i ) { From a5e850b546da9e52f4b408e5309041a0210dcea0 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 23 Mar 2026 16:46:13 -0500 Subject: [PATCH 18/18] image asset popup augs create terrain texures asset context popup create Material context to spin up a mat --- .../scripts/assetTypes/image.tscript | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index 2b832d0ba..2df7b32da 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -127,6 +127,28 @@ function ImageAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat return false; } +function ImageAsset::makeMaterialFrom(%this) +{ + %matName = %this.assetName @ "_Mat"; + %assetLoc = AssetDatabase.getAssetPath(%this.getAssetId()) @"/"@ %this.assetName @"_Mat.asset.taml"; + %newMat = new Material(%matName) { + diffuseMapAsset[0] = %this.getAssetId(); + mapTo = %this.assetName; + }; + + %matAsset = new MaterialAsset() { + assetName = %matName; + materialDefinitionName = %matName; + }; + + %matAsset.add(%newMat); + + TamlWrite(%matAsset, expandPath(%assetLoc)); + AssetDatabase.addDeclaredAsset(AssetDatabase.getAssetModule(%this.getAssetId()), %assetLoc); + return %matAsset; +} + + function ImageAsset::onShowActionMenu(%this) { GenericAsset::onShowActionMenu(%this); @@ -134,6 +156,8 @@ function ImageAsset::onShowActionMenu(%this) %assetId = %this.getAssetId(); EditAssetPopup.setItemPosition("Create Composite Texture" TAB "" TAB "CompositeTextureEditor.buildComposite(\"" @ %assetId @ "\");", 4); + EditAssetPopup.setItemPosition("Create Terrain Textures" TAB "" TAB "makeTerrainMapsFrom(\"" @ %assetId @ "\");", 5); + EditAssetPopup.setItemPosition("Create Material" TAB "" TAB %this @ ".makeMaterialFrom();", 6); EditAssetPopup.objectData = %assetId; EditAssetPopup.objectType = AssetDatabase.getAssetType(%assetId);