ugfx/src/gmisc/gmisc.h

487 lines
16 KiB
C

/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.io/license.html
*/
/**
* @file src/gmisc/gmisc.h
* @brief GMISC - Miscellaneous Routines header file.
*
* @addtogroup GMISC
*
* @brief Module which contains different features such as array conversions
*
* @{
*/
#ifndef _GMISC_H
#define _GMISC_H
#include "../../gfx.h"
/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
// Forward definition
typedef struct gPoint gPoint;
/**
* @brief Sample data formats
* @note These are defined regardless of whether you use the GMISC module
* or not as they are used in lots of places.
*/
typedef enum ArrayDataFormat_e {
ARRAY_DATA_UNKNOWN = 0,
ARRAY_DATA_4BITUNSIGNED = 4, ARRAY_DATA_4BITSIGNED = 5,
ARRAY_DATA_8BITUNSIGNED = 8, ARRAY_DATA_8BITSIGNED = 9,
ARRAY_DATA_10BITUNSIGNED = 10, ARRAY_DATA_10BITSIGNED = 11,
ARRAY_DATA_12BITUNSIGNED = 12, ARRAY_DATA_12BITSIGNED = 13,
ARRAY_DATA_14BITUNSIGNED = 14, ARRAY_DATA_14BITSIGNED = 15,
ARRAY_DATA_16BITUNSIGNED = 16, ARRAY_DATA_16BITSIGNED = 17,
} ArrayDataFormat;
/**
* @brief Is the sample data format a "signed" data format?
*/
#define gfxSampleFormatIsSigned(fmt) ((fmt) & 1)
/**
* @brief How many bits are in the sample data format
*/
#define gfxSampleFormatBits(fmt) ((fmt) & ~1)
/**
* @brief The type for a fixed point type.
* @details The top 16 bits are the integer component, the bottom 16 bits are the real component.
*/
typedef gI32 fixed;
/**
* @brief Macros to convert to and from a fixed point.
* @{
*/
#define FIXED(x) ((fixed)(x)<<16) /* @< integer to fixed */
#define NONFIXED(x) ((x)>>16) /* @< fixed to integer */
#define FIXED0_5 32768 /* @< 0.5 as a fixed (used for rounding) */
#define FP2FIXED(x) ((fixed)((x)*65536.0)) /* @< floating point to fixed */
#define FIXED2FP(x) ((double)(x)/65536.0) /* @< fixed to floating point */
#define FIXEDMUL(a,b) ((fixed)((((long long)(a))*(b))>>16)) /* @< fixed,fixed multiplication */
#define FIXEDMULINT(a,b) ((a)*(b)) /* @< integer,fixed multiplication */
/** @} */
/**
* @brief The famous number pi
*/
#ifndef GFX_PI
#define GFX_PI 3.1415926535897932384626433832795028841971693993751
#endif
/**
* @brief pi as a fixed point
*/
#define FIXED_PI FP2FIXED(GFX_PI)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if GFX_USE_GMISC || defined(__DOXYGEN__)
#if GMISC_NEED_ARRAYOPS || defined(__DOXYGEN__)
/**
* @brief Convert from one array format to another array format.
* @pre Requires GFX_USE_GMISC and GMISC_NEED_ARRAYOPS
*
* @param[in] srcfmt The format of the source array
* @param[in] src The source array
* @param[in] dstfmt The format of the destination array
* @param[in] dst The dstination array
* @param[in] cnt The number of array elements to convert
*
* @note Assumes the destination buffer is large enough for the resultant data.
* @note This routine is optimised to perform as fast as possible.
* @note No type checking is performed on the source format. It is assumed to
* have only valid values eg. ARRAY_DATA_4BITSIGNED will have values
* 0000 -> 0111 for positive numbers and 1111 -> 1000 for negative numbers
* Bits 5 -> 8 in the storage byte are treated in an undefined manner.
* @note If srcfmt or dstfmt is an unknown format, this routine does nothing
* with no warning that something is wrong
*
* @api
*/
void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt, void *dst, gMemSize cnt);
#if 0
void gmiscArrayTranslate(ArrayDataFormat fmt, void *src, void *dst, gMemSize cnt, int trans);
void gmiscArrayMultiply(ArrayDataFormat fmt, void *src, void *dst, gMemSize cnt, int mult);
void gmiscArrayDivide(ArrayDataFormat fmt, void *src, void *dst, gMemSize cnt, int mdiv);
void gmiscArrayMultDiv(ArrayDataFormat fmt, void *src, void *dst, gMemSize cnt, int mult, int div);
void gmiscArrayAdd(ArrayDataFormat fmt, void *src1, void *src2, void *dst, gMemSize cnt);
void gmiscArrayAddNoOverflow(ArrayDataFormat fmt, void *src1, void *src2, void *dst, gMemSize cnt);
#endif
#endif
#if GMISC_NEED_FASTTRIG || defined(__DOXYGEN__)
#include <math.h>
extern const double sintabledouble[];
/**
* @brief Fast Table Based Trig functions
* @return A double in the range -1.0 .. 0.0 .. 1.0
* @pre Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
*
* @param[in] degrees The angle in degrees (not radians)
*
* @note These functions use degrees rather than radians to describe the angle.
*
* @api
* @{
*/
double fsin(int degrees);
double fcos(int degrees);
/** @}
*
* @brief Fast Table Based Trig functions
* @return A double in the range -1.0 .. 0.0 .. 1.0
* @pre Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
*
* @param[in] degrees The angle in degrees 0 .. 359
*
* @note These functions use degrees rather than radians to describe the angle.
* @note These functions are super fast but require the parameter to be in range.
* Use the lowercase functions if the parameter may not be in range or if a
* required trig function is not supported in this form.
*
* @api
* @{
*/
#define FSIN(degrees) sintabledouble[degrees];
/** @} */
#endif
#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
extern const fixed sintablefixed[];
/**
* @brief Fast Table Based Trig functions
* @return A fixed point in the range -1.0 .. 0.0 .. 1.0
* @pre Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
*
* @param[in] degrees The angle in degrees (not radians)
*
* @note These functions use degrees rather than radians to describe the angle.
*
* @api
* @{
*/
fixed ffsin(int degrees);
fixed ffcos(int degrees);
/** @}
*
* @brief Fast Table Based Trig functions
* @return A fixed point in the range -1.0 .. 0.0 .. 1.0
* @pre Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
*
* @param[in] degrees The angle in degrees 0 .. 359
*
* @note These functions use degrees rather than radians to describe the angle.
* @note These functions are super fast but require the parameter to be in range.
* Use the lowercase functions if the parameter may not be in range or if a
* required trig function is not supported in this form.
*
* @api
* @{
*/
#define FFSIN(degrees) sintablefixed[degrees];
/** @} */
#endif
#if GMISC_NEED_INVSQRT || defined(__DOXYGEN__)
/**
* @brief Fast inverse square root function (x^-1/2)
* @return The approximate inverse square root
* @pre Requires GFX_USE_GMISC and GMISC_NEED_INVSQRT
*
* @param[in] n The number to find the inverse square root of
*
* @note This function generates an approximate result. Higher accuracy (at the expense
* of speed) can be obtained by modifying the source code (the necessary line
* is already there - just commented out).
* @note This function relies on the internal machine format of a float and a long.
* If your machine architecture is very unusual this function may not work.
*
* @api
*/
float invsqrt(float n);
#endif
#if GMISC_NEED_MATRIXFLOAT2D || defined(__DOXYGEN__)
/**
* @brief A matrix for doing 2D graphics using floats
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*/
typedef struct MatrixFloat2D {
float a00, a01, a02;
float a10, a11, a12;
float a20, a21, a22;
} MatrixFloat2D;
/**
* @brief Apply the matrix to a set of points
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination array of points
* @param[in] src The source array of points
* @param[in] m The matrix to apply
* @param[in] cnt How many points are in the array
*
* @note In-place matrix application is allowed ie. dst = src
*
* @api
*/
void gmiscMatrixFloat2DApplyToPoints(gPoint *dst, const gPoint *src, const MatrixFloat2D *m, int cnt);
/**
* @brief Set the 2D matrix to the identity matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] m The matrix to set to identity
*
* @api
*/
void gmiscMatrixFloat2DSetIdentity(MatrixFloat2D *m);
/**
* @brief Multiple two 2D matrixes together
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination matrix
* @param[in] src1 The first source matrix
* @param[in] src2 The second source matrix
*
* @note In-place matrix application is NOT allowed ie. dst != src1, dst != src2
*
* @api
*/
void gmiscMatrixFloat2DMultiply(MatrixFloat2D *dst, const MatrixFloat2D *src1, const MatrixFloat2D *src2);
/**
* @brief Add an x,y translation to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] tx, ty The x and y translation to apply
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFloat2DApplyTranslation(MatrixFloat2D *dst, const MatrixFloat2D *src, float tx, float ty);
/**
* @brief Add x,y scaling to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] sx, sy The scaling to apply in the x and y direction. Negative numbers give reflection.
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFloat2DApplyScale(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
/**
* @brief Add x,y shear to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] sx, sy The shear to apply in the x and y direction.
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFloat2DApplyShear(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
/**
* @brief Add rotation to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] angle The angle to apply in degrees (not radians).
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation.
* @note If GMISC_NEED_FASTTRIG is defined then the fast table sin and cos lookup's will be used
* rather than the C library versions.
*
* @api
*/
void gmiscMatrixFloat2DApplyRotation(MatrixFloat2D *dst, const MatrixFloat2D *src, int angle);
#endif
#if GMISC_NEED_MATRIXFIXED2D || defined(__DOXYGEN__)
/**
* @brief A matrix for doing 2D graphics using fixed point maths
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*/
typedef struct MatrixFixed2D {
fixed a00, a01, a02;
fixed a10, a11, a12;
fixed a20, a21, a22;
} MatrixFixed2D;
/**
* @brief Apply the matrix to a set of points
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] dst The destination array of points
* @param[in] src The source array of points
* @param[in] m The matrix to apply
* @param[in] cnt How many points are in the array
*
* @note In-place matrix application is allowed ie. dst = src
*
* @api
*/
void gmiscMatrixFixed2DApplyToPoints(gPoint *dst, const gPoint *src, const MatrixFixed2D *m, int cnt);
/**
* @brief Set the 2D matrix to the identity matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] m The matrix to set to identity
*
* @api
*/
void gmiscMatrixFixed2DSetIdentity(MatrixFixed2D *m);
/**
* @brief Multiple two 2D matrixes together
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] dst The destination matrix
* @param[in] src1 The first source matrix
* @param[in] src2 The second source matrix
*
* @note In-place matrix application is NOT allowed ie. dst != src1, dst != src2
*
* @api
*/
void gmiscMatrixFixed2DMultiply(MatrixFixed2D *dst, const MatrixFixed2D *src1, const MatrixFixed2D *src2);
/**
* @brief Add an x,y translation to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] tx, ty The x and y translation to apply
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFixed2DApplyTranslation(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed tx, fixed ty);
/**
* @brief Add x,y scaling to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] sx, sy The scaling to apply in the x and y direction. Negative numbers give reflection.
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFixed2DApplyScale(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
/**
* @brief Add x,y shear to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] sx, sy The shear to apply in the x and y direction.
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFixed2DApplyShear(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
/**
* @brief Add rotation to a matrix
* @pre Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D and GMISC_NEED_FIXEDTRIG
*
* @param[in] dst The destination matrix
* @param[in] src The source matrix. Can be NULL
* @param[in] angle The angle to apply in degrees (not radians).
*
* @note In-place matrix operation is NOT allowed ie. dst != src
* @note If no source matrix is provided, it is equivalent to applying the operation
* to an identity matrix. It also is a much simpler operation requiring no multiplication.
*
* @api
*/
void gmiscMatrixFixed2DApplyRotation(MatrixFixed2D *dst, const MatrixFixed2D *src, int angle);
#endif
#endif
#if GMISC_NEED_HITTEST_POLY || defined(__DOXYGEN__)
/**
* @brief Check whether a point is inside or on the edge of a polygon
* @pre Requires GFX_USE_GMISC and GMISC_NEED_HITTEST_POLY
*
* @note This function works both with convex and concave polygons
*
* @param[in] pntarray The array of points that form the polygon
* @param[in] cnt The number of points in the point array @p pntarray
* @param[in] p The point to test
*
* @return @p gTrue if the point @p p is inside or on the edge of the polygon @p pntarray, @p gFalse otherwise.
*
* @api
*/
gBool gmiscHittestPoly(const gPoint *pntarray, unsigned cnt, const gPoint *p);
#endif // GMISC_NEED_HITTEST_POLY
#endif /* GFX_USE_MISC */
#endif /* _GMISC_H */
/** @} */