Files
picovga-cmake/src/util/mat2d.h
2023-03-05 23:23:16 -08:00

295 lines
6.5 KiB
C++

/**
* @file
* @brief 2D Transformation Matrix
* @author Miroslav Nemecek <Panda38@seznam.cz>
* @see CanvasGroup
*/
#ifndef _MAT2D_H
#define _MAT2D_H
#include "pico/double.h"
#include "define.h"
/// Transformation matrix
template <typename m2type> class cMat2D
{
public:
// transformation matrix
m2type m11, m12, m13;
m2type m21, m22, m23;
/// Transform X
inline m2type GetX(m2type x, m2type y) const
{
return x*m11 + y*m12 + m13;
}
/// Transform Y
inline m2type GetY(m2type x, m2type y) const
{
return x*m21 + y*m22 + m23;
}
/// Set unit matrix
inline void Unit()
{
m11 = 1; m12 = 0; m13 = 0;
m21 = 0; m22 = 1; m23 = 0;
}
/// Copy matrix
inline void Copy(const cMat2D* m)
{
m11 = m->m11; m12 = m->m12; m13 = m->m13;
m21 = m->m21; m22 = m->m22; m23 = m->m23;
}
/**
* @brief Translate in X direction
* @details
* <pre>
* 1 0 tx m11 m12 m13 m11 m12 m13+tx
* 0 1 0 * m21 m22 m23 = m21 m22 m23
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void TransX(m2type tx)
{
m13 += tx;
}
/**
* @brief Translate in Y direction
* @details
* <pre>
* 1 0 0 m11 m12 m13 m11 m12 m13
* 0 1 ty * m21 m22 m23 = m21 m22 m23+ty
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void TransY(m2type ty)
{
m23 += ty;
}
/**
* @brief Scale in X direction
* @details
* <pre>
* sx 0 0 m11 m12 m13 m11*sx m12*sx m13*sx
* 0 1 0 * m21 m22 m23 = m21 m22 m23
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void ScaleX(m2type sx)
{
m11 *= sx;
m12 *= sx;
m13 *= sx;
}
/**
* @brief Scale in Y direction
* @details
* <pre>
* 1 0 0 m11 m12 m13 m11 m12 m13
* 0 sy 0 * m21 m22 m23 = m21*sy m22*sy m23*sy
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void ScaleY(m2type sy)
{
m21 *= sy;
m22 *= sy;
m23 *= sy;
}
/**
* @brief Rotate, using sin and cos
* @details
* <pre>
* cosa -sina 0 m11 m12 m13 m11*cosa-m21*sina m12*cosa-m22*sina m13*cosa-m23*sina
* sina cosa 0 * m21 m22 m23 = m11*sina+m21*cosa m12*sina+m22*cosa m13*sina+m23*cosa
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void RotSC(m2type sina, m2type cosa)
{
m2type t1 = m11;
m2type t2 = m21;
m11 = t1*cosa - t2*sina;
m21 = t1*sina + t2*cosa;
t1 = m12;
t2 = m22;
m12 = t1*cosa - t2*sina;
m22 = t1*sina + t2*cosa;
t1 = m13;
t2 = m23;
m13 = t1*cosa - t2*sina;
m23 = t1*sina + t2*cosa;
}
/// Rotate, using angle
inline void Rot(m2type a)
{
this->RotSC(sin(a), cos(a));
}
/// Rotate by 90 deg (sina=1, cosa=0)
inline void Rot90()
{
m2type t = m11;
m11 = -m21;
m21 = t;
t = m12;
m12 = -m22;
m22 = t;
t = m13;
m13 = -m23;
m23 = t;
}
/// Rotate by 180 deg (=flipX and flipY) (sina=0, cosa=-1)
inline void Rot180()
{
m11 = -m11;
m21 = -m21;
m12 = -m12;
m22 = -m22;
m13 = -m13;
m23 = -m23;
}
/// Rotate by 270 deg (sina=-1, cosa=0)
inline void Rot270()
{
m2type t = m11;
m11 = m21;
m21 = -t;
t = m12;
m12 = m22;
m22 = -t;
t = m13;
m13 = m23;
m23 = -t;
}
/**
* @brief Shear in X direction
* @details
* <pre>
* 1 dx 0 m11 m12 m13 m11+m21*dx m12+m22*dx m13+m23*dx
* 0 1 0 * m21 m22 m23 = m21 m22 m23
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void ShearX(m2type dx)
{
m11 += m21*dx;
m12 += m22*dx;
m13 += m23*dx;
}
/**
* @brief Shear in Y direction
* @details
* <pre>
* 1 0 0 m11 m12 m13 m11 m12 m13
* dy 1 0 * m21 m22 m23 = m21+m11*dy m22+m12*dy m23+m13*dy
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void ShearY(m2type dy)
{
m21 += m11*dy;
m22 += m12*dy;
m23 += m13*dy;
}
/**
* @brief Flip in Y direction
* @details
* <pre>
* 1 0 0 m11 m12 m13 m11 m12 m13
* 0 -1 0 * m21 m22 m23 = -m21 -m22 -m23
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void FlipY()
{
m21 = -m21;
m22 = -m22;
m23 = -m23;
}
/**
* @brief Flip in X direction
* @details
* <pre>
* -1 0 0 m11 m12 m13 -m11 -m12 -m13
* 0 1 0 * m21 m22 m23 = m21 m22 m23
* 0 0 1 0 0 1 0 0 1
* </pre>
*/
inline void FlipX()
{
m11 = -m11;
m12 = -m12;
m13 = -m13;
}
};
#define TOFRACT(f) ((int)((f)*FRACTMUL + (((f) < 0) ? -0.5f : 0.5f)))
/// @addtogroup CanvasGroup
/// @{
/**
* @brief 2D Transformation Matrix
* @details Some rendering functions use the cMat2Df transformation matrix to define image transformation. The matrix has
* 6 numeric elements of float type. The transformation is prepared by setting the initial state with the Unit function and
* then entering the transformations one by one. Using the matrix, operations are performed on the image as if the
* operations were entered sequentially.
*/
class cMat2Df : public cMat2D<float>
{
public:
/**
* @brief Prepare transformation matrix (for DrawImgMat() function)
* @details The order of operations is chosen as if the image is first moved to the point tx and ty, scaled, skewed, then
* rotated and finally moved to the target coordinates.
* @param ws Source image width
* @param hs Source image height
* @param x0 Reference point X on source image
* @param y0 Reference point Y on source image
* @param wd Destination image width (negative = flip image in X direction)
* @param hd Destination image height (negative = flip image in Y direction)
* @param shearx Shear image in X direction
* @param sheary Shear image in Y direction
* @param r Rotate image (angle in radians)
* @param tx Shift in X direction (ws = whole image width)
* @param ty Shift in Y direction (hs = whole image height)
*/
void PrepDrawImg(int ws, int hs, int x0, int y0, int wd, int hd,
float shearx, float sheary, float r, float tx, float ty);
/**
* @brief Export matrix to int array[6]
* @details After transformation, the lower 12 bits of the number contain the decimal part of the number, the upper 20 bits
* contain the integer part of the number. Rendering functions require this integer form of the transformation matrix.
*/
void ExportInt(int* mat) const;
};
/// @}
#endif // _MAT2D_H