Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 595ea77f authored by Mathias Agopian's avatar Mathias Agopian
Browse files

vector and matrix classes for graphics use

- this implements vec2, vec3, vec4, which are float vectors
of size 2, 3 and 4 respectively.

the code allows easy instantiation of vectors of a different
type via the tvec{2|3|4}<T> template classes.

- this also implements mat4 which is a float 4x4 matrix. the
tmat44<T> template class allows easy instantiation of a
4x4 matrix of a different value_type.

The vector types have some minimal support for the
glsl style swizzled access; for instance:

  vec4 u;
  vec3 v = u.xyz;

only .x, .xy, .xyz and their .stpq / .rgba equivalent are
supported.

most operators are supported on both vector and matrices:
arithmetic, unary, compound assignment and comparison
(bit-wise operators NOT supported).

- operations available on vectors include:
dot, length, distance, normalize and cross

- operations available on matrices include:
transpose, inverse, trace

- and a few utilities to create matrices:
ortho, frustum, lookAt

Change-Id: I64add89ae90fa78d3f2f59985b63495575378635
parent f2e4fcd9
Loading
Loading
Loading
Loading
+179 −0
Original line number Original line Diff line number Diff line
/*
 * 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 <stdint.h>
#include <sys/types.h>
#include <utils/Debug.h>
#include <utils/String8.h>

#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<typename MATRIX>
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<N ; i++) {
        // look for largest element in column
        swap = i;
        for (size_t j=i+1 ; j<N ; j++) {
            if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
                swap = j;
            }
        }

        if (swap != i) {
            /* swap rows. */
            for (size_t k=0 ; k<N ; k++) {
                t = tmp[i][k];
                tmp[i][k] = tmp[swap][k];
                tmp[swap][k] = t;

                t = inverse[i][k];
                inverse[i][k] = inverse[swap][k];
                inverse[swap][k] = t;
            }
        }

        t = 1 / tmp[i][i];
        for (size_t k=0 ; k<N ; k++) {
            tmp[i][k] *= t;
            inverse[i][k] *= t;
        }
        for (size_t j=0 ; j<N ; j++) {
            if (j != i) {
                t = tmp[j][i];
                for (size_t k=0 ; k<N ; k++) {
                    tmp[j][k] -= tmp[i][k] * t;
                    inverse[j][k] -= inverse[i][k] * t;
                }
            }
        }
    }
    return inverse;
}

template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
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_R::row_size() ; r++) {
        res[r] = lhs * rhs[r];
    }
    return res;
}

// transpose. this handles matrices of matrices
template <typename MATRIX>
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<MATRIX::row_size() ; r++)
        for (size_t c=0 ; c<MATRIX::col_size() ; c++)
            result[c][r] = transpose(m[r][c]);
    return result;
}

// trace. this handles matrices of matrices
template <typename MATRIX>
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<MATRIX::row_size() ; r++)
        result += trace(m[r][r]);
    return result;
}

// trace. this handles matrices of matrices
template <typename MATRIX>
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<MATRIX::row_size() ; r++)
        result[r] = m[r][r];
    return result;
}

template <typename MATRIX>
String8 asString(const MATRIX& m) {
    String8 s;
    for (size_t c=0 ; c<MATRIX::col_size() ; c++) {
        s.append("|  ");
        for (size_t r=0 ; r<MATRIX::row_size() ; r++) {
            s.appendFormat("%7.2f  ", m[r][c]);
        }
        s.append("|\n");
    }
    return s;
}

}; // namespace matrix

// -------------------------------------------------------------------------------------
}; // namespace android

#undef PURE

#endif /* UI_TMAT_HELPERS_H */
+348 −0
Original line number Original line Diff line number Diff line
/*
 * 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 TVEC_IMPLEMENTATION
#error "Don't include TVecHelpers.h directly. use ui/vec*.h instead"
#else
#undef TVEC_IMPLEMENTATION
#endif


#ifndef UI_TVEC_HELPERS_H
#define UI_TVEC_HELPERS_H

#include <stdint.h>
#include <sys/types.h>

#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 <typename TYPE>
struct Impersonator {
    Impersonator& operator = (const TYPE& rhs) {
        reinterpret_cast<TYPE&>(*this) = rhs;
        return *this;
    }
    operator TYPE& () {
        return reinterpret_cast<TYPE&>(*this);
    }
    operator TYPE const& () const {
        return reinterpret_cast<TYPE const&>(*this);
    }
};

/*
 * TVecArithmeticOperators implements basic arithmetic and basic compound assignments
 * operators on a vector of type BASE<T>.
 *
 * BASE only needs to implement operator[] and size().
 * By simply inheriting from TVecArithmeticOperators<BASE, T> BASE will automatically
 * get all the functionality here.
 */

template <template<typename T> class BASE, typename T>
class TVecArithmeticOperators {
public:
    /* compound assignment from a another vector of the same size but different
     * element type.
     */
    template <typename OTHER>
    BASE<T>& operator += (const BASE<OTHER>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] += v[i];
        }
        return rhs;
    }
    template <typename OTHER>
    BASE<T>& operator -= (const BASE<OTHER>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] -= v[i];
        }
        return rhs;
    }
    template <typename OTHER>
    BASE<T>& operator *= (const BASE<OTHER>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] *= v[i];
        }
        return rhs;
    }
    template <typename OTHER>
    BASE<T>& operator /= (const BASE<OTHER>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::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<T> allows it).
     */
    BASE<T>& operator += (const BASE<T>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] += v[i];
        }
        return rhs;
    }
    BASE<T>& operator -= (const BASE<T>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] -= v[i];
        }
        return rhs;
    }
    BASE<T>& operator *= (const BASE<T>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            rhs[i] *= v[i];
        }
        return rhs;
    }
    BASE<T>& operator /= (const BASE<T>& v) {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::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<T> being known).
     */

    /* The operators below handle operation between vectors of the same side
     * but of a different element type.
     */
    template<typename RT>
    friend inline
    BASE<T> PURE operator +(const BASE<T>& lv, const BASE<RT>& rv) {
        return BASE<T>(lv) += rv;
    }
    template<typename RT>
    friend inline
    BASE<T> PURE operator -(const BASE<T>& lv, const BASE<RT>& rv) {
        return BASE<T>(lv) -= rv;
    }
    template<typename RT>
    friend inline
    BASE<T> PURE operator *(const BASE<T>& lv, const BASE<RT>& rv) {
        return BASE<T>(lv) *= rv;
    }
    template<typename RT>
    friend inline
    BASE<T> PURE operator /(const BASE<T>& lv, const BASE<RT>& rv) {
        return BASE<T>(lv) /= rv;
    }

    /* The operators below (which are not templates once this class is instanced,
     * i.e.: BASE<T> 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<T> allows it).
     */
    friend inline
    BASE<T> PURE operator +(const BASE<T>& lv, const BASE<T>& rv) {
        return BASE<T>(lv) += rv;
    }
    friend inline
    BASE<T> PURE operator -(const BASE<T>& lv, const BASE<T>& rv) {
        return BASE<T>(lv) -= rv;
    }
    friend inline
    BASE<T> PURE operator *(const BASE<T>& lv, const BASE<T>& rv) {
        return BASE<T>(lv) *= rv;
    }
    friend inline
    BASE<T> PURE operator /(const BASE<T>& lv, const BASE<T>& rv) {
        return BASE<T>(lv) /= rv;
    }
};

/*
 * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
 *
 * BASE only needs to implement operator[] and size().
 * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
 * get all the functionality here.
 *
 * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
 */
template <template<typename T> class BASE, typename T>
class TVecUnaryOperators {
public:
    BASE<T>& operator ++ () {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            ++rhs[i];
        }
        return rhs;
    }
    BASE<T>& operator -- () {
        BASE<T>& rhs = static_cast<BASE<T>&>(*this);
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            --rhs[i];
        }
        return rhs;
    }
    BASE<T> operator - () const {
        BASE<T> r(BASE<T>::NO_INIT);
        BASE<T> const& rv(static_cast<BASE<T> const&>(*this));
        for (size_t i=0 ; i<BASE<T>::size() ; i++) {
            r[i] = -rv[i];
        }
        return r;
    }
};


/*
 * TVecComparisonOperators implements relational/comparison operators
 * on a vector of type BASE<T>.
 *
 * BASE only needs to implement operator[] and size().
 * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
 * get all the functionality here.
 */
template <template<typename T> 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<T> being known).
     */
    template<typename RT>
    friend inline
    bool PURE operator ==(const BASE<T>& lv, const BASE<RT>& rv) {
        for (size_t i = 0; i < BASE<T>::size(); i++)
            if (lv[i] != rv[i])
                return false;
        return true;
    }

    template<typename RT>
    friend inline
    bool PURE operator !=(const BASE<T>& lv, const BASE<RT>& rv) {
        return !operator ==(lv, rv);
    }

    template<typename RT>
    friend inline
    bool PURE operator >(const BASE<T>& lv, const BASE<RT>& rv) {
        for (size_t i = 0; i < BASE<T>::size(); i++)
            if (lv[i] <= rv[i])
                return false;
        return true;
    }

    template<typename RT>
    friend inline
    bool PURE operator <=(const BASE<T>& lv, const BASE<RT>& rv) {
        return !(lv > rv);
    }

    template<typename RT>
    friend inline
    bool PURE operator <(const BASE<T>& lv, const BASE<RT>& rv) {
        for (size_t i = 0; i < BASE<T>::size(); i++)
            if (lv[i] >= rv[i])
                return false;
        return true;
    }

    template<typename RT>
    friend inline
    bool PURE operator >=(const BASE<T>& lv, const BASE<RT>& rv) {
        return !(lv < rv);
    }
};


/*
 * TVecFunctions implements functions on a vector of type BASE<T>.
 *
 * BASE only needs to implement operator[] and size().
 * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
 * get all the functionality here.
 */
template <template<typename T> 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<T> being known).
     */
    template<typename RT>
    friend inline
    T PURE dot(const BASE<T>& lv, const BASE<RT>& rv) {
        T r(0);
        for (size_t i = 0; i < BASE<T>::size(); i++)
            r += lv[i]*rv[i];
        return r;
    }

    friend inline
    T PURE length(const BASE<T>& lv) {
        return sqrt( dot(lv, lv) );
    }

    template<typename RT>
    friend inline
    T PURE distance(const BASE<T>& lv, const BASE<RT>& rv) {
        return length(rv - lv);
    }

    friend inline
    BASE<T> PURE normalize(const BASE<T>& lv) {
        return lv * (1 / length(lv));
    }
};

#undef PURE

// -------------------------------------------------------------------------------------
}; // namespace android


#endif /* UI_TVEC_HELPERS_H */

include/ui/mat4.h

0 → 100644
+473 −0

File added.

Preview size limit exceeded, changes collapsed.

include/ui/vec2.h

0 → 100644
+85 −0
Original line number Original line Diff line number Diff line
/*
 * 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 <stdint.h>
#include <sys/types.h>

#define TVEC_IMPLEMENTATION
#include <ui/TVecHelpers.h>

namespace android {
// -------------------------------------------------------------------------------------

template <typename T>
class tvec2 :   public TVecArithmeticOperators<tvec2, T>,
                public TVecUnaryOperators<tvec2, T>,
                public TVecComparisonOperators<tvec2, T>,
                public TVecFunctions<tvec2, T>
{
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<typename A>
    tvec2(A v) : x(v), y(v) { }

    template<typename A, typename B>
    tvec2(A x, B y) : x(x), y(y) { }

    template<typename A>
    explicit tvec2(const tvec2<A>& v) : x(v.x), y(v.y) { }
};

// ----------------------------------------------------------------------------------------

typedef tvec2<float> vec2;

// ----------------------------------------------------------------------------------------
}; // namespace android

#endif /* UI_VEC4_H */

include/ui/vec3.h

0 → 100644
+106 −0
Original line number Original line Diff line number Diff line
/*
 * 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 <stdint.h>
#include <sys/types.h>

#include <ui/vec2.h>

namespace android {
// -------------------------------------------------------------------------------------

template <typename T>
class tvec3 :   public TVecArithmeticOperators<tvec3, T>,
                public TVecUnaryOperators<tvec3, T>,
                public TVecComparisonOperators<tvec3, T>,
                public TVecFunctions<tvec3, T>
{
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<T> > xy;
        Impersonator< tvec2<T> > st;
        Impersonator< tvec2<T> > 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<typename A>
    tvec3(A v) : x(v), y(v), z(v) { }

    template<typename A, typename B, typename C>
    tvec3(A x, B y, C z) : x(x), y(y), z(z) { }

    template<typename A, typename B>
    tvec3(const tvec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }

    template<typename A>
    explicit tvec3(const tvec3<A>& v) : x(v.x), y(v.y), z(v.z) { }

    template<typename A, typename B>
    tvec3(const Impersonator< tvec2<A> >& v, B z)
        : x(((const tvec2<A>&)v).x),
          y(((const tvec2<A>&)v).y),
          z(z) { }

    // cross product works only on vectors of size 3
    template <typename RT>
    friend inline
    tvec3 __attribute__((pure)) cross(const tvec3& u, const tvec3<RT>& 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<float> vec3;

// ----------------------------------------------------------------------------------------
}; // namespace android

#endif /* UI_VEC4_H */
Loading