diff --git a/.gitignore b/.gitignore index 2a2e8c7..0b41b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ Thumbs.db build/ lib/ bin/ +doc/ diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..01ddcfe --- /dev/null +++ b/Doxyfile @@ -0,0 +1,317 @@ +# Doxyfile 1.8.11 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "citro3d" +PROJECT_NUMBER = "1.2.0" +PROJECT_BRIEF = +PROJECT_LOGO = citro3d_logo.png +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = YES +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = include source +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = _3DS +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/Makefile b/Makefile index cdc7d45..e4bce42 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ INCLUDES := include #--------------------------------------------------------------------------------- ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -CFLAGS := -g -Wall -Werror -O2 -mword-relocations \ +CFLAGS := -g -Wall -Wextra -Werror -O2 -mword-relocations \ -fomit-frame-pointer -ffunction-sections \ $(ARCH) @@ -89,11 +89,14 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I$(CURDIR)/$(BUILD) -.PHONY: $(BUILD) clean all +.PHONY: $(BUILD) clean all doc #--------------------------------------------------------------------------------- all: $(BUILD) +doc: + @doxygen Doxyfile + dist-bin: all @tar --exclude=*~ -cjf citro3d-$(VERSION).tar.bz2 include lib diff --git a/citro3d_logo.png b/citro3d_logo.png new file mode 100644 index 0000000..c16191c Binary files /dev/null and b/citro3d_logo.png differ diff --git a/include/c3d/base.h b/include/c3d/base.h index 2219283..04111d7 100644 --- a/include/c3d/base.h +++ b/include/c3d/base.h @@ -1,6 +1,7 @@ #pragma once -#include "types.h" #include "buffers.h" +#include "maths.h" + #define C3D_DEFAULT_CMDBUF_SIZE 0x40000 enum diff --git a/include/c3d/light.h b/include/c3d/light.h index 67b492c..cb3ec7b 100644 --- a/include/c3d/light.h +++ b/include/c3d/light.h @@ -1,6 +1,6 @@ #pragma once -#include "types.h" #include "lightlut.h" +#include "maths.h" //----------------------------------------------------------------------------- // Material diff --git a/include/c3d/maths.h b/include/c3d/maths.h index a1ade85..f1b4f86 100644 --- a/include/c3d/maths.h +++ b/include/c3d/maths.h @@ -3,9 +3,16 @@ #include #include -// See http://tauday.com/tau-manifesto -//#define M_TAU 6.28318530717958647693 -/// The one true circumference-to-radius ratio +/** + * @addtogroup math_support + * @brief Implementations of matrix, vector, and quaternion operations. + * @{ + */ + +/** + * The one true circumference-to-radius ratio. + * See http://tauday.com/tau-manifesto + */ #define M_TAU (2*M_PI) /** @@ -25,8 +32,11 @@ #define C3D_AspectRatioTop (400.0f / 240.0f) ///< Aspect ratio for 3DS top screen #define C3D_AspectRatioBot (320.0f / 240.0f) ///< Aspect ratio for 3DS bottom screen -///@name Vector Math -///@{ +/** + * @name Vector Math + * @{ + */ + /** * @brief Create a new FVec4 * @param[in] x X-component @@ -66,7 +76,7 @@ static inline C3D_FVec FVec4_Subtract(C3D_FVec lhs, C3D_FVec rhs) /** * @brief Negate a FVec4 - * @note This is the same as scaling by -1 + * @note This is equivalent to `FVec4_Scale(v, -1)` * @param[in] v Vector to negate * @return -v */ @@ -222,7 +232,7 @@ static inline float FVec3_Distance(C3D_FVec lhs, C3D_FVec rhs) } /** - * @brief Scale a FVec4 + * @brief Scale a FVec3 * @param[in] v Vector to scale * @param[in] s Scale factor * @return v*s @@ -234,8 +244,8 @@ static inline C3D_FVec FVec3_Scale(C3D_FVec v, float s) } /** - * @brief Negate a FVec4 - * @note This is the same as scaling by -1 + * @brief Negate a FVec3 + * @note This is equivalent to `FVec3_Scale(v, -1)` * @param[in] v Vector to negate * @return -v */ @@ -258,11 +268,13 @@ static inline C3D_FVec FVec3_Cross(C3D_FVec lhs, C3D_FVec rhs) // A×B = (AyBz - AzBy, AzBx - AxBz, AxBy - AyBx) return FVec3_New(lhs.y*rhs.z - lhs.z*rhs.y, lhs.z*rhs.x - lhs.x*rhs.z, lhs.x*rhs.y - lhs.y*rhs.x); } -///@} +/** @} */ -///@name Matrix Math -///@note All matrices are 4x4 unless otherwise noted -///@{ +/** + * @name Matrix Math + * @note All matrices are 4x4 unless otherwise noted. + * @{ + */ /** * @brief Zero matrix @@ -283,6 +295,64 @@ static inline void Mtx_Copy(C3D_Mtx* out, const C3D_Mtx* in) *out = *in; } +/** + * @brief Creates a matrix with the diagonal using the given parameters. + * @param[out] out Output matrix. + * @param[in] x The X component. + * @param[in] y The Y component. + * @param[in] z The Z component. + * @param[in] w The W component. + */ +static inline void Mtx_Diagonal(C3D_Mtx* out, float x, float y, float z, float w) +{ + Mtx_Zeros(out); + out->r[0].x = x; + out->r[1].y = y; + out->r[2].z = z; + out->r[3].w = w; +} + +/** + * @brief Identity matrix + * @param[out] out Matrix to fill + */ +static inline void Mtx_Identity(C3D_Mtx* out) +{ + Mtx_Diagonal(out, 1.0f, 1.0f, 1.0f, 1.0f); +} + +/** + *@brief Transposes the matrix. Row => Column, and vice versa. + *@param[in,out] out Output matrix. + */ +void Mtx_Transpose(C3D_Mtx* out); + +/** + * @brief Matrix addition + * @param[out] out Output matrix. + * @param[in] lhs Left matrix. + * @param[in] rhs Right matrix. + * @return lhs+rhs (sum) + */ +static inline void Mtx_Add(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs) +{ + for (int i = 0; i < 16; i++) + out->m[i] = lhs->m[i] + rhs->m[i]; +} + +/** + * @brief Matrix subtraction + * @param[out] out Output matrix. + * @param[in] lhs Left matrix. + * @param[in] rhs Right matrix. + * @return lhs-rhs (difference) + */ +static inline void Mtx_Subtract(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs) +{ + for (int i = 0; i < 16; i++) + out->m[i] = lhs->m[i] - rhs->m[i]; +} + /** * @brief Multiply two matrices * @param[out] out Output matrix @@ -293,8 +363,8 @@ void Mtx_Multiply(C3D_Mtx* out, const C3D_Mtx* a, const C3D_Mtx* b); /** * @brief Inverse a matrix - * @note returns 0.0f if the matrix is degenerate; i.e. no inverse * @param[in,out] out Matrix to inverse + * @retval 0.0f Degenerate matrix (no inverse) * @return determinant */ float Mtx_Inverse(C3D_Mtx* out); @@ -303,7 +373,7 @@ float Mtx_Inverse(C3D_Mtx* out); * @brief Multiply 3x3 matrix by a FVec3 * @param[in] mtx Matrix * @param[in] v Vector - * @return Product of mtx and v + * @return mtx*v (product) */ C3D_FVec Mtx_MultiplyFVec3(const C3D_Mtx* mtx, C3D_FVec v); @@ -311,7 +381,7 @@ C3D_FVec Mtx_MultiplyFVec3(const C3D_Mtx* mtx, C3D_FVec v); * @brief Multiply 4x4 matrix by a FVec4 * @param[in] mtx Matrix * @param[in] v Vector - * @return Product of mtx and v + * @return mtx*v (product) */ C3D_FVec Mtx_MultiplyFVec4(const C3D_Mtx* mtx, C3D_FVec v); @@ -319,7 +389,7 @@ C3D_FVec Mtx_MultiplyFVec4(const C3D_Mtx* mtx, C3D_FVec v); * @brief Multiply 4x3 matrix by a FVec3 * @param[in] mtx Matrix * @param[in] v Vector - * @return Product of mtx and v + * @return mtx*v (product) */ static inline C3D_FVec Mtx_MultiplyFVecH(const C3D_Mtx* mtx, C3D_FVec v) { @@ -327,15 +397,22 @@ static inline C3D_FVec Mtx_MultiplyFVecH(const C3D_Mtx* mtx, C3D_FVec v) return Mtx_MultiplyFVec4(mtx, v); } -///@} + +/** + * @brief Get 4x4 matrix equivalent to Quaternion + * @param[out] m Output matrix + * @param[in] q Input Quaternion + */ +void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q); +/** @} */ /** * @name 3D Transformation Matrix Math * @note bRightSide is used to determine which side to perform the transformation. * With an input matrix A and a transformation matrix B, bRightSide being * true yields AB, while being false yield BA. + * @{ */ -///@{ /** * @brief 3D translation @@ -388,10 +465,12 @@ void Mtx_RotateY(C3D_Mtx* mtx, float angle, bool bRightSide); * @param[in] bRightSide Whether to transform from the right side */ void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide); -///@} +/** @} */ -///@name 3D Projection Matrix Math -///@{ +/** + * @name 3D Projection Matrix Math + * @{ + */ /** * @brief Orthogonal projection @@ -403,6 +482,7 @@ void Mtx_RotateZ(C3D_Mtx* mtx, float angle, bool bRightSide); * @param[in] near Near clip plane (Z=near) * @param[in] far Far clip plane (Z=far) * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_OrthoTilt */ void Mtx_Ortho(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded); @@ -414,6 +494,9 @@ void Mtx_Ortho(C3D_Mtx* mtx, float left, float right, float bottom, float top, f * @param[in] near Near clip plane (Z=near) * @param[in] far Far clip plane (Z=far) * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_PerspTilt + * @sa Mtx_PerspStereo + * @sa Mtx_PerspStereoTilt */ void Mtx_Persp(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded); @@ -433,11 +516,15 @@ void Mtx_Persp(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bo * @param[in] iod Interocular distance * @param[in] screen Focal length * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_Persp + * @sa Mtx_PerspTilt + * @sa Mtx_PerspStereoTilt */ void Mtx_PerspStereo(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded); /** * @brief Orthogonal projection, tilted to account for the 3DS screen rotation + * @param[out] mtx Output matrix * @param[in] left Left clip plane (X=left) * @param[in] right Right clip plane (X=right) * @param[in] bottom Bottom clip plane (Y=bottom) @@ -445,6 +532,7 @@ void Mtx_PerspStereo(C3D_Mtx* mtx, float fovy, float aspect, float near, float f * @param[in] near Near clip plane (Z=near) * @param[in] far Far clip plane (Z=far) * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_Ortho */ void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float top, float near, float far, bool isLeftHanded); @@ -456,12 +544,15 @@ void Mtx_OrthoTilt(C3D_Mtx* mtx, float left, float right, float bottom, float to * @param[in] near Near clip plane (Z=near) * @param[in] far Far clip plane (Z=far) * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_Persp + * @sa Mtx_PerspStereo + * @sa Mtx_PerspStereoTilt */ void Mtx_PerspTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, bool isLeftHanded); /** * @brief Stereo perspective projection, tilted to account for the 3DS screen rotation - * @note See the notes for Mtx_PerspStereo + * @note See the notes for @ref Mtx_PerspStereo * @param[out] mtx Output matrix * @param[in] fovy Vertical field of view in radians * @param[in] aspect Aspect ration of projection plane (width/height) @@ -470,93 +561,42 @@ void Mtx_PerspTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far * @param[in] iod Interocular distance * @param[in] screen Focal length * @param[in] isLeftHanded Whether to build a LH projection + * @sa Mtx_Persp + * @sa Mtx_PerspTilt + * @sa Mtx_PerspStereo */ void Mtx_PerspStereoTilt(C3D_Mtx* mtx, float fovy, float aspect, float near, float far, float iod, float screen, bool isLeftHanded); /** - * @brief Left-handed Look-At matrix, using DirectX implementation + * @brief Look-At matrix, based on DirectX implementation * @note See https://msdn.microsoft.com/en-us/library/windows/desktop/bb205342 - * @param[out] out Output matrix. - * @param[in] cameraPosition Position of the intended camera in 3D space. - * @param[in] cameraTarget Position of the intended target the camera is supposed to face in 3D space. - * @param[in] cameraUpVector The vector that points straight up depending on the camera's "Up" direction. - * @param[in] isLeftHanded If true, output matrix is left-handed. If false, output matrix is right-handed. + * @param[out] out Output matrix. + * @param[in] cameraPosition Position of the intended camera in 3D space. + * @param[in] cameraTarget Position of the intended target the camera is supposed to face in 3D space. + * @param[in] cameraUpVector The vector that points straight up depending on the camera's "Up" direction. + * @param[in] isLeftHanded Whether to build a LH projection */ void Mtx_LookAt(C3D_Mtx* out, C3D_FVec cameraPosition, C3D_FVec cameraTarget, C3D_FVec cameraUpVector, bool isLeftHanded); +/** @} */ /** - *@brief Transposes the matrix. Row => Column, and vice versa. - *@param[in,out] out Output matrix. + * @name Quaternion Math + * @{ */ -void Mtx_Transpose(C3D_Mtx* out); -/** - * @brief Creates a matrix with the diagonal using the given parameters. - * @param[out] out Output matrix. - * @param[in] x The X component. - * @param[in] y The Y component. - * @param[in] z The Z component. - * @param[in] w The W component. - */ -static inline void Mtx_Diagonal(C3D_Mtx* out, float x, float y, float z, float w) -{ - Mtx_Zeros(out); - out->r[0].x = x; - out->r[1].y = y; - out->r[2].z = z; - out->r[3].w = w; -} - -/** - * @brief Identity matrix - * @param[out] out Matrix to fill - */ -static inline void Mtx_Identity(C3D_Mtx* out) -{ - Mtx_Diagonal(out, 1.0f, 1.0f, 1.0f, 1.0f); -} - -/** - * @brief Matrix addition - * @param[out] out Output matrix. - * @param[in] lhs Left matrix. - * @param[in] rhs Right matrix. - */ -static inline void Mtx_Add(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs) -{ - for (int i = 0; i < 16; i++) - out->m[i] = lhs->m[i] + rhs->m[i]; -} - -/** - * @brief Matrix subtraction - * @param[out] out Output matrix. - * @param[in] lhs Left matrix. - * @param[in] rhs Right matrix. - */ -static inline void Mtx_Subtract(C3D_Mtx* out, const C3D_Mtx* lhs, const C3D_Mtx* rhs) -{ - for (int i = 0; i < 16; i++) - out->m[i] = lhs->m[i] - rhs->m[i]; -} -///@} - -///@name Quaternion Math -///@{ -// /** * @brief Create a new Quaternion * @param[in] i I-component * @param[in] j J-component * @param[in] k K-component - * @param[in] r R-component + * @param[in] r Real component * @return New Quaternion */ #define Quat_New(i,j,k,r) FVec4_New(i,j,k,r) /** * @brief Negate a Quaternion - * @note This is the same as scaling by -1 + * @note This is equivalent to `Quat_Scale(v, -1)` * @param[in] q Quaternion to negate * @return -q */ @@ -615,14 +655,14 @@ C3D_FQuat Quat_Multiply(C3D_FQuat lhs, C3D_FQuat rhs); * If p is 1, this returns q. * @param[in] q Base Quaternion * @param[in] p Power - * @return q^p + * @return qp */ C3D_FQuat Quat_Pow(C3D_FQuat q, float p); /** * @brief Cross product of Quaternion and FVec3 - * @param[in] lhs Left-side Quaternion - * @param[in] rhs Right-side FVec3 + * @param[in] q Base Quaternion + * @param[in] v Vector to cross * @return q×v */ C3D_FVec Quat_CrossFVec3(C3D_FQuat q, C3D_FVec v); @@ -664,16 +704,9 @@ C3D_FQuat Quat_RotateY(C3D_FQuat q, float r, bool bRightSide); */ C3D_FQuat Quat_RotateZ(C3D_FQuat q, float r, bool bRightSide); -/** - * @brief Get 4x4 matrix equivalent to Quaternion - * @param[out] m Output matrix - * @param[in] q Input Quaternion - */ -void Mtx_FromQuat(C3D_Mtx* m, C3D_FQuat q); - /** * @brief Get Quaternion equivalent to 4x4 matrix - * @note If the matrix is orthogonal or special orthogonal, where determinant(matrix) = +1.0f, then the matrix can be converted. + * @note If the matrix is orthogonal or special orthogonal, where determinant(matrix) = +1.0f, then the matrix can be converted. * @param[in] m Input Matrix * @return Generated Quaternion */ @@ -692,7 +725,7 @@ static inline C3D_FQuat Quat_Identity(void) /** * @brief Quaternion conjugate * @param[in] q Quaternion of which to get conjugate - * @return Conjugate of q + * @return q* */ static inline C3D_FQuat Quat_Conjugate(C3D_FQuat q) { @@ -702,9 +735,9 @@ static inline C3D_FQuat Quat_Conjugate(C3D_FQuat q) /** * @brief Quaternion inverse - * @note This is the same as raising to the power of -1 + * @note This is equivalent to `Quat_Pow(v, -1)` * @param[in] q Quaternion of which to get inverse - * @return Inverse of q + * @return q-1 */ static inline C3D_FQuat Quat_Inverse(C3D_FQuat q) { @@ -717,13 +750,13 @@ static inline C3D_FQuat Quat_Inverse(C3D_FQuat q) /** * @brief Cross product of FVec3 and Quaternion - * @param[in] lhs Left-side FVec3 - * @param[in] rhs Right-side Quaternion + * @param[in] v Base FVec3 + * @param[in] q Quaternion to cross * @return v×q */ static inline C3D_FVec FVec3_CrossQuat(C3D_FVec v, C3D_FQuat q) { - // v×q = q^-1×v + // v×q = (q^-1)×v return Quat_CrossFVec3(Quat_Inverse(q), v); } @@ -732,12 +765,13 @@ static inline C3D_FVec FVec3_CrossQuat(C3D_FVec v, C3D_FQuat q) * @param[in] pitch The pitch angle in radians. * @param[in] yaw The yaw angle in radians. * @param[in] roll The roll angle in radians. - * @return C3D_FQuat The Quaternion equivalent with the pitch, yaw, and roll orientations applied. + * @param[in] bRightSide Whether to transform from the right side + * @return C3D_FQuat The Quaternion equivalent with the pitch, yaw, and roll (in that order) orientations applied. */ C3D_FQuat Quat_FromPitchYawRoll(float pitch, float yaw, float roll, bool bRightSide); /** - * @brief Quaternion Look At + * @brief Quaternion Look-At * @param[in] source C3D_FVec Starting position. Origin of rotation. * @param[in] target C3D_FVec Target position to orient towards. * @param[in] forwardVector C3D_FVec The Up vector. @@ -751,6 +785,7 @@ C3D_FQuat Quat_LookAt(C3D_FVec source, C3D_FVec target, C3D_FVec forwardVector, * @param[in] axis C3D_FVec The axis to rotate around at. * @param[in] angle float The angle to rotate. Unit: Radians * @return Quaternion rotation based on the axis and angle. Axis doesn't have to be orthogonal. - */ + */ C3D_FQuat Quat_FromAxisAngle(C3D_FVec axis, float angle); -///@} +/** @} */ +/** @} */ diff --git a/include/c3d/mtxstack.h b/include/c3d/mtxstack.h index 3c86536..1de0c25 100644 --- a/include/c3d/mtxstack.h +++ b/include/c3d/mtxstack.h @@ -1,5 +1,6 @@ #pragma once #include "maths.h" + #define C3D_MTXSTACK_SIZE 8 typedef struct diff --git a/include/c3d/renderbuffer.h b/include/c3d/renderbuffer.h index 40e6ff8..69accb6 100644 --- a/include/c3d/renderbuffer.h +++ b/include/c3d/renderbuffer.h @@ -1,5 +1,4 @@ #pragma once -#include "types.h" #include "texture.h" typedef struct diff --git a/include/c3d/types.h b/include/c3d/types.h index 243b37c..4a3c3c8 100644 --- a/include/c3d/types.h +++ b/include/c3d/types.h @@ -10,23 +10,66 @@ typedef uint32_t u32; typedef u32 C3D_IVec; -typedef union -{ - struct { float w, z, y, x; }; - struct { float r, k, j, i; }; - float c[4]; -} C3D_FVec; - -typedef C3D_FVec C3D_FQuat; - -// Row-major 4x4 matrix -typedef union -{ - C3D_FVec r[4]; // Rows are vectors - float m[4*4]; -} C3D_Mtx; - static inline C3D_IVec IVec_Pack(u8 x, u8 y, u8 z, u8 w) { return (u32)x | ((u32)y << 8) | ((u32)z << 16) | ((u32)w << 24); } + +/** + * @defgroup math_support Math Support Library + * @brief Implementations of matrix, vector, and quaternion operations. + * @{ + */ + +/** + * @struct C3D_FVec + * @brief Float vector + * + * Matches PICA layout + */ +typedef union +{ + /** + * @brief Vector access + */ + struct + { + float w; ///< W-component + float z; ///< Z-component + float y; ///< Y-component + float x; ///< X-component + }; + + /** + * @brief Quaternion access + */ + struct + { + float r; ///< Real component + float k; ///< K-component + float j; ///< J-component + float i; ///< I-component + }; + + /** + * @brief Raw access + */ + float c[4]; +} C3D_FVec; + +/** + * @struct C3D_FQuat + * @brief Float quaternion. See @ref C3D_FVec. + */ +typedef C3D_FVec C3D_FQuat; + +/** + * @struct C3D_Mtx + * @brief Row-major 4x4 matrix + */ +typedef union +{ + C3D_FVec r[4]; ///< Rows are vectors + float m[4*4]; ///< Raw access +} C3D_Mtx; +/** @} */ diff --git a/include/c3d/uniforms.h b/include/c3d/uniforms.h index ddc06b4..9e50153 100644 --- a/include/c3d/uniforms.h +++ b/include/c3d/uniforms.h @@ -1,5 +1,6 @@ #pragma once -#include "types.h" +#include "maths.h" + #define C3D_FVUNIF_COUNT 96 #define C3D_IVUNIF_COUNT 4 diff --git a/include/citro3d.h b/include/citro3d.h index a9f2215..a7df27d 100644 --- a/include/citro3d.h +++ b/include/citro3d.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "c3d/types.h" + #include "c3d/maths.h" #include "c3d/mtxstack.h" @@ -21,6 +22,7 @@ extern "C" { #include "c3d/effect.h" #include "c3d/texture.h" #include "c3d/light.h" +#include "c3d/lightlut.h" #include "c3d/renderbuffer.h" #include "c3d/renderqueue.h" diff --git a/source/attribs.c b/source/attribs.c index 0a32256..6fc5ee4 100644 --- a/source/attribs.c +++ b/source/attribs.c @@ -1,6 +1,5 @@ +#include "internal.h" #include -#include -#include "context.h" void AttrInfo_Init(C3D_AttrInfo* info) { diff --git a/source/base.c b/source/base.c index 28aac3e..d2c237d 100644 --- a/source/base.c +++ b/source/base.c @@ -1,4 +1,7 @@ -#include "context.h" +#include "internal.h" +#include +#include +#include C3D_Context __C3D_Context; @@ -35,7 +38,7 @@ static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex) static aptHookCookie hookCookie; -static void C3Di_AptEventHook(APT_HookType hookType, void* param) +static void C3Di_AptEventHook(APT_HookType hookType, C3D_UNUSED void* param) { C3D_Context* ctx = C3Di_GetContext(); diff --git a/source/buffers.c b/source/buffers.c index a7c54b2..0dc0135 100644 --- a/source/buffers.c +++ b/source/buffers.c @@ -1,6 +1,4 @@ -#include -#include -#include "context.h" +#include "internal.h" #define BUFFER_BASE_PADDR 0x18000000 diff --git a/source/drawArrays.c b/source/drawArrays.c index 07b7720..8305ca1 100644 --- a/source/drawArrays.c +++ b/source/drawArrays.c @@ -1,4 +1,4 @@ -#include "context.h" +#include "internal.h" void C3D_DrawArrays(GPU_Primitive_t primitive, int first, int size) { diff --git a/source/drawElements.c b/source/drawElements.c index a2f08e2..034cb7e 100644 --- a/source/drawElements.c +++ b/source/drawElements.c @@ -1,4 +1,4 @@ -#include "context.h" +#include "internal.h" void C3D_DrawElements(GPU_Primitive_t primitive, int count, int type, const void* indices) { diff --git a/source/effect.c b/source/effect.c index edb84f7..0f0deb8 100644 --- a/source/effect.c +++ b/source/effect.c @@ -1,4 +1,4 @@ -#include "context.h" +#include "internal.h" static inline C3D_Effect* getEffect() { diff --git a/source/immediate.c b/source/immediate.c index 6ba39ab..6924364 100644 --- a/source/immediate.c +++ b/source/immediate.c @@ -1,4 +1,4 @@ -#include "context.h" +#include "internal.h" void C3D_ImmDrawBegin(GPU_Primitive_t primitive) { diff --git a/source/context.h b/source/internal.h similarity index 95% rename from source/context.h rename to source/internal.h index 48fa053..b30253f 100644 --- a/source/context.h +++ b/source/internal.h @@ -1,13 +1,11 @@ #pragma once -#include -#include #include #include -#include -#include -#include #include #include +#include + +#define C3D_UNUSED __attribute__((unused)) typedef struct { diff --git a/source/light.c b/source/light.c index e1d921a..3b87d30 100644 --- a/source/light.c +++ b/source/light.c @@ -1,6 +1,4 @@ -#include -#include "context.h" -#include +#include "internal.h" void C3Di_LightMtlBlend(C3D_Light* light) { @@ -81,7 +79,7 @@ void C3D_LightPosition(C3D_Light* light, C3D_FVec* pos) { // Enable/disable positional light depending on W coordinate light->conf.config &= ~BIT(0); - light->conf.config |= (pos->w == 0.0); + light->conf.config |= (pos->w == 0.0f); light->conf.position[0] = f32tof16(pos->x); light->conf.position[1] = f32tof16(pos->y); light->conf.position[2] = f32tof16(pos->z); diff --git a/source/lightenv.c b/source/lightenv.c index 182766d..cee869c 100644 --- a/source/lightenv.c +++ b/source/lightenv.c @@ -1,5 +1,4 @@ -#include -#include "context.h" +#include "internal.h" static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env) { diff --git a/source/lightlut.c b/source/lightlut.c index b49534a..1b76be3 100644 --- a/source/lightlut.c +++ b/source/lightlut.c @@ -1,5 +1,4 @@ -#include -#include "context.h" +#include "internal.h" void LightLut_FromArray(C3D_LightLut* lut, float* data) { @@ -9,14 +8,14 @@ void LightLut_FromArray(C3D_LightLut* lut, float* data) float in = data[i], diff = data[i+256]; u32 val = 0; - if (in > 0.0) + if (in > 0.0f) { in *= 0x1000; val = (in < 0x1000) ? (u32)in : 0xFFF; } u32 val2 = 0; - if (diff != 0.0) + if (diff != 0.0f) { if (diff < 0) { diff --git a/source/renderbuffer.c b/source/renderbuffer.c index 30db0f8..1d919dc 100644 --- a/source/renderbuffer.c +++ b/source/renderbuffer.c @@ -1,5 +1,5 @@ -#include "context.h" -#include +#include "internal.h" +#include static const u8 colorFmtSizes[] = {2,1,0,0,0}; static const u8 depthFmtSizes[] = {0,0,1,2}; diff --git a/source/renderqueue.c b/source/renderqueue.c index 67dd13b..2a637c4 100644 --- a/source/renderqueue.c +++ b/source/renderqueue.c @@ -1,6 +1,5 @@ -#include "context.h" +#include "internal.h" #include -#include #include static C3D_RenderTarget *firstTarget, *lastTarget; @@ -94,7 +93,7 @@ static void clearTarget(C3D_RenderTarget* target) a->link = target; } -static void onVBlank0(void* unused) +static void onVBlank0(C3D_UNUSED void* unused) { if (!linkedTarget[0]) return; @@ -116,13 +115,13 @@ static void onVBlank0(void* unused) transferTarget(linkedTarget[0]); } -static void onVBlank1(void* unused) +static void onVBlank1(C3D_UNUSED void* unused) { if (linkedTarget[2] && linkedTarget[2]->transferOk) transferTarget(linkedTarget[2]); } -void onRenderFinish(void* unused) +void onRenderFinish(C3D_UNUSED void* unused) { C3D_RenderTarget *a, *next; @@ -152,7 +151,7 @@ void onRenderFinish(void* unused) updateFrameQueue(); } -void onTransferFinish(void* unused) +void onTransferFinish(C3D_UNUSED void* unused) { C3D_RenderTarget* target = transferQueue; if (inSafeTransfer) @@ -174,7 +173,7 @@ void onTransferFinish(void* unused) updateFrameQueue(); } -void onClearDone(void* unused) +void onClearDone(C3D_UNUSED void* unused) { C3D_RenderTarget* target = clearQueue; if (inSafeClear) @@ -228,7 +227,7 @@ static void C3Di_RenderQueueWaitDone(void) gspWaitForAnyEvent(); } -bool checkRenderQueueInit(void) +static bool checkRenderQueueInit(void) { C3D_Context* ctx = C3Di_GetContext(); diff --git a/source/texenv.c b/source/texenv.c index d897d7a..a9dfb09 100644 --- a/source/texenv.c +++ b/source/texenv.c @@ -1,6 +1,4 @@ -#include -#include -#include "context.h" +#include "internal.h" void TexEnv_Init(C3D_TexEnv* env) { diff --git a/source/texture.c b/source/texture.c index c03374a..58cdbbc 100644 --- a/source/texture.c +++ b/source/texture.c @@ -1,5 +1,4 @@ -#include "context.h" -#include +#include "internal.h" // Return bits per pixel static inline size_t fmtSize(GPU_TEXCOLOR fmt) diff --git a/source/uniforms.c b/source/uniforms.c index 10876cc..aecad41 100644 --- a/source/uniforms.c +++ b/source/uniforms.c @@ -1,5 +1,5 @@ +#include "internal.h" #include -//#include C3D_FVec C3D_FVUnif[2][C3D_FVUNIF_COUNT]; C3D_IVec C3D_IVUnif[2][C3D_IVUNIF_COUNT]; diff --git a/test/3ds/source/main.cpp b/test/3ds/source/main.cpp index 018509a..66f129e 100644 --- a/test/3ds/source/main.cpp +++ b/test/3ds/source/main.cpp @@ -105,7 +105,7 @@ struct }; #define num_textures (sizeof(texture)/sizeof(texture[0])) - + void *vbo_data; void sceneInit(shaderProgram_s *program) @@ -133,7 +133,7 @@ void sceneInit(shaderProgram_s *program) C3D_BufInfo* bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); BufInfo_Add(bufInfo, vbo_data, sizeof(attribute_t), 3, 0x210); - + // Load the texture and bind it to the first texture unit for(size_t i = 0; i < num_textures; ++i) { @@ -145,7 +145,7 @@ void sceneInit(shaderProgram_s *program) void *buffer = std::malloc(size); void *p = buffer; - + while(size > 0) { ssize_t rc = ::read(fd, p, size); @@ -845,14 +845,14 @@ void transpose_test() { consoleClear(); C3D_Mtx modelView, check; - + Mtx_Identity(&modelView); Mtx_Translate(&modelView, ((float)(rand() % 100)) + 5.0f, ((float)(rand() % 100)) + 5.0f, ((float)(rand() % 100)) + 5.0f, true); Mtx_RotateX(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true); Mtx_RotateY(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true); Mtx_RotateZ(&modelView, (float)(rand() % 180) * (acos(-1)/180.0f), true); Mtx_Copy(&check, &modelView); - + std::printf("Random Translation:\n"); for (int i = 0; i < 16; i++) { @@ -860,9 +860,9 @@ void transpose_test() if (i % 4 == 3) std::printf("\n"); } - + Mtx_Transpose(&modelView); - + std::printf("Random Translation Transposed:\n"); for (int i = 0; i < 16; i++) { @@ -870,9 +870,9 @@ void transpose_test() if (i % 4 == 3) std::printf("\n"); } - + Mtx_Transpose(&modelView); - + std::printf("Rand-Trans Transposed Transposed:\n"); for (int i = 0; i < 16; i++) { @@ -880,7 +880,7 @@ void transpose_test() if (i % 4 == 3) std::printf("\n"); } - + bool transposeFailCheck = false; for (int i = 0; i < 16; i++) { @@ -890,7 +890,7 @@ void transpose_test() break; } } - + bool transInvFailCheck = false; Mtx_Inverse(&modelView); Mtx_Transpose(&modelView); @@ -905,7 +905,7 @@ void transpose_test() break; } } - + std::printf("Transposed Inverse of RandMatrix:\n"); for (int i = 0; i < 16; i++) { @@ -913,7 +913,7 @@ void transpose_test() if (i % 4 == 3) std::printf("\n"); } - + std::printf("Inverse Transposed of RandMatrix:\n"); for (int i = 0; i < 16; i++) { @@ -921,11 +921,11 @@ void transpose_test() if (i % 4 == 3) std::printf("\n"); } - + std::printf("\n"); std::printf("Transpose(Transpose(A)) = A? %s\n", (transposeFailCheck ? "False" : "True")); std::printf("Inv(Trans(A))=Trans(Inv(A))? %s\n", (transInvFailCheck ? "False" : "True")); - + while(aptMainLoop()) { gspWaitForVBlank(); @@ -988,7 +988,7 @@ int main(int argc, char *argv[]) print_choices(choice); while(aptMainLoop()) - { + { gfxFlushBuffers(); gspWaitForVBlank(); gfxSwapBuffers(); diff --git a/test/pc/main.cpp b/test/pc/main.cpp index b39f908..ac2681f 100644 --- a/test/pc/main.cpp +++ b/test/pc/main.cpp @@ -737,27 +737,27 @@ check_matrix(generator_t &gen, distribution_t &dist) assert(Mtx_MultiplyFVecH(&m, FVec3_New(v.x, v.y, v.z)) == glm::mat4x3(g)*v); } - + // check matrix transpose { C3D_Mtx m; glm::mat4 check; - + randomMatrix(m, gen, dist); - + //Reducing rounding errors, and copying the values over to the check matrix. for(size_t i = 0; i < 16; ++i) { m.m[i] = static_cast(m.m[i]); } - + check = loadMatrix(m); Mtx_Transpose(&m); Mtx_Transpose(&m); assert(m == glm::transpose(glm::transpose(check))); - //Comparing inverse(transpose(m)) == transpose(inverse(m)) + //Comparing inverse(transpose(m)) == transpose(inverse(m)) Mtx_Transpose(&m); Mtx_Inverse(&m); assert(m == glm::transpose(glm::inverse(check)));