diff --git a/include/ui/TMatHelpers.h b/include/ui/TMatHelpers.h new file mode 100644 index 000000000..b778af0ff --- /dev/null +++ b/include/ui/TMatHelpers.h @@ -0,0 +1,179 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TMAT_IMPLEMENTATION +#error "Don't include TMatHelpers.h directly. use ui/mat*.h instead" +#else +#undef TMAT_IMPLEMENTATION +#endif + + +#ifndef UI_TMAT_HELPERS_H +#define UI_TMAT_HELPERS_H + +#include +#include +#include +#include + +#define PURE __attribute__((pure)) + +namespace android { +// ------------------------------------------------------------------------------------- + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include ui/mat*.h + */ + + +/* + * Matrix utilities + */ + +namespace matrix { + +inline int PURE transpose(int v) { return v; } +inline float PURE transpose(float v) { return v; } +inline double PURE transpose(double v) { return v; } + +inline int PURE trace(int v) { return v; } +inline float PURE trace(float v) { return v; } +inline double PURE trace(double v) { return v; } + +template +MATRIX PURE inverse(const MATRIX& src) { + + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::COL_SIZE == MATRIX::ROW_SIZE ); + + typename MATRIX::value_type t; + const size_t N = MATRIX::col_size(); + size_t swap; + MATRIX tmp(src); + MATRIX inverse(1); + + for (size_t i=0 ; i fabs(tmp[i][i])) { + swap = j; + } + } + + if (swap != i) { + /* swap rows. */ + for (size_t k=0 ; k +MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { + // pre-requisite: + // lhs : D columns, R rows + // rhs : C columns, D rows + // res : C columns, R rows + + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_A::ROW_SIZE == MATRIX_B::COL_SIZE ); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::ROW_SIZE == MATRIX_B::ROW_SIZE ); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX_R::COL_SIZE == MATRIX_A::COL_SIZE ); + + MATRIX_R res(MATRIX_R::NO_INIT); + for (size_t r=0 ; r +MATRIX PURE transpose(const MATRIX& m) { + // for now we only handle square matrix transpose + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); + MATRIX result(MATRIX::NO_INIT); + for (size_t r=0 ; r +typename MATRIX::value_type PURE trace(const MATRIX& m) { + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); + typename MATRIX::value_type result(0); + for (size_t r=0 ; r +typename MATRIX::col_type PURE diag(const MATRIX& m) { + COMPILE_TIME_ASSERT_FUNCTION_SCOPE( MATRIX::ROW_SIZE == MATRIX::COL_SIZE ); + typename MATRIX::col_type result(MATRIX::col_type::NO_INIT); + for (size_t r=0 ; r +String8 asString(const MATRIX& m) { + String8 s; + for (size_t c=0 ; c +#include + +#define PURE __attribute__((pure)) + +namespace android { +// ------------------------------------------------------------------------------------- + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include ui/vec{2|3|4}.h + */ + +/* + * This class casts itself into anything and assign itself from anything! + * Use with caution! + */ +template +struct Impersonator { + Impersonator& operator = (const TYPE& rhs) { + reinterpret_cast(*this) = rhs; + return *this; + } + operator TYPE& () { + return reinterpret_cast(*this); + } + operator TYPE const& () const { + return reinterpret_cast(*this); + } +}; + +/* + * TVecArithmeticOperators implements basic arithmetic and basic compound assignments + * operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecArithmeticOperators BASE will automatically + * get all the functionality here. + */ + +template class BASE, typename T> +class TVecArithmeticOperators { +public: + /* compound assignment from a another vector of the same size but different + * element type. + */ + template + BASE& operator += (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] += v[i]; + } + return rhs; + } + template + BASE& operator -= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] -= v[i]; + } + return rhs; + } + template + BASE& operator *= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] *= v[i]; + } + return rhs; + } + template + BASE& operator /= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] /= v[i]; + } + return rhs; + } + + /* compound assignment from a another vector of the same type. + * These operators can be used for implicit conversion and handle operations + * like "vector *= scalar" by letting the compiler implicitly convert a scalar + * to a vector (assuming the BASE allows it). + */ + BASE& operator += (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] += v[i]; + } + return rhs; + } + BASE& operator -= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] -= v[i]; + } + return rhs; + } + BASE& operator *= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] *= v[i]; + } + return rhs; + } + BASE& operator /= (const BASE& v) { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + rhs[i] /= v[i]; + } + return rhs; + } + + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + /* The operators below handle operation between vectors of the same side + * but of a different element type. + */ + template + friend inline + BASE PURE operator +(const BASE& lv, const BASE& rv) { + return BASE(lv) += rv; + } + template + friend inline + BASE PURE operator -(const BASE& lv, const BASE& rv) { + return BASE(lv) -= rv; + } + template + friend inline + BASE PURE operator *(const BASE& lv, const BASE& rv) { + return BASE(lv) *= rv; + } + template + friend inline + BASE PURE operator /(const BASE& lv, const BASE& rv) { + return BASE(lv) /= rv; + } + + /* The operators below (which are not templates once this class is instanced, + * i.e.: BASE is known) can be used for implicit conversion on both sides. + * These handle operations like "vector * scalar" and "scalar * vector" by + * letting the compiler implicitly convert a scalar to a vector (assuming + * the BASE allows it). + */ + friend inline + BASE PURE operator +(const BASE& lv, const BASE& rv) { + return BASE(lv) += rv; + } + friend inline + BASE PURE operator -(const BASE& lv, const BASE& rv) { + return BASE(lv) -= rv; + } + friend inline + BASE PURE operator *(const BASE& lv, const BASE& rv) { + return BASE(lv) *= rv; + } + friend inline + BASE PURE operator /(const BASE& lv, const BASE& rv) { + return BASE(lv) /= rv; + } +}; + +/* + * TVecUnaryOperators implements unary operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecUnaryOperators BASE will automatically + * get all the functionality here. + * + * These operators are implemented as friend functions of TVecUnaryOperators + */ +template class BASE, typename T> +class TVecUnaryOperators { +public: + BASE& operator ++ () { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + ++rhs[i]; + } + return rhs; + } + BASE& operator -- () { + BASE& rhs = static_cast&>(*this); + for (size_t i=0 ; i::size() ; i++) { + --rhs[i]; + } + return rhs; + } + BASE operator - () const { + BASE r(BASE::NO_INIT); + BASE const& rv(static_cast const&>(*this)); + for (size_t i=0 ; i::size() ; i++) { + r[i] = -rv[i]; + } + return r; + } +}; + + +/* + * TVecComparisonOperators implements relational/comparison operators + * on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecComparisonOperators BASE will automatically + * get all the functionality here. + */ +template class BASE, typename T> +class TVecComparisonOperators { +public: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend inline + bool PURE operator ==(const BASE& lv, const BASE& rv) { + for (size_t i = 0; i < BASE::size(); i++) + if (lv[i] != rv[i]) + return false; + return true; + } + + template + friend inline + bool PURE operator !=(const BASE& lv, const BASE& rv) { + return !operator ==(lv, rv); + } + + template + friend inline + bool PURE operator >(const BASE& lv, const BASE& rv) { + for (size_t i = 0; i < BASE::size(); i++) + if (lv[i] <= rv[i]) + return false; + return true; + } + + template + friend inline + bool PURE operator <=(const BASE& lv, const BASE& rv) { + return !(lv > rv); + } + + template + friend inline + bool PURE operator <(const BASE& lv, const BASE& rv) { + for (size_t i = 0; i < BASE::size(); i++) + if (lv[i] >= rv[i]) + return false; + return true; + } + + template + friend inline + bool PURE operator >=(const BASE& lv, const BASE& rv) { + return !(lv < rv); + } +}; + + +/* + * TVecFunctions implements functions on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecFunctions BASE will automatically + * get all the functionality here. + */ +template class BASE, typename T> +class TVecFunctions { +public: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend inline + T PURE dot(const BASE& lv, const BASE& rv) { + T r(0); + for (size_t i = 0; i < BASE::size(); i++) + r += lv[i]*rv[i]; + return r; + } + + friend inline + T PURE length(const BASE& lv) { + return sqrt( dot(lv, lv) ); + } + + template + friend inline + T PURE distance(const BASE& lv, const BASE& rv) { + return length(rv - lv); + } + + friend inline + BASE PURE normalize(const BASE& lv) { + return lv * (1 / length(lv)); + } +}; + +#undef PURE + +// ------------------------------------------------------------------------------------- +}; // namespace android + + +#endif /* UI_TVEC_HELPERS_H */ diff --git a/include/ui/mat4.h b/include/ui/mat4.h new file mode 100644 index 000000000..08a67c7a1 --- /dev/null +++ b/include/ui/mat4.h @@ -0,0 +1,473 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UI_MAT4_H +#define UI_MAT4_H + +#include +#include + +#include +#include + +#define TMAT_IMPLEMENTATION +#include + +#define PURE __attribute__((pure)) + +namespace android { +// ------------------------------------------------------------------------------------- + +template +class tmat44 : public TVecUnaryOperators, + public TVecComparisonOperators +{ +public: + enum no_init { NO_INIT }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef tvec4 col_type; + typedef tvec4 row_type; + + // size of a column (i.e.: number of rows) + enum { COL_SIZE = col_type::SIZE }; + static inline size_t col_size() { return COL_SIZE; } + + // size of a row (i.e.: number of columns) + enum { ROW_SIZE = row_type::SIZE }; + static inline size_t row_size() { return ROW_SIZE; } + static inline size_t size() { return row_size(); } // for TVec*<> + +private: + + /* + * <-- N columns --> + * + * a00 a10 a20 ... aN0 ^ + * a01 a11 a21 ... aN1 | + * a02 a12 a22 ... aN2 M rows + * ... | + * a0M a1M a2M ... aNM v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [a00 a01 a02 ... a01M] + */ + + col_type mValue[ROW_SIZE]; + +public: + // array access + inline col_type const& operator [] (size_t i) const { return mValue[i]; } + inline col_type& operator [] (size_t i) { return mValue[i]; } + + T const* asArray() const { return &mValue[0][0]; } + + // ----------------------------------------------------------------------- + // we don't provide copy-ctor and operator= on purpose + // because we want the compiler generated versions + + /* + * constructors + */ + + // leaves object uninitialized. use with caution. + explicit tmat44(no_init) { } + + // initialize to identity + tmat44(); + + // initialize to Identity*scalar. + template + explicit tmat44(U v); + + // sets the diagonal to the passed vector + template + explicit tmat44(const tvec4& rhs); + + // construct from another matrix of the same size + template + explicit tmat44(const tmat44& rhs); + + // construct from 4 column vectors + template + tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3); + + // construct from a C array + template + explicit tmat44(U const* rawArray); + + /* + * helpers + */ + + static tmat44 ortho(T left, T right, T bottom, T top, T near, T far); + + static tmat44 frustum(T left, T right, T bottom, T top, T near, T far); + + template + static tmat44 lookAt(const tvec3& eye, const tvec3& center, const tvec3& up); + + template + static tmat44 translate(const tvec4& t); + + template + static tmat44 scale(const tvec4& s); + + template + static tmat44 rotate(A radian, const tvec3& about); + + + /* + * Compound assignment arithmetic operators + */ + + // add another matrix of the same size + template + tmat44& operator += (const tmat44& v); + + // subtract another matrix of the same size + template + tmat44& operator -= (const tmat44& v); + + // multiply by a scalar + template + tmat44& operator *= (U v); + + // divide by a scalar + template + tmat44& operator /= (U v); + + /* + * debugging + */ + + String8 asString() const; +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +/* + * Since the matrix code could become pretty big quickly, we don't inline most + * operations. + */ + +template +tmat44::tmat44() { + mValue[0] = col_type(1,0,0,0); + mValue[1] = col_type(0,1,0,0); + mValue[2] = col_type(0,0,1,0); + mValue[3] = col_type(0,0,0,1); +} + +template +template +tmat44::tmat44(U v) { + mValue[0] = col_type(v,0,0,0); + mValue[1] = col_type(0,v,0,0); + mValue[2] = col_type(0,0,v,0); + mValue[3] = col_type(0,0,0,v); +} + +template +template +tmat44::tmat44(const tvec4& v) { + mValue[0] = col_type(v.x,0,0,0); + mValue[1] = col_type(0,v.y,0,0); + mValue[2] = col_type(0,0,v.z,0); + mValue[3] = col_type(0,0,0,v.w); +} + +template +template +tmat44::tmat44(const tmat44& rhs) { + for (size_t r=0 ; r +template +tmat44::tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3) { + mValue[0] = v0; + mValue[1] = v1; + mValue[2] = v2; + mValue[3] = v3; +} + +template +template +tmat44::tmat44(U const* rawArray) { + for (size_t r=0 ; r +tmat44 tmat44::ortho(T left, T right, T bottom, T top, T near, T far) { + tmat44 m; + m[0][0] = 2 / (right - left); + m[1][1] = 2 / (top - bottom); + m[2][2] = -2 / (far - near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far - near); + return m; +} + +template +tmat44 tmat44::frustum(T left, T right, T bottom, T top, T near, T far) { + tmat44 m; + T A = (right + left) / (right - left); + T B = (top + bottom) / (top - bottom); + T C = (far + near) / (far - near); + T D = (2 * far * near) / (far - near); + m[0][0] = (2 * near) / (right - left); + m[1][1] = (2 * near) / (top - bottom); + m[2][0] = A; + m[2][1] = B; + m[2][2] = C; + m[2][3] =-1; + m[3][2] = D; + m[3][3] = 0; + return m; +} + +template +template +tmat44 tmat44::lookAt(const tvec3& eye, const tvec3& center, const tvec3& up) { + tvec3 L(normalize(center - eye)); + tvec3 S(normalize( cross(L, up) )); + tvec3 U(cross(S, L)); + return tmat44( + tvec4( S, 0), + tvec4( U, 0), + tvec4(-L, 0), + tvec4(-eye, 1)); +} + +template +template +tmat44 tmat44::translate(const tvec4& t) { + tmat44 r; + r[3] = t; + return r; +} + +template +template +tmat44 tmat44::scale(const tvec4& s) { + tmat44 r; + r[0][0] = s[0]; + r[1][1] = s[1]; + r[2][2] = s[2]; + r[3][3] = s[3]; + return r; +} + +template +template +tmat44 tmat44::rotate(A radian, const tvec3& about) { + tmat44 rotation; + T* r = const_cast(rotation.asArray()); + T c = cos(radian); + T s = sin(radian); + if (about.x==1 && about.y==0 && about.z==0) { + r[5] = c; r[10]= c; + r[6] = s; r[9] = -s; + } else if (about.x==0 && about.y==1 && about.z==0) { + r[0] = c; r[10]= c; + r[8] = s; r[2] = -s; + } else if (about.x==0 && about.y==0 && about.z==1) { + r[0] = c; r[5] = c; + r[1] = s; r[4] = -s; + } else { + tvec3 nabout = normalize(about); + B x = nabout.x; + B y = nabout.y; + B z = nabout.z; + T nc = 1 - c; + T xy = x * y; + T yz = y * z; + T zx = z * x; + T xs = x * s; + T ys = y * s; + T zs = z * s; + r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys; + r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs; + r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c; + } +} + +// ---------------------------------------------------------------------------------------- +// Compound assignment arithmetic operators +// ---------------------------------------------------------------------------------------- + +template +template +tmat44& tmat44::operator += (const tmat44& v) { + for (size_t r=0 ; r +template +tmat44& tmat44::operator -= (const tmat44& v) { + for (size_t r=0 ; r +template +tmat44& tmat44::operator *= (U v) { + for (size_t r=0 ; r +template +tmat44& tmat44::operator /= (U v) { + for (size_t r=0 ; r +tmat44 PURE operator +(const tmat44& lhs, const tmat44& rhs) { + tmat44 result(tmat44::NO_INIT); + for (size_t r=0 ; r::row_size() ; r++) + result[r] = lhs[r] + rhs[r]; + return result; +} + +// matrix - matrix, result is a matrix of the same type than the lhs matrix +template +tmat44 PURE operator -(const tmat44& lhs, const tmat44& rhs) { + tmat44 result(tmat44::NO_INIT); + for (size_t r=0 ; r::row_size() ; r++) + result[r] = lhs[r] - rhs[r]; + return result; +} + +// matrix * vector, result is a vector of the same type than the input vector +template +typename tmat44::col_type PURE operator *(const tmat44& lv, const tvec4& rv) { + typename tmat44::col_type result; + for (size_t r=0 ; r::row_size() ; r++) + result += rv[r]*lv[r]; + return result; +} + +// vector * matrix, result is a vector of the same type than the input vector +template +typename tmat44::row_type PURE operator *(const tvec4& rv, const tmat44& lv) { + typename tmat44::row_type result(tmat44::row_type::NO_INIT); + for (size_t r=0 ; r::row_size() ; r++) + result[r] = dot(rv, lv[r]); + return result; +} + +// matrix * scalar, result is a matrix of the same type than the input matrix +template +tmat44 PURE operator *(const tmat44& lv, U rv) { + tmat44 result(tmat44::NO_INIT); + for (size_t r=0 ; r::row_size() ; r++) + result[r] = lv[r]*rv; + return result; +} + +// scalar * matrix, result is a matrix of the same type than the input matrix +template +tmat44 PURE operator *(U rv, const tmat44& lv) { + tmat44 result(tmat44::NO_INIT); + for (size_t r=0 ; r::row_size() ; r++) + result[r] = lv[r]*rv; + return result; +} + +// matrix * matrix, result is a matrix of the same type than the lhs matrix +template +tmat44 PURE operator *(const tmat44& lhs, const tmat44& rhs) { + return matrix::multiply< tmat44 >(lhs, rhs); +} + +// ---------------------------------------------------------------------------------------- +// Functions +// ---------------------------------------------------------------------------------------- + +// inverse a matrix +template +tmat44 PURE inverse(const tmat44& m) { + return matrix::inverse(m); +} + +template +tmat44 PURE transpose(const tmat44& m) { + return matrix::transpose(m); +} + +template +T PURE trace(const tmat44& m) { + return matrix::trace(m); +} + +template +tvec4 PURE diag(const tmat44& m) { + return matrix::diag(m); +} + +// ---------------------------------------------------------------------------------------- +// Debugging +// ---------------------------------------------------------------------------------------- + +template +String8 tmat44::asString() const { + return matrix::asString(*this); +} + +// ---------------------------------------------------------------------------------------- + +typedef tmat44 mat4; + +// ---------------------------------------------------------------------------------------- +}; // namespace android + +#undef PURE + +#endif /* UI_MAT4_H */ diff --git a/include/ui/vec2.h b/include/ui/vec2.h new file mode 100644 index 000000000..b4edfc67d --- /dev/null +++ b/include/ui/vec2.h @@ -0,0 +1,85 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UI_VEC2_H +#define UI_VEC2_H + +#include +#include + +#define TVEC_IMPLEMENTATION +#include + +namespace android { +// ------------------------------------------------------------------------------------- + +template +class tvec2 : public TVecArithmeticOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions +{ +public: + enum no_init { NO_INIT }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + + union { + struct { T x, y; }; + struct { T s, t; }; + struct { T r, g; }; + }; + + enum { SIZE = 2 }; + inline static size_type size() { return SIZE; } + + // array access + inline T const& operator [] (size_t i) const { return (&x)[i]; } + inline T& operator [] (size_t i) { return (&x)[i]; } + + // ----------------------------------------------------------------------- + // we don't provide copy-ctor and operator= on purpose + // because we want the compiler generated versions + + // constructors + + // leaves object uninitialized. use with caution. + explicit tvec2(no_init) { } + + // default constructor + tvec2() : x(0), y(0) { } + + // handles implicit conversion to a tvec4. must not be explicit. + template + tvec2(A v) : x(v), y(v) { } + + template + tvec2(A x, B y) : x(x), y(y) { } + + template + explicit tvec2(const tvec2& v) : x(v.x), y(v.y) { } +}; + +// ---------------------------------------------------------------------------------------- + +typedef tvec2 vec2; + +// ---------------------------------------------------------------------------------------- +}; // namespace android + +#endif /* UI_VEC4_H */ diff --git a/include/ui/vec3.h b/include/ui/vec3.h new file mode 100644 index 000000000..591b8b284 --- /dev/null +++ b/include/ui/vec3.h @@ -0,0 +1,106 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UI_VEC3_H +#define UI_VEC3_H + +#include +#include + +#include + +namespace android { +// ------------------------------------------------------------------------------------- + +template +class tvec3 : public TVecArithmeticOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions +{ +public: + enum no_init { NO_INIT }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + + union { + struct { T x, y, z; }; + struct { T s, t, p; }; + struct { T r, g, b; }; + Impersonator< tvec2 > xy; + Impersonator< tvec2 > st; + Impersonator< tvec2 > rg; + }; + + enum { SIZE = 3 }; + inline static size_type size() { return SIZE; } + + // array access + inline T const& operator [] (size_t i) const { return (&x)[i]; } + inline T& operator [] (size_t i) { return (&x)[i]; } + + // ----------------------------------------------------------------------- + // we don't provide copy-ctor and operator= on purpose + // because we want the compiler generated versions + + // constructors + // leaves object uninitialized. use with caution. + explicit tvec3(no_init) { } + + // default constructor + tvec3() : x(0), y(0), z(0) { } + + // handles implicit conversion to a tvec4. must not be explicit. + template + tvec3(A v) : x(v), y(v), z(v) { } + + template + tvec3(A x, B y, C z) : x(x), y(y), z(z) { } + + template + tvec3(const tvec2& v, B z) : x(v.x), y(v.y), z(z) { } + + template + explicit tvec3(const tvec3& v) : x(v.x), y(v.y), z(v.z) { } + + template + tvec3(const Impersonator< tvec2 >& v, B z) + : x(((const tvec2&)v).x), + y(((const tvec2&)v).y), + z(z) { } + + // cross product works only on vectors of size 3 + template + friend inline + tvec3 __attribute__((pure)) cross(const tvec3& u, const tvec3& v) { + return tvec3( + u.y*v.z - u.z*v.y, + u.z*v.x - u.x*v.z, + u.x*v.y - u.y*v.x); + } +}; + + +// ---------------------------------------------------------------------------------------- + +typedef tvec3 vec3; + +// ---------------------------------------------------------------------------------------- +}; // namespace android + +#endif /* UI_VEC4_H */ diff --git a/include/ui/vec4.h b/include/ui/vec4.h new file mode 100644 index 000000000..798382d2b --- /dev/null +++ b/include/ui/vec4.h @@ -0,0 +1,110 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UI_VEC4_H +#define UI_VEC4_H + +#include +#include + +#include + +namespace android { +// ------------------------------------------------------------------------------------- + +template +class tvec4 : public TVecArithmeticOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions +{ +public: + enum no_init { NO_INIT }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + + union { + struct { T x, y, z, w; }; + struct { T s, t, p, q; }; + struct { T r, g, b, a; }; + Impersonator< tvec2 > xy; + Impersonator< tvec2 > st; + Impersonator< tvec2 > rg; + Impersonator< tvec3 > xyz; + Impersonator< tvec3 > stp; + Impersonator< tvec3 > rgb; + }; + + enum { SIZE = 4 }; + inline static size_type size() { return SIZE; } + + // array access + inline T const& operator [] (size_t i) const { return (&x)[i]; } + inline T& operator [] (size_t i) { return (&x)[i]; } + + // ----------------------------------------------------------------------- + // we don't provide copy-ctor and operator= on purpose + // because we want the compiler generated versions + + // constructors + + // leaves object uninitialized. use with caution. + explicit tvec4(no_init) { } + + // default constructor + tvec4() : x(0), y(0), z(0), w(0) { } + + // handles implicit conversion to a tvec4. must not be explicit. + template + tvec4(A v) : x(v), y(v), z(v), w(v) { } + + template + tvec4(A x, B y, C z, D w) : x(x), y(y), z(z), w(w) { } + + template + tvec4(const tvec2& v, B z, C w) : x(v.x), y(v.y), z(z), w(w) { } + + template + tvec4(const tvec3& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { } + + template + explicit tvec4(const tvec4& v) : x(v.x), y(v.y), z(v.z), w(v.w) { } + + template + tvec4(const Impersonator< tvec3 >& v, B w) + : x(((const tvec3&)v).x), + y(((const tvec3&)v).y), + z(((const tvec3&)v).z), + w(w) { } + + template + tvec4(const Impersonator< tvec2 >& v, B z, C w) + : x(((const tvec2&)v).x), + y(((const tvec2&)v).y), + z(z), + w(w) { } +}; + +// ---------------------------------------------------------------------------------------- + +typedef tvec4 vec4; + +// ---------------------------------------------------------------------------------------- +}; // namespace android + +#endif /* UI_VEC4_H */ diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index 8b8e1d87d..6f62a553a 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -4,9 +4,12 @@ include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ - Region_test.cpp + Region_test.cpp \ + vec_test.cpp \ + mat_test.cpp shared_libraries := \ + libutils \ libui static_libraries := \ diff --git a/libs/ui/tests/mat_test.cpp b/libs/ui/tests/mat_test.cpp new file mode 100644 index 000000000..a2c63ac7c --- /dev/null +++ b/libs/ui/tests/mat_test.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RegionTest" + +#include +#include +#include +#include + +#include + +namespace android { + +class MatTest : public testing::Test { +protected: +}; + +TEST_F(MatTest, Basics) { + mat4 m0; + EXPECT_EQ(sizeof(mat4), sizeof(float)*16); +} + +TEST_F(MatTest, ComparisonOps) { + mat4 m0; + mat4 m1(2); + + EXPECT_TRUE(m0 == m0); + EXPECT_TRUE(m0 != m1); + EXPECT_FALSE(m0 != m0); + EXPECT_FALSE(m0 == m1); +} + +TEST_F(MatTest, Constructors) { + mat4 m0; + ASSERT_EQ(m0[0].x, 1); + ASSERT_EQ(m0[0].y, 0); + ASSERT_EQ(m0[0].z, 0); + ASSERT_EQ(m0[0].w, 0); + ASSERT_EQ(m0[1].x, 0); + ASSERT_EQ(m0[1].y, 1); + ASSERT_EQ(m0[1].z, 0); + ASSERT_EQ(m0[1].w, 0); + ASSERT_EQ(m0[2].x, 0); + ASSERT_EQ(m0[2].y, 0); + ASSERT_EQ(m0[2].z, 1); + ASSERT_EQ(m0[2].w, 0); + ASSERT_EQ(m0[3].x, 0); + ASSERT_EQ(m0[3].y, 0); + ASSERT_EQ(m0[3].z, 0); + ASSERT_EQ(m0[3].w, 1); + + mat4 m1(2); + mat4 m2(vec4(2)); + mat4 m3(m2); + + EXPECT_EQ(m1, m2); + EXPECT_EQ(m2, m3); + EXPECT_EQ(m3, m1); + + mat4 m4(vec4(1), vec4(2), vec4(3), vec4(4)); +} + +TEST_F(MatTest, ArithmeticOps) { + mat4 m0; + mat4 m1(2); + mat4 m2(vec4(2)); + + m1 += m2; + EXPECT_EQ(mat4(4), m1); + + m2 -= m1; + EXPECT_EQ(mat4(-2), m2); + + m1 *= 2; + EXPECT_EQ(mat4(8), m1); + + m1 /= 2; + EXPECT_EQ(mat4(4), m1); + + m0 = -m0; + EXPECT_EQ(mat4(-1), m0); +} + +TEST_F(MatTest, UnaryOps) { + const mat4 identity; + mat4 m0; + + ++m0; + EXPECT_EQ(mat4( vec4(2,1,1,1), vec4(1,2,1,1), vec4(1,1,2,1), vec4(1,1,1,2) ), m0); + EXPECT_EQ(mat4( -vec4(2,1,1,1), -vec4(1,2,1,1), -vec4(1,1,2,1), -vec4(1,1,1,2) ), -m0); + + --m0; + EXPECT_EQ(identity, m0); +} + +TEST_F(MatTest, MiscOps) { + const mat4 identity; + mat4 m0; + EXPECT_EQ(4, trace(m0)); + + mat4 m1(vec4(1,2,3,4), vec4(5,6,7,8), vec4(9,10,11,12), vec4(13,14,15,16)); + mat4 m2(vec4(1,5,9,13), vec4(2,6,10,14), vec4(3,7,11,15), vec4(4,8,12,16)); + EXPECT_EQ(m1, transpose(m2)); + EXPECT_EQ(m2, transpose(m1)); + EXPECT_EQ(vec4(1,6,11,16), diag(m1)); + + EXPECT_EQ(identity, inverse(identity)); + + mat4 m3(vec4(4,3,0,0), vec4(3,2,0,0), vec4(0,0,1,0), vec4(0,0,0,1)); + mat4 m3i(inverse(m3)); + EXPECT_FLOAT_EQ(-2, m3i[0][0]); + EXPECT_FLOAT_EQ( 3, m3i[0][1]); + EXPECT_FLOAT_EQ( 3, m3i[1][0]); + EXPECT_FLOAT_EQ(-4, m3i[1][1]); + + mat4 m3ii(inverse(m3i)); + EXPECT_FLOAT_EQ(m3[0][0], m3ii[0][0]); + EXPECT_FLOAT_EQ(m3[0][1], m3ii[0][1]); + EXPECT_FLOAT_EQ(m3[1][0], m3ii[1][0]); + EXPECT_FLOAT_EQ(m3[1][1], m3ii[1][1]); + + EXPECT_EQ(m1, m1*identity); +} + +}; // namespace android diff --git a/libs/ui/tests/vec_test.cpp b/libs/ui/tests/vec_test.cpp new file mode 100644 index 000000000..00f737e2f --- /dev/null +++ b/libs/ui/tests/vec_test.cpp @@ -0,0 +1,256 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RegionTest" + +#include +#include +#include +#include + +#include + +namespace android { + +class VecTest : public testing::Test { +protected: +}; + +TEST_F(VecTest, Basics) { + vec4 v4; + vec3& v3(v4.xyz); + + EXPECT_EQ(sizeof(vec4), sizeof(float)*4); + EXPECT_EQ(sizeof(vec3), sizeof(float)*3); + EXPECT_EQ(sizeof(vec2), sizeof(float)*2); + EXPECT_EQ((void*)&v3, (void*)&v4); +} + +TEST_F(VecTest, Constructors) { + vec4 v0; + EXPECT_EQ(v0.x, 0); + EXPECT_EQ(v0.y, 0); + EXPECT_EQ(v0.z, 0); + EXPECT_EQ(v0.w, 0); + + vec4 v1(1); + EXPECT_EQ(v1.x, 1); + EXPECT_EQ(v1.y, 1); + EXPECT_EQ(v1.z, 1); + EXPECT_EQ(v1.w, 1); + + vec4 v2(1,2,3,4); + EXPECT_EQ(v2.x, 1); + EXPECT_EQ(v2.y, 2); + EXPECT_EQ(v2.z, 3); + EXPECT_EQ(v2.w, 4); + + vec4 v3(v2); + EXPECT_EQ(v3.x, 1); + EXPECT_EQ(v3.y, 2); + EXPECT_EQ(v3.z, 3); + EXPECT_EQ(v3.w, 4); + + vec4 v4(v3.xyz, 42); + EXPECT_EQ(v4.x, 1); + EXPECT_EQ(v4.y, 2); + EXPECT_EQ(v4.z, 3); + EXPECT_EQ(v4.w, 42); + + vec4 v5(vec3(v2.xy, 42), 24); + EXPECT_EQ(v5.x, 1); + EXPECT_EQ(v5.y, 2); + EXPECT_EQ(v5.z, 42); + EXPECT_EQ(v5.w, 24); + + tvec4 vd(2); + EXPECT_EQ(vd.x, 2); + EXPECT_EQ(vd.y, 2); + EXPECT_EQ(vd.z, 2); + EXPECT_EQ(vd.w, 2); +} + +TEST_F(VecTest, Access) { + vec4 v0(1,2,3,4); + v0.x = 10; + v0.y = 20; + v0.z = 30; + v0.w = 40; + EXPECT_EQ(v0.x, 10); + EXPECT_EQ(v0.y, 20); + EXPECT_EQ(v0.z, 30); + EXPECT_EQ(v0.w, 40); + + v0[0] = 100; + v0[1] = 200; + v0[2] = 300; + v0[3] = 400; + EXPECT_EQ(v0.x, 100); + EXPECT_EQ(v0.y, 200); + EXPECT_EQ(v0.z, 300); + EXPECT_EQ(v0.w, 400); + + v0.xyz = vec3(1,2,3); + EXPECT_EQ(v0.x, 1); + EXPECT_EQ(v0.y, 2); + EXPECT_EQ(v0.z, 3); + EXPECT_EQ(v0.w, 400); +} + +TEST_F(VecTest, UnaryOps) { + vec4 v0(1,2,3,4); + + v0 += 1; + EXPECT_EQ(v0.x, 2); + EXPECT_EQ(v0.y, 3); + EXPECT_EQ(v0.z, 4); + EXPECT_EQ(v0.w, 5); + + v0 -= 1; + EXPECT_EQ(v0.x, 1); + EXPECT_EQ(v0.y, 2); + EXPECT_EQ(v0.z, 3); + EXPECT_EQ(v0.w, 4); + + v0 *= 2; + EXPECT_EQ(v0.x, 2); + EXPECT_EQ(v0.y, 4); + EXPECT_EQ(v0.z, 6); + EXPECT_EQ(v0.w, 8); + + v0 /= 2; + EXPECT_EQ(v0.x, 1); + EXPECT_EQ(v0.y, 2); + EXPECT_EQ(v0.z, 3); + EXPECT_EQ(v0.w, 4); + + vec4 v1(10, 20, 30, 40); + + v0 += v1; + EXPECT_EQ(v0.x, 11); + EXPECT_EQ(v0.y, 22); + EXPECT_EQ(v0.z, 33); + EXPECT_EQ(v0.w, 44); + + v0 -= v1; + EXPECT_EQ(v0.x, 1); + EXPECT_EQ(v0.y, 2); + EXPECT_EQ(v0.z, 3); + EXPECT_EQ(v0.w, 4); + + v0 *= v1; + EXPECT_EQ(v0.x, 10); + EXPECT_EQ(v0.y, 40); + EXPECT_EQ(v0.z, 90); + EXPECT_EQ(v0.w, 160); + + v0 /= v1; + EXPECT_EQ(v0.x, 1); + EXPECT_EQ(v0.y, 2); + EXPECT_EQ(v0.z, 3); + EXPECT_EQ(v0.w, 4); + + ++v0; + EXPECT_EQ(v0.x, 2); + EXPECT_EQ(v0.y, 3); + EXPECT_EQ(v0.z, 4); + EXPECT_EQ(v0.w, 5); + + ++++v0; + EXPECT_EQ(v0.x, 4); + EXPECT_EQ(v0.y, 5); + EXPECT_EQ(v0.z, 6); + EXPECT_EQ(v0.w, 7); + + --v1; + EXPECT_EQ(v1.x, 9); + EXPECT_EQ(v1.y, 19); + EXPECT_EQ(v1.z, 29); + EXPECT_EQ(v1.w, 39); + + v1 = -v1; + EXPECT_EQ(v1.x, -9); + EXPECT_EQ(v1.y, -19); + EXPECT_EQ(v1.z, -29); + EXPECT_EQ(v1.w, -39); + + tvec4 dv(1,2,3,4); + v1 += dv; + EXPECT_EQ(v1.x, -8); + EXPECT_EQ(v1.y, -17); + EXPECT_EQ(v1.z, -26); + EXPECT_EQ(v1.w, -35); +} + +TEST_F(VecTest, ComparisonOps) { + vec4 v0(1,2,3,4); + vec4 v1(10,20,30,40); + + EXPECT_TRUE(v0 == v0); + EXPECT_TRUE(v0 != v1); + EXPECT_FALSE(v0 != v0); + EXPECT_FALSE(v0 == v1); +} + +TEST_F(VecTest, ArithmeticOps) { + vec4 v0(1,2,3,4); + vec4 v1(10,20,30,40); + + vec4 v2(v0 + v1); + EXPECT_EQ(v2.x, 11); + EXPECT_EQ(v2.y, 22); + EXPECT_EQ(v2.z, 33); + EXPECT_EQ(v2.w, 44); + + v0 = v1 * 2; + EXPECT_EQ(v0.x, 20); + EXPECT_EQ(v0.y, 40); + EXPECT_EQ(v0.z, 60); + EXPECT_EQ(v0.w, 80); + + v0 = 2 * v1; + EXPECT_EQ(v0.x, 20); + EXPECT_EQ(v0.y, 40); + EXPECT_EQ(v0.z, 60); + EXPECT_EQ(v0.w, 80); + + tvec4 vd(2); + v0 = v1 * vd; + EXPECT_EQ(v0.x, 20); + EXPECT_EQ(v0.y, 40); + EXPECT_EQ(v0.z, 60); + EXPECT_EQ(v0.w, 80); +} + +TEST_F(VecTest, ArithmeticFunc) { + vec3 east(1, 0, 0); + vec3 north(0, 1, 0); + vec3 up( cross(east, north) ); + EXPECT_EQ(up, vec3(0,0,1)); + EXPECT_EQ(dot(east, north), 0); + EXPECT_EQ(length(east), 1); + EXPECT_EQ(distance(east, north), sqrtf(2)); + + vec3 v0(1,2,3); + vec3 vn(normalize(v0)); + EXPECT_FLOAT_EQ(1, length(vn)); + EXPECT_FLOAT_EQ(length(v0), dot(v0, vn)); + + tvec3 vd(east); + EXPECT_EQ(length(vd), 1); +} + +}; // namespace android