Browse Source

Add glm::abs() function for the glm::mat<> class

This is added as part of the GLM_EXT_matrix_common extension, as this
function is not provided by the core GLSL specification (version 4.20).

The implementation of this glm::abs(mat<>) function mirrors the
glm::abs(vec<>) implementation. It should be functionning the same in
every way as the vec implementation.

Bonus points : AFAICT this allows to vectorize operations on compilers
that support optimization of these patterns, just like the functor1<>
struct in _vectorize.hpp for vectors.
Thibault de Villèle [UM] 3 years ago
parent
commit
48e1ff3fee

+ 128 - 0
glm/ext/_matrix_vectorize.hpp

@@ -0,0 +1,128 @@
+#pragma once
+
+namespace glm {
+
+	namespace detail {
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, length_t C, length_t R, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1 {
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 2, 2, Ret, T, Q> {
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 2, T, Q> call(Ret (*Func)(T x), mat<2, 2, T, Q> const &x) {
+				return mat<2, 2, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]),
+					Func(x[1][0]), Func(x[1][1])
+				);
+			}
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 2, 3, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 3, T, Q> call(Ret (*Func)(T x), mat<2, 3, T, Q> const &x) {
+				return mat<2, 3, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]),
+					Func(x[1][0]), Func(x[1][1]),
+					Func(x[2][0]), Func(x[2][1])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 2, 4, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 4, T, Q> call(Ret (*Func)(T x), mat<2, 4, T, Q> const &x) {
+				return mat<2, 4, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]),
+					Func(x[1][0]), Func(x[1][1]),
+					Func(x[2][0]), Func(x[2][1]),
+					Func(x[3][0]), Func(x[3][1])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 3, 2, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 2, T, Q> call(Ret (*Func)(T x), mat<3, 2, T, Q> const &x) {
+				return mat<3, 2, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 3, 3, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 3, T, Q> call(Ret (*Func)(T x), mat<3, 3, T, Q> const &x) {
+				return mat<3, 3, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2]),
+					Func(x[2][0]), Func(x[2][1]), Func(x[2][2])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 3, 4, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 4, T, Q> call(Ret (*Func)(T x), mat<3, 4, T, Q> const &x) {
+				return mat<3, 4, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2]),
+					Func(x[2][0]), Func(x[2][1]), Func(x[2][2]),
+					Func(x[3][0]), Func(x[3][1]), Func(x[3][2])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 4, 2, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 2, T, Q> call(Ret (*Func)(T x), mat<4, 2, T, Q> const &x) {
+				return mat<4, 2, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 4, 3, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 3, T, Q> call(Ret (*Func)(T x), mat<4, 3, T, Q> const &x) {
+				return mat<4, 3, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3]),
+					Func(x[2][0]), Func(x[2][1]), Func(x[2][2]), Func(x[2][3])
+				);
+			}
+
+		};
+
+		template<template<length_t C, length_t R, typename T, qualifier Q> class mat, typename Ret, typename T, qualifier Q>
+		struct matrix_functor_1<mat, 4, 4, Ret, T, Q> {
+
+			GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 4, T, Q> call(Ret (*Func)(T x), mat<4, 4, T, Q> const &x) {
+				return mat<4, 4, Ret, Q>(
+					Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]),
+					Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3]),
+					Func(x[2][0]), Func(x[2][1]), Func(x[2][2]), Func(x[2][3]),
+					Func(x[3][0]), Func(x[3][1]), Func(x[3][2]), Func(x[3][3])
+				);
+			}
+
+		};
+
+	}
+
+}// namespace glm

+ 3 - 0
glm/ext/matrix_common.hpp

@@ -30,6 +30,9 @@ namespace glm
 	template<length_t C, length_t R, typename T, typename U, qualifier Q>
 	template<length_t C, length_t R, typename T, typename U, qualifier Q>
 	GLM_FUNC_DECL mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, U a);
 	GLM_FUNC_DECL mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, U a);
 
 
+	template <length_t C, length_t R, typename T, qualifier Q>
+	GLM_FUNC_DECL GLM_CONSTEXPR mat<C, R, T, Q> abs(mat<C, R, T, Q> const& x);
+
 	/// @}
 	/// @}
 }//namespace glm
 }//namespace glm
 
 

+ 18 - 0
glm/ext/matrix_common.inl

@@ -1,5 +1,7 @@
 #include "../matrix.hpp"
 #include "../matrix.hpp"
 
 
+#include "_matrix_vectorize.hpp"
+
 namespace glm
 namespace glm
 {
 {
 	template<length_t C, length_t R, typename T, typename U, qualifier Q>
 	template<length_t C, length_t R, typename T, typename U, qualifier Q>
@@ -13,4 +15,20 @@ namespace glm
 	{
 	{
 		return matrixCompMult(mat<C, R, U, Q>(x), static_cast<U>(1) - a) + matrixCompMult(mat<C, R, U, Q>(y), a);
 		return matrixCompMult(mat<C, R, U, Q>(x), static_cast<U>(1) - a) + matrixCompMult(mat<C, R, U, Q>(y), a);
 	}
 	}
+
+	template<length_t C, length_t R, typename T, qualifier Q, bool Aligned>
+	struct compute_abs_matrix
+	{
+		GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<C, R, T, Q> call(mat<C, R, T, Q> const& x)
+		{
+			return detail::matrix_functor_1<mat, C, R, T, T, Q>::call(abs, x);
+		}
+	};
+
+	template<length_t C, length_t R, typename T, qualifier Q>
+	GLM_FUNC_DECL GLM_CONSTEXPR mat<C, R, T, Q> abs(mat<C, R, T, Q> const& x)
+	{
+		return compute_abs_matrix<C, R, T, Q, detail::is_aligned<Q>::value>::call(x);
+	}
+
 }//namespace glm
 }//namespace glm

+ 30 - 0
test/ext/ext_matrix_common.cpp

@@ -43,11 +43,41 @@ static int test_mix()
 	return Error;
 	return Error;
 }
 }
 
 
+static int test_abs()
+{
+	int Error = 0;
+
+	{
+		glm::mat4 A(
+			3.0f, 1.0f, 5.2f, 4.9f,
+			1.4f, 0.5f, 9.3f, 3.7f,
+			6.8f, 8.4f, 4.3f, 3.9f,
+			5.6f, 7.2f, 1.1f, 4.4f
+		);
+		glm::mat4 B(
+			 1.0,-1.0, 1.0, 1.0,
+			-1.0, 1.0, 1.0,-1.0,
+			 1.0,-1.0,-1.0,-1.0,
+			-1.0,-1.0, 1.0, 1.0
+		);
+		glm::mat4 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product.
+		glm::mat4 D = glm::abs(C);
+		glm::bvec4 const row1 = glm::equal(D[0], A[0]);
+		glm::bvec4 const row2 = glm::equal(D[1], A[1]);
+		glm::bvec4 const row3 = glm::equal(D[2], A[2]);
+		glm::bvec4 const row4 = glm::equal(D[3], A[3]);
+		Error += glm::all(glm::bvec4{glm::all(row1), glm::all(row2), glm::all(row3), glm::all(row4)}) ? 0 : 1;
+
+		return Error;
+	}
+}
+
 int main()
 int main()
 {
 {
 	int Error = 0;
 	int Error = 0;
 
 
 	Error += test_mix();
 	Error += test_mix();
+	Error += test_abs();
 
 
 	return Error;
 	return Error;
 }
 }