diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..de57aab --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.12.0) + +# Set path where samples will be installed +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR} CACHE PATH "Path to where the samples will be installed") + +project(NvAR_SDK CXX) + +set(CMAKE_CONFIGURATION_TYPES "Release") + +# Require C++11 and disable non-standard extensions +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) + +# Set common build path for all targets +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +set(SDK_INCLUDES_PATH ${CMAKE_CURRENT_SOURCE_DIR}/nvar/include) + +# Add target for nvARPose +add_library(nvARPose INTERFACE) +target_include_directories(nvARPose INTERFACE ${SDK_INCLUDES_PATH}) + +set(ENABLE_SAMPLES TRUE) +add_subdirectory(samples) + diff --git a/NVIDIA AR SDK Programming Guide.pdf b/NVIDIA AR SDK Programming Guide.pdf new file mode 100644 index 0000000..46924bf Binary files /dev/null and b/NVIDIA AR SDK Programming Guide.pdf differ diff --git a/nvar/include/nvAR.h b/nvar/include/nvAR.h new file mode 100644 index 0000000..34a3f3f --- /dev/null +++ b/nvar/include/nvAR.h @@ -0,0 +1,99 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ + +#ifndef NvAR_H +#define NvAR_H + +#include "nvAR_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Forward declaration for CUDA API +// CUstream and cudaStream_t are CUstream_st* +struct CUstream_st; +typedef struct CUstream_st *CUstream; + +typedef struct nvAR_Feature nvAR_Feature; +typedef struct nvAR_Feature *NvAR_FeatureHandle; + +//! Create a new feature instantiation. +//! \param[in] InFeatureID The selector code for the desired feature. +//! \param[out] handle Handle to the feature instance. +NvCV_Status NvAR_API NvAR_Create(NvAR_FeatureID featureID, NvAR_FeatureHandle *handle); + +//! Load the model based on the set params. +//! \param[in] handle Handle to the feature instance. +NvCV_Status NvAR_API NvAR_Load(NvAR_FeatureHandle handle); + +//! Run the selected feature instance. +//! \param[in] handle Handle to the feature instance. +NvCV_Status NvAR_API NvAR_Run(NvAR_FeatureHandle handle); + +//! Delete a previously created feature instance. +//! \param[in] handle Handle to the feature instance. +NvCV_Status NvAR_API NvAR_Destroy(NvAR_FeatureHandle handle); + +//! Wrapper for cudaStreamCreate(), if it is desired to avoid linking with the cuda lib. +//! \param[out] stream A place to store the newly allocated stream. +NvCV_Status NvAR_API NvAR_CudaStreamCreate(CUstream *stream); + +//! Wrapper for cudaStreamDestroy(), if it is desired to avoid linking with the cuda lib. +//! \param[in] stream The stream to destroy. +NvCV_Status NvAR_API NvAR_CudaStreamDestroy(CUstream stream); + +//! Set the value of the selected parameter. +//! \param[in] handle Handle to the feature instance. +//! \param[in] name The selector of the feature parameter to configure. +//! \param[in] val The value to be assigned to the selected feature parameter. +NvCV_Status NvAR_API NvAR_SetU32(NvAR_FeatureHandle handle, const char *name, unsigned int val); +NvCV_Status NvAR_API NvAR_SetS32(NvAR_FeatureHandle handle, const char *name, int val); +NvCV_Status NvAR_API NvAR_SetF32(NvAR_FeatureHandle handle, const char *name, float val); +NvCV_Status NvAR_API NvAR_SetF64(NvAR_FeatureHandle handle, const char *name, double val); +NvCV_Status NvAR_API NvAR_SetU64(NvAR_FeatureHandle handle, const char *name, unsigned long long val); +NvCV_Status NvAR_API NvAR_SetObject(NvAR_FeatureHandle handle, const char *name, void *ptr, unsigned long typeSize); +NvCV_Status NvAR_API NvAR_SetString(NvAR_FeatureHandle handle, const char *name, const char *str); +NvCV_Status NvAR_API NvAR_SetCudaStream(NvAR_FeatureHandle handle, const char *name, CUstream stream); +NvCV_Status NvAR_API NvAR_SetF32Array(NvAR_FeatureHandle handle, const char *name, float *vals, int /*count*/); + +//! Get the value of the selected parameter. +//! \param[in] handle Handle to the feature instance. +//! \param[in] name The selector of the feature parameter to retrieve. +//! \param[out] val Place to store the retrieved parameter. +NvCV_Status NvAR_API NvAR_GetU32(NvAR_FeatureHandle handle, const char *name, unsigned int *val); +NvCV_Status NvAR_API NvAR_GetS32(NvAR_FeatureHandle handle, const char *name, int *val); +NvCV_Status NvAR_API NvAR_GetF32(NvAR_FeatureHandle handle, const char *name, float *val); +NvCV_Status NvAR_API NvAR_GetF64(NvAR_FeatureHandle handle, const char *name, double *val); +NvCV_Status NvAR_API NvAR_GetU64(NvAR_FeatureHandle handle, const char *name, unsigned long long *val); +NvCV_Status NvAR_API NvAR_GetObject(NvAR_FeatureHandle handle, const char *name, const void **ptr, + unsigned long typeSize); +NvCV_Status NvAR_API NvAR_GetString(NvAR_FeatureHandle handle, const char *name, const char **str); +NvCV_Status NvAR_API NvAR_GetCudaStream(NvAR_FeatureHandle handle, const char *name, const CUstream *stream); +NvCV_Status NvAR_API NvAR_GetF32Array(NvAR_FeatureHandle handle, const char *name, const float **vals, int */*count*/); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // #define NvAR_H diff --git a/nvar/include/nvAR_defs.h b/nvar/include/nvAR_defs.h new file mode 100644 index 0000000..85951a0 --- /dev/null +++ b/nvar/include/nvAR_defs.h @@ -0,0 +1,162 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ +#ifndef NvAR_DEFS_H +#define NvAR_DEFS_H + +#include +#include +#include + +#ifdef _WIN32 +#ifdef NVAR_API_EXPORT +#define NvAR_API __declspec(dllexport) __cdecl +#else +#define NvAR_API +#endif +#elif linux +// TODO: Linux code goes here +#endif + +typedef struct NvAR_Vector3f +{ + float vec[3]; +} NvAR_Vector3f; + +typedef struct NvAR_Vector3u16 { + unsigned short vec[3]; +} NvAR_Vector3u16; + +typedef struct NvAR_Rect { + float x, y, width, height; +} NvAR_Rect; + +typedef struct NvAR_BBoxes { + NvAR_Rect *boxes; + uint8_t num_boxes; + uint8_t max_boxes; +} NvAR_BBoxes; + +typedef struct NvAR_FaceMesh { + NvAR_Vector3f *vertices; ///< Mesh 3D vertex positions. + size_t num_vertices; + NvAR_Vector3u16 *tvi; ///< Mesh triangle's vertex indices + size_t num_tri_idx; +} NvAR_FaceMesh; + +typedef struct NvAR_Frustum { + float left; + float right; + float bottom; + float top; +} NvAR_Frustum; + +typedef struct NvAR_Quaternion { + float x, y, z, w; +} NvAR_Quaternion; + +typedef struct NvAR_Point2f { + float x, y; +} NvAR_Point2f; + +typedef struct NvAR_Vector2f { + float x, y; +} NvAR_Vector2f; + +typedef struct NvAR_RenderingParams { + NvAR_Frustum frustum; + NvAR_Quaternion rotation; + NvAR_Vector3f translation; +} NvAR_RenderingParams; + +// Parameters provided by client application +typedef const char* NvAR_FeatureID; +#define NvAR_Feature_FaceDetection "FaceDetection" +#define NvAR_Feature_LandmarkDetection "LandmarkDetection" +#define NvAR_Feature_Face3DReconstruction "Face3DReconstruction" + +#define NvAR_Parameter_Input(Name) "NvAR_Parameter_Input_" #Name +#define NvAR_Parameter_Output(Name) "NvAR_Parameter_Output_" #Name +#define NvAR_Parameter_Config(Name) "NvAR_Parameter_Config_" #Name + +/* +Parameters supported by each NvAR_FeatureID + +*******NvAR_Feature_FaceDetection******* +Config: +NvAR_Parameter_Config(FeatureDescription) +NvAR_Parameter_Config(CUDAStream) +NvAR_Parameter_Config(TRTModelDir) +NvAR_Parameter_Config(Temporal) + +Input: +NvAR_Parameter_Input(Image) + +Output: +NvAR_Parameter_Output(BoundingBoxes) +NvAR_Parameter_Output(BoundingBoxesConfidence) - OPTIONAL + +*******NvAR_Feature_LandmarkDetection******* +Config: +NvAR_Parameter_Config(FeatureDescription) +NvAR_Parameter_Config(CUDAStream) +NvAR_Parameter_Config(ModelDir) +NvAR_Parameter_Config(BatchSize) +NvAR_Parameter_Config(Landmarks_Size) +NvAR_Parameter_Config(LandmarksConfidence_Size) +NvAR_Parameter_Config(Temporal) + +Input: +NvAR_Parameter_Input(Image) +NvAR_Parameter_Input(BoundingBoxes) - OPTIONAL + +Output: +NvAR_Parameter_Output(BoundingBoxes) - OPTIONAL +NvAR_Parameter_Output(Landmarks) +NvAR_Parameter_Output(Pose) - OPTIONAL +NvAR_Parameter_Output(LandmarksConfidence) - OPTIONAL + +*******NvAR_Feature_Face3DReconstruction******* +Config +NvAR_Parameter_Config(FeatureDescription) +NvAR_Parameter_Config(ModelDir) +NvAR_Parameter_Config(Landmarks_Size) +NvAR_Parameter_Config(CUDAStream) -OPTIONAL +NvAR_Parameter_Config(Temporal) - OPTIONAL + +Input: +NvAR_Parameter_Input(Width) +NvAR_Parameter_Input(Height) +NvAR_Parameter_Input(Image) - OPTIONAL +NvAR_Parameter_Input(Landmarks) - OPTIONAL + +Output: +NvAR_Parameter_Output(FaceMesh) +NvAR_Parameter_Output(RenderingParams) +NvAR_Parameter_Output(BoundingBoxes) - OPTIONAL +NvAR_Parameter_Output(BoundingBoxesConfidence) - OPTIONAL +NvAR_Parameter_Output(Landmarks) - OPTIONAL +NvAR_Parameter_Output(Pose) - OPTIONAL +NvAR_Parameter_Output(LandmarksConfidence) - OPTIONAL +*/ + +#endif // NvAR_DEFS_H diff --git a/nvar/include/nvCVImage.h b/nvar/include/nvCVImage.h new file mode 100644 index 0000000..f63b71c --- /dev/null +++ b/nvar/include/nvCVImage.h @@ -0,0 +1,466 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ + +#ifndef __NVCVIMAGE_H__ +#define __NVCVIMAGE_H__ + +#include "nvCVStatus.h" + +#ifdef __cplusplus +extern "C" { +#endif // ___cplusplus + +struct CUstream_st; // typedef struct CUstream_st *CUstream; + +//! The format of pixels in an image. +typedef enum NvCVImage_PixelFormat { + NVCV_FORMAT_UNKNOWN = 0, //!< Unknown pixel format. + NVCV_Y = 1, //!< Luminance (gray). + NVCV_A = 2, //!< Alpha (opacity) + NVCV_YA = 3, //!< { Luminance, Alpha } + NVCV_RGB = 4, //!< { Red, Green, Blue } + NVCV_BGR = 5, //!< { Red, Green, Blue } + NVCV_RGBA = 6, //!< { Red, Green, Blue, Alpha } + NVCV_BGRA = 7, //!< { Red, Green, Blue, Alpha } + NVCV_YUV420 = 8, //!< Luminance and subsampled Chrominance { Y, Cb, Cr } + NVCV_YUV422 = 9, //!< Luminance and subsampled Chrominance { Y, Cb, Cr } +} NvCVImage_PixelFormat; + + +//! The data type used to represent each component of an image. +typedef enum NvCVImage_ComponentType { + NVCV_TYPE_UNKNOWN = 0, //!< Unknown type of component. + NVCV_U8 = 1, //!< Unsigned 8-bit integer. + NVCV_U16 = 2, //!< Unsigned 16-bit integer. + NVCV_S16 = 3, //!< Signed 16-bit integer. + NVCV_F16 = 4, //!< 16-bit floating-point. + NVCV_U32 = 5, //!< Unsigned 32-bit integer. + NVCV_S32 = 6, //!< Signed 32-bit integer. + NVCV_F32 = 7, //!< 32-bit floating-point (float). + NVCV_U64 = 8, //!< Unsigned 64-bit integer. + NVCV_S64 = 9, //!< Signed 64-bit integer. + NVCV_F64 = 10, //!< 64-bit floating-point (double). +} NvCVImage_ComponentType; + + +//! Value for the planar field or isPlanar argument. Two values are currently accommodated for RGB: +//! Interleaved or chunky storage locates all components of a pixel adjacent in memory, +//! e.g. RGBRGBRGB... (denoted [RGB]). +//! Planar storage locates the same component of all pixels adjacent in memory, +//! e.g. RRRRR...GGGGG...BBBBB... (denoted [R][G][B]) +//! YUV has many more variants. +//! 4:2:2 can be chunky, planar or semi-planar, with different orderings. +//! 4:2:0 can be planar or semi-planar, with different orderings. +//! Aliases are provided for FOURCCs defined at fourcc.org. +//! Note: the LSB can be used to distinguish between chunky and planar formats. +#define NVCV_INTERLEAVED 0 //!< All components of pixel(x,y) are adjacent (same as chunky) (default for non-YUV). +#define NVCV_CHUNKY 0 //!< All components of pixel(x,y) are adjacent (same as interleaved). +#define NVCV_PLANAR 1 //!< The same component of all pixels are adjacent. +#define NVCV_UYVY 2 //!< [UYVY] Chunky 4:2:2 (default for 4:2:2) +#define NVCV_VYUY 4 //!< [VYUY] Chunky 4:2:2 +#define NVCV_YUYV 6 //!< [YUYV] Chunky 4:2:2 +#define NVCV_YVYU 8 //!< [YVYU] Chunky 4:2:2 +#define NVCV_YUV 3 //!< [Y][U][V] Planar 4:2:2 or 4:2:0 +#define NVCV_YVU 5 //!< [Y][V][U] Planar 4:2:2 or 4:2:0 +#define NVCV_YCUV 7 //!< [Y][UV] Semi-planar 4:2:2 or 4:2:0 (default for 4:2:0) +#define NVCV_YCVU 9 //!< [Y][VU] Semi-planar 4:2:2 or 4:2:0 +#define NVCV_YUY2 NVCV_YUYV //!< [YUYV] Chunky 4:2:2 +#define NVCV_I420 NVCV_YUV //!< [Y][U][V] Planar 4:2:2 or 4:2:0 +#define NVCV_IYUV NVCV_YUV //!< [Y][U][V] Planar 4:2:2 or 4:2:0 +#define NVCV_YV12 NVCV_YVU //!< [Y][V][U] Planar 4:2:2 or 4:2:0 +#define NVCV_NV12 NVCV_YCUV //!< [Y][UV] Semi-planar 4:2:2 or 4:2:0 (default for 4:2:0) +#define NVCV_NV21 NVCV_YCVU //!< [Y][VU] Semi-planar 4:2:2 or 4:2:0 + +//! The following are ORed together for the colorspace field for YUV. +//! NVCV_601 and NVCV_709 describe the color axes of YUV. +//! NVCV_VIDEO_RANGE and NVCV_VIDEO_RANGE describe the range, [16, 235] or [0, 255], respectively. +//! NVCV_CHROMA_COSITED and NVCV_CHROMA_INTSTITIAL describe the location of the chroma samples. +#define NVCV_601 0 //!< The Rec.601 YUV colorspace, typically used for SD. +#define NVCV_709 1 //!< The Rec.709 YUV colorspace, typically used for HD. +#define NVCV_VIDEO_RANGE 0 //!< The video range is [16, 235]. +#define NVCV_FULL_RANGE 4 //!< The video range is [ 0, 255]. +#define NVCV_CHROMA_COSITED 0 //!< The chroma is sampled at the same location as the luma samples horizontally. +#define NVCV_CHROMA_INTSTITIAL 8 //!< The chroma is sampled between luma samples horizontally. +#define NVCV_CHROMA_MPEG2 NVCV_CHROMA_COSITED +#define NVCV_CHROMA_MPEG1 NVCV_CHROMA_INTSTITIAL + +//! This is the value for the gpuMem field or the onGPU argument. Two values are currently accommodated: +//! CPU indicates standard CPU memory. +//! GPU indicates CUDA buffers. +#define NVCV_CPU 0 //!< The buffer is stored in CPU memory. +#define NVCV_GPU 1 //!< The buffer is stored in CUDA memory. +#define NVCV_CUDA 1 //!< The buffer is stored in CUDA memory. + +//! Image descriptor. +typedef struct +#ifdef _MSC_VER +__declspec(dllexport) +#endif // _MSC_VER +NvCVImage { + unsigned int width; //!< The number of pixels horizontally in the image. + unsigned int height; //!< The number of pixels vertically in the image. + signed int pitch; //!< The byte stride between pixels vertically. + NvCVImage_PixelFormat pixelFormat; //!< The format of the pixels in the image. + NvCVImage_ComponentType componentType; //!< The data type used to represent each component of the image. + unsigned char pixelBytes; //!< The number of bytes in a chunky pixel. + unsigned char componentBytes; //!< The number of bytes in each pixel component. + unsigned char numComponents; //!< The number of components in each pixel. + unsigned char planar; //!< 0=chunky, 1=planar, 2=semi-planar (NV12, NV21). + unsigned char gpuMem; //!< 0=cpu mem, 1=cuda mem, + unsigned char colorspace; //!< an OR of colorspace, range and chroma phase. + unsigned char reserved[2]; //!< For structure padding and future expansion. Set to 0. + void *pixels; //!< Pointer to pixel(0,0) in the image. + void *deletePtr; //!< Buffer memory to be deleted (can be NULL). + void (*deleteProc)(void *p); //!< Delete procedure to call rather than free(). + unsigned long long bufferBytes; //!< The maximum amount of memory available through pixels. + + +#ifdef __cplusplus + + //! Default constructor: fill with 0. + inline NvCVImage(); + + //! Allocation constructor. + //! \param[in] width the number of pixels horizontally. + //! \param[in] height the number of pixels vertically. + //! \param[in] format the format of the pixels. + //! \param[in] type the type of each pixel component. + //! \param[in] isPlanar One of { NVCV_CHUNKY, NVCV_PLANAR }. + //! \param[in] onGPU One of { NVCV_CPU, NVCV_GPU } + //! \param[in] alignment row byte alignment. Choose 0 or a power of 2. + //! 1: yields no gap whatsoever between scanlines; + //! 0: default alignment: 4 on CPU, and cudaMallocPitch's choice on GPU. + //! Other common values are 16 or 32 for cache line size. + inline NvCVImage(unsigned width, unsigned height, NvCVImage_PixelFormat format, NvCVImage_ComponentType type, + unsigned isPlanar = 0, unsigned onGPU = 0, unsigned alignment = 0); + + //! Subimage constructor. + //! \param[in] fullImg the full image, from which this subImage view is to be created. + //! \param[in] x the left edge of the subImage, in reference to the full image. + //! \param[in] y the top edge of the subImage, in reference to the full image. + //! \param[in] width the width of the subImage, in pixels. + //! \param[in] height the height of the subImage, in pixels. + //! \bug This does not work for planar or semi-planar formats, neither RGB nor YUV. + //! \note This does work for all chunky formats, including UYVY, VYUY, YUYV, YVYU. + inline NvCVImage(NvCVImage *fullImg, int x, int y, unsigned width, unsigned height); + + //! Destructor + inline ~NvCVImage(); + + //! Copy a rectangular subimage. This works for CPU->CPU, CPU->GPU, GPU->GPU, and GPU->CPU. + //! \param[in] src The source image from which to copy. + //! \param[in] srcX The left coordinate of the src rectangle. + //! \param[in] srcY The top coordinate of the src rectangle. + //! \param[in] dstX The left coordinate of the dst rectangle. + //! \param[in] dstY The top coordinate of the dst rectangle. + //! \param[in] width The width of the rectangle to be copied, in pixels. + //! \param[in] height The height of the rectangle to be copied, in pixels. + //! \note NvCVImage_Transfer() can handle more cases. + //! \return NVCV_SUCCESS if successful + //! \return NVCV_ERR_MISMATCH if the formats are different + //! \return NVCV_ERR_CUDA if a CUDA error occurred + //! \return NVCV_ERR_PIXELFORMAT if the pixel format is not yet accommodated. + //! \bug This does not work for planar or semi-planar formats, neither RGB nor YUV. + //! \note This does work for all chunky formats, including UYVY, VYUY, YUYV, YVYU. + inline NvCV_Status copyFrom(const NvCVImage *src, int srcX, int srcY, int dstX, int dstY, unsigned width, unsigned height); + + //! Copy from one image to another. This works for CPU->CPU, CPU->GPU, GPU->GPU, and GPU->CPU. + //! \param[in] src The source image from which to copy. + //! \note NvCVImage_Transfer() can handle more cases. + //! \return NVCV_SUCCESS if successful + //! \return NVCV_ERR_MISMATCH if the formats are different + //! \return NVCV_ERR_CUDA if a CUDA error occurred + //! \return NVCV_ERR_PIXELFORMAT if the pixel format is not yet accommodated. + inline NvCV_Status copyFrom(const NvCVImage *src); + +#endif // ___cplusplus +} NvCVImage; + + +//! Initialize an image. The C++ constructors can initialize this appropriately. +//! This is called by the C++ constructor, but C code should call this explicitly. +//! \param[in,out] im the image to initialize. +//! \param[in] width the desired width of the image, in pixels. +//! \param[in] height the desired height of the image, in pixels. +//! \param[in] pitch the byte stride between pixels vertically. +//! \param[in] pixels a pointer to the pixel buffer. +//! \param[in] format the format of the pixels. +//! \param[in] type the type of the components of the pixels. +//! \param[in] isPlanar One of { NVCV_CHUNKY, NVCV_PLANAR }. +//! \param[in] onGPU Location of the buffer: one of { NVCV_CPU, NVCV_GPU } +//! \return NVCV_SUCCESS if successful +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not yet accommodated. +NvCV_Status NvCV_API NvCVImage_Init(NvCVImage *im, unsigned width, unsigned height, int pitch, void *pixels, + NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU); + + +//! Initialize a view into a subset of an existing image. +//! No memory is allocated -- the fullImg buffer is used. +//! \param[in] subImg the sub-image view into the existing full image. +//! \param[in] fullImg the existing full image. +//! \param[in] x the left edge of the sub-image, as coordinate of the full image. +//! \param[in] y the top edge of the sub-image, as coordinate of the full image. +//! \param[in] width the desired width of the subImage, in pixels. +//! \param[in] height the desired height of the subImage, in pixels. +//! \bug This does not work for planar or semi-planar formats, neither RGB nor YUV. +//! \note This does work for all chunky formats, including UYVY, VYUY, YUYV, YVYU. +void NvCV_API NvCVImage_InitView(NvCVImage *subImg, NvCVImage *fullImg, int x, int y, unsigned width, unsigned height); + + +//! Allocate memory for, and initialize an image. This assumes that the image data structure has nothing meaningful in it. +//! This is called by the C++ constructor, but C code can call this to allocate an image. +//! \param[in,out] im the image to initialize. +//! \param[in] width the desired width of the image, in pixels. +//! \param[in] height the desired height of the image, in pixels. +//! \param[in] format the format of the pixels. +//! \param[in] type the type of the components of the pixels. +//! \param[in] isPlanar One of { NVCV_CHUNKY, NVCV_PLANAR }. +//! \param[in] onGPU Location of the buffer: one of { NVCV_CPU, NVCV_GPU } +//! \param[in] alignment row byte alignment. Choose 0 or a power of 2. +//! 1: yields no gap whatsoever between scanlines; +//! 0: default alignment: 4 on CPU, and cudaMallocPitch's choice on GPU. +//! Other common values are 16 or 32 for cache line size. +//! \return NVCV_SUCCESS if the operation was successful. +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not accommodated. +//! \return NVCV_ERR_MEMORY if there is not enough memory to allocate the buffer. +NvCV_Status NvCV_API NvCVImage_Alloc(NvCVImage *im, unsigned width, unsigned height, NvCVImage_PixelFormat format, + NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment); + + +//! Reallocate memory for, and initialize an image. This assumes that the image is valid. +//! It will check bufferBytes to see if enough memory is already available, and will reshape rather than realloc if true. +//! Otherwise, it will free the previous buffer and reallocate a new one. +//! \param[in,out] im the image to initialize. +//! \param[in] width the desired width of the image, in pixels. +//! \param[in] height the desired height of the image, in pixels. +//! \param[in] format the format of the pixels. +//! \param[in] type the type of the components of the pixels. +//! \param[in] isPlanar One of { NVCV_CHUNKY, NVCV_PLANAR }. +//! \param[in] onGPU Location of the buffer: one of { NVCV_CPU, NVCV_GPU } +//! \param[in] alignment row byte alignment. Choose 0 or a power of 2. +//! 1: yields no gap whatsoever between scanlines; +//! 0: default alignment: 4 on CPU, and cudaMallocPitch's choice on GPU. +//! Other common values are 16 or 32 for cache line size. +//! \return NVCV_SUCCESS if the operation was successful. +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not accommodated. +//! \return NVCV_ERR_MEMORY if there is not enough memory to allocate the buffer. +NvCV_Status NvCV_API NvCVImage_Realloc(NvCVImage *im, unsigned width, unsigned height, NvCVImage_PixelFormat format, + NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment); + + +//! Deallocate the image buffer from the image. The image is not deallocated. +//! param[in,out] im the image whose buffer is to be deallocated. +void NvCV_API NvCVImage_Dealloc(NvCVImage *im); + + +//! Allocate a new image, with storage (C-style constructor). +//! \param[in] width the desired width of the image, in pixels. +//! \param[in] height the desired height of the image, in pixels. +//! \param[in] format the format of the pixels. +//! \param[in] type the type of the components of the pixels. +//! \param[in] isPlanar One of { NVCV_CHUNKY, NVCV_PLANAR }. +//! \param[in] onGPU Location of the buffer: one of { NVCV_CPU, NVCV_GPU } +//! \param[in] alignment row byte alignment. Choose 0 or a power of 2. +//! 1: yields no gap whatsoever between scanlines; +//! 0: default alignment: 4 on CPU, and cudaMallocPitch's choice on GPU. +//! Other common values are 16 or 32 for cache line size. +//! \param[out] *out will be a pointer to the new image if successful; otherwise NULL. +//! \return NVCV_SUCCESS if the operation was successful. +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not accommodated. +//! \return NVCV_ERR_MEMORY if there is not enough memory to allocate the buffer. +NvCV_Status NvCV_API NvCVImage_Create(unsigned width, unsigned height, NvCVImage_PixelFormat format, + NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment, NvCVImage **out); + + +//! Deallocate the image allocated with NvCVImage_Create() (C-style destructor). +void NvCV_API NvCVImage_Destroy(NvCVImage *im); + + +//! Get offsets for the components of a pixel format. +//! These are not byte offsets, but component offsets. +//! \param[in] format the pixel format to be interrogated. +//! \param[out] rOff a place to store the offset for the red channel (can be NULL). +//! \param[out] gOff a place to store the offset for the green channel (can be NULL). +//! \param[out] bOff a place to store the offset for the blue channel (can be NULL). +//! \param[out] aOff a place to store the offset for the alpha channel (can be NULL). +//! \param[out] yOff a place to store the offset for the luminance channel (can be NULL). +void NvCV_API NvCVImage_ComponentOffsets(NvCVImage_PixelFormat format, int *rOff, int *gOff, int *bOff, int *aOff, int *yOff); + + +//! Transfer one image to another, with a limited set of conversions. +//! If any of the images resides on the GPU, it may run asynchronously, +//! so cudaStreamSynchronize() should be called if it is necessary to run synchronously. +//! Conversions are between +//! - RGBu8 --> RGBu8, where the RGB components are in any order; +//! - RGBu8 <--> RGBf32, where the RGB components are in any order (e.g. BGR, RGB); +//! - RGBu8 --> GRAYf32, where the RGB components are in any order; +//! - RGBf32 --> RGBAu8, setting A=255, where the RGB and RGBA components are in any order; +//! - RGBAu8 --> RGBu8, by removing the alpha component; +//! - GRAYf32 --> GRAYu8; +//! - GRAYu8 --> GRAYu8, where the RGB components are in any order (also works with ALPHAu8); +//! - ALPHAu8 --> RGBAu8, (insertion) without touching the RGB components. +//! - GRAYu8 --> RGBu8, by replicating gray into all RGB components. +//! - YUVu8 --> RGBu8, though colorspace field needs to be set manually prior to calling. +//! - chunky <--> planar; +//! - CPU <--> GPU; +//! Additionally, when the src and dst formats are the same, all formats are accommodated on CPU and GPU, +//! and this can be used as a replacement for cudaMemcpy2DAsync() (which it utilizes). +//! +//! When there is some kind of conversion AND the src and dst reside on different processors (CPU, GPU), +//! it is necessary to have a temporary GPU buffer, which is reshaped as needed to match the characteristics +//! of the CPU image. The same temporary image can be used in subsequent calls to NvCVImage_Transfer(), +//! regardless of the shape, format or component type, as it will grow as needed to accommodate +//! the largest memory requirement. The recommended usage for most cases is to supply an empty image +//! as the temporary; if it is not needed, no buffer is allocated. NULL can be supplied as the tmp +//! image, in which case an ephemeral buffer is allocated if needed, with resultant +//! performance degradation for image sequences. +//! +//! \param[in] src the source image. +//! \param[out] dst the destination image. +//! \param[in] scale a scale factor that can be applied when one (but not both) of the images +//! is based on floating-point components; this parameter is ignored when all image components +//! are represented with integer data types, or all image components are represented with +//! floating-point data types. +//! \param[in] stream the stream on which to perform the copy. This is ignored if both images reside on the CPU. +//! \param[in,out] tmp a temporary buffer that is sometimes needed when transferring images +//! between the CPU and GPU in either direction (can be empty or NULL). +//! It has the same characteristics as the CPU image, but it resides on the GPU. +//! \return NVCV_SUCCESS if successful, +//! NVCV_ERR_PIXELFORMAT if one of the pixel formats is not accommodated. +//! NVCV_ERR_CUDA if a CUDA error has occurred. +//! NVCV_ERR_GENERAL if an otherwise unspecified error has occurred. +NvCV_Status NvCV_API NvCVImage_Transfer( + const NvCVImage *src, NvCVImage *dst, float scale, struct CUstream_st *stream, NvCVImage *tmp); + + +//! Composite one BGRu8 source image over another using the given matte. +//! \param[in] src the source BGRu8 (or RGBu8) image. +//! \param[in] mat the matte Yu8 (or Au8) image, indicating where the src should come through. +//! \param[out] dst the destination BGRu8 (or RGBu8) image. +//! \return NVCV_SUCCESS if the operation was successful. +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not accommodated. +//! \bug This is only implemented for 3-component u8 src and dst, and 1-component mat, +//! where all images are resident on the CPU. +NvCV_Status NvCV_API NvCVImage_Composite(const NvCVImage *src, const NvCVImage *mat, NvCVImage *dst); + + +//! Composite a BGRu8 source image over a constant color field using the given matte. +//! \param[in] src the source BGRu8 (or RGBu8) image. +//! \param[in] mat the matte Yu8 (or Au8) image, indicating where the src should come through. +//! \param[in] bgColor the desired flat background color, with the same component ordering as the src and dst. +//! \param[in,out] dst the destination BGRu8 (or RGBu8) image. May be the same as src. +//! \return NVCV_SUCCESS if the operation was successful. +//! \return NVCV_ERR_PIXELFORMAT if the pixel format is not accommodated. +//! \bug This is only implemented for 3-component u8 src and dst, and 1-component mat, +//! where all images are resident on the CPU. +NvCV_Status NvCV_API NvCVImage_CompositeOverConstant( + const NvCVImage *src, const NvCVImage *mat, const unsigned char bgColor[3], NvCVImage *dst); + + +//! Flip the image vertically. +//! No actual pixels are moved: it is just an accounting procedure. +//! This is extremely low overhead, but requires appropriate interpretation of the pitch. +//! Flipping twice yields the original orientation. +//! \param[in] src the source image (NULL implies src == dst). +//! \param[out] dst the flipped image (can be the same as the src). +//! \return NVCV_SUCCESS if successful. +//! \return NVCV_ERR_PIXELFORMAT for most planar formats. +//! \bug This does not work for planar or semi-planar formats, neither RGB nor YUV. +//! \note This does work for all chunky formats, including UYVY, VYUY, YUYV, YVYU. +NvCV_Status NvCV_API NvCVImage_FlipY(const NvCVImage *src, NvCVImage *dst); + + +//! Get the pointers for YUV, based on the format. +//! \param[in] im The image to be deconstructed. +//! \param[out] y A place to store the pointer to y(0,0). +//! \param[out] u A place to store the pointer to u(0,0). +//! \param[out] v A place to store the pointer to v(0,0). +//! \param[out] yPixBytes A place to store the byte stride between luma samples horizontally. +//! \param[out] cPixBytes A place to store the byte stride between chroma samples horizontally. +//! \param[out] yRowBytes A place to store the byte stride between luma samples vertically. +//! \param[out] cRowBytes A place to store the byte stride between chroma samples vertically. +//! \return NVCV_SUCCESS If the information was gathered successfully. +//! NVCV_ERR_PIXELFORMAT Otherwise. +NvCV_Status NvCV_API NvCVImage_GetYUVPointers(NvCVImage *im, + unsigned char **y, unsigned char **u, unsigned char **v, + int *yPixBytes, int *cPixBytes, int *yRowBytes, int *cRowBytes); + + +#ifdef __cplusplus +} // extern "C" + +/******************************************************************************** + * NvCVImage default constructor + ********************************************************************************/ + +NvCVImage::NvCVImage() { + pixels = nullptr; + (void)NvCVImage_Alloc(this, 0, 0, NVCV_FORMAT_UNKNOWN, NVCV_TYPE_UNKNOWN, 0, 0, 0); +} + +/******************************************************************************** + * NvCVImage allocation constructor + ********************************************************************************/ + +NvCVImage::NvCVImage(unsigned width, unsigned height, NvCVImage_PixelFormat format, NvCVImage_ComponentType type, + unsigned isPlanar, unsigned onGPU, unsigned alignment) { + pixels = nullptr; + (void)NvCVImage_Alloc(this, width, height, format, type, isPlanar, onGPU, alignment); +} + +/******************************************************************************** + * Subimage constructor + ********************************************************************************/ + +NvCVImage::NvCVImage(NvCVImage *fullImg, int x, int y, unsigned width, unsigned height) { + NvCVImage_InitView(this, fullImg, x, y, width, height); +} + +/******************************************************************************** + * NvCVImage destructor + ********************************************************************************/ + +NvCVImage::~NvCVImage() { NvCVImage_Dealloc(this); } + +/******************************************************************************** + * copy subimage + ********************************************************************************/ + +NvCV_Status NvCVImage::copyFrom(const NvCVImage *src, int srcX, int srcY, int dstX, int dstY, unsigned wd, + unsigned ht) { + NvCVImage srcView, dstView; + NvCVImage_InitView(&srcView, const_cast(src), srcX, srcY, wd, ht); + NvCVImage_InitView(&dstView, this, dstX, dstY, wd, ht); + return NvCVImage_Transfer(&srcView, &dstView, 1.f, 0, nullptr); +} + +/******************************************************************************** + * copy image + ********************************************************************************/ + +NvCV_Status NvCVImage::copyFrom(const NvCVImage *src) { return NvCVImage_Transfer(src, this, 1.f, 0, nullptr); } + + +#endif // ___cplusplus + +#endif // __NVCVIMAGE_H__ diff --git a/nvar/include/nvCVStatus.h b/nvar/include/nvCVStatus.h new file mode 100644 index 0000000..5c32654 --- /dev/null +++ b/nvar/include/nvCVStatus.h @@ -0,0 +1,94 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ + +#ifndef __NVCVSTATUS_H__ +#define __NVCVSTATUS_H__ + +#ifndef NvCV_API + #ifdef _WIN32 + #ifdef NVCV_API_EXPORT + #define NvCV_API __declspec(dllexport) __cdecl + #else + #define NvCV_API + #endif + #else //if linux + #define NvCV_API // TODO: Linux code goes here + #endif // _WIN32 or linux +#endif //NvCV_API + + +#ifdef __cplusplus +extern "C" { +#endif // ___cplusplus + + +//! Status codes returned from APIs. +typedef enum NvCV_Status { + NVCV_SUCCESS = 0, //!< The procedure returned successfully. + NVCV_ERR_GENERAL = -1, //!< An otherwise unspecified error has occurred. + NVCV_ERR_UNIMPLEMENTED = -2, //!< The requested feature is not yet implemented. + NVCV_ERR_MEMORY = -3, //!< There is not enough memory for the requested operation. + NVCV_ERR_EFFECT = -4, //!< An invalid effect handle has been supplied. + NVCV_ERR_SELECTOR = -5, //!< The given parameter selector is not valid in this effect filter. + NVCV_ERR_BUFFER = -6, //!< An image buffer has not been specified. + NVCV_ERR_PARAMETER = -7, //!< An invalid parameter value has been supplied for this effect+selector. + NVCV_ERR_MISMATCH = -8, //!< Some parameters are not appropriately matched. + NVCV_ERR_PIXELFORMAT = -9, //!< The specified pixel format is not accommodated. + NVCV_ERR_MODEL = -10, //!< Error while loading the TRT model. + NVCV_ERR_LIBRARY = -11, //!< Error loading the dynamic library. + NVCV_ERR_INITIALIZATION = -12, //!< The effect has not been properly initialized. + NVCV_ERR_FILE = -13, //!< The file could not be found. + NVCV_ERR_FEATURENOTFOUND = -14, //!< The requested feature was not found + NVCV_ERR_MISSINGINPUT = -15, //!< A required parameter was not set + NVCV_ERR_RESOLUTION = -16, //!< The specified image resolution is not supported. + + NVCV_ERR_CUDA_MEMORY = -20, //!< There is not enough CUDA memory for the requested operation. + NVCV_ERR_CUDA_VALUE = -21, //!< A CUDA parameter is not within the acceptable range. + NVCV_ERR_CUDA_PITCH = -22, //!< A CUDA pitch is not within the acceptable range. + NVCV_ERR_CUDA_INIT = -23, //!< The CUDA driver and runtime could not be initialized. + NVCV_ERR_CUDA_LAUNCH = -24, //!< The CUDA kernel launch has failed. + NVCV_ERR_CUDA_KERNEL = -25, //!< No suitable kernel image is available for the device. + NVCV_ERR_CUDA_DRIVER = -26, //!< The installed NVIDIA CUDA driver is older than the CUDA runtime library. + NVCV_ERR_CUDA_UNSUPPORTED = -27, //!< The CUDA operation is not supported on the current system or device. + NVCV_ERR_CUDA_ILLEGAL_ADDRESS = -28, //!< CUDA tried to load or store on an invalid memory address. + NVCV_ERR_CUDA = -30, //!< An otherwise unspecified CUDA error has been reported. +} NvCV_Status; + + +//! Get an error string corresponding to the given status code. +//! \param[in] code the NvCV status code. +//! \return the corresponding string. +//! \todo Find a cleaner way to do this, because NvCV_API doesn't work. +#ifdef _WIN32 + __declspec(dllexport) const char* __cdecl +#else + const char* +#endif // _WIN32 or linux +NvCV_GetErrorStringFromCode(NvCV_Status code); + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __NVCVSTATUS_H__ diff --git a/nvar/src/nvARProxy.cpp b/nvar/src/nvARProxy.cpp new file mode 100644 index 0000000..8368ca9 --- /dev/null +++ b/nvar/src/nvARProxy.cpp @@ -0,0 +1,357 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ +#include + +#include "nvAR.h" + +#ifdef _WIN32 +#define _WINSOCKAPI_ +#include +#include +#else +#include +typedef void* HMODULE; +typedef void* HANDLE; +typedef void* HINSTANCE; +#endif + +// Parameter string does not include the file extension +#ifdef _WIN32 +#define nvLoadLibrary(library) LoadLibrary(TEXT(library ".dll")) +#else +#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY) +#endif + + +inline void* nvGetProcAddress(HINSTANCE handle, const char* proc) { + if (nullptr == handle) return nullptr; +#ifdef _WIN32 + return GetProcAddress(handle, proc); +#else + return dlsym(handle, proc); +#endif +} + +inline int nvFreeLibrary(HINSTANCE handle) { +#ifdef _WIN32 + return FreeLibrary(handle); +#else + return dlclose(handle); +#endif +} + +HINSTANCE getNvARLib() { + + TCHAR path[MAX_PATH], fullPath[2*MAX_PATH]; + + // There can be multiple apps on the system, + // some might include the SDK in the app package and + // others might expect the SDK to be installed in Program Files + GetEnvironmentVariable(TEXT("NV_AR_SDK_PATH"), path, MAX_PATH); + if (_tcscmp(path, TEXT("USE_APP_PATH"))) { + // App has not set environment variable to "USE_APP_PATH" + // So pick up the SDK dll and dependencies from Program Files + GetEnvironmentVariable(TEXT("ProgramFiles"), path, MAX_PATH); + size_t max_len = sizeof(fullPath)/sizeof(TCHAR); + _stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA AR SDK\\"), path); + SetDllDirectory(fullPath); + } + static const HINSTANCE NvArLib = nvLoadLibrary("nvARPose"); + return NvArLib; +} + +NvCV_Status NvAR_API NvCVImage_Init(NvCVImage* im, unsigned width, unsigned height, int pitch, void* pixels, + NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned isPlanar, + unsigned onGPU) { + static const auto funcPtr = (decltype(NvCVImage_Init)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Init"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(im, width, height, pitch, pixels, format, type, isPlanar, onGPU); +} + +void NvAR_API NvCVImage_InitView(NvCVImage* subImg, NvCVImage* fullImg, int x, int y, unsigned width, + unsigned height) { + static const auto funcPtr = (decltype(NvCVImage_InitView)*)nvGetProcAddress(getNvARLib(), "NvCVImage_InitView"); + + if (nullptr != funcPtr) funcPtr(subImg, fullImg, x, y, width, height); +} + +NvCV_Status NvAR_API NvCVImage_Alloc(NvCVImage* im, unsigned width, unsigned height, NvCVImage_PixelFormat format, + NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment) { + static const auto funcPtr = (decltype(NvCVImage_Alloc)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Alloc"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment); +} + +NvCV_Status NvAR_API NvCVImage_Realloc(NvCVImage* im, unsigned width, unsigned height, + NvCVImage_PixelFormat format, NvCVImage_ComponentType type, + unsigned isPlanar, unsigned onGPU, unsigned alignment) { + static const auto funcPtr = (decltype(NvCVImage_Realloc)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Realloc"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment); +} + +void NvAR_API NvCVImage_Dealloc(NvCVImage* im) { + static const auto funcPtr = (decltype(NvCVImage_Dealloc)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Dealloc"); + + if (nullptr != funcPtr) funcPtr(im); +} + +NvCV_Status NvAR_API NvCVImage_Create(unsigned width, unsigned height, NvCVImage_PixelFormat format, + NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, + unsigned alignment, NvCVImage** out) { + static const auto funcPtr = (decltype(NvCVImage_Create)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Create"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(width, height, format, type, isPlanar, onGPU, alignment, out); +} + +void NvAR_API NvCVImage_Destroy(NvCVImage* im) { + static const auto funcPtr = (decltype(NvCVImage_Destroy)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Destroy"); + + if (nullptr != funcPtr) funcPtr(im); +} + +void NvAR_API NvCVImage_ComponentOffsets(NvCVImage_PixelFormat format, int* rOff, int* gOff, int* bOff, int* aOff, + int* yOff) { + static const auto funcPtr = + (decltype(NvCVImage_ComponentOffsets)*)nvGetProcAddress(getNvARLib(), "NvCVImage_ComponentOffsets"); + + if (nullptr != funcPtr) funcPtr(format, rOff, gOff, bOff, aOff, yOff); +} + +NvCV_Status NvAR_API NvCVImage_Transfer(const NvCVImage* src, NvCVImage* dst, float scale, CUstream_st* stream, + NvCVImage* tmp) { + static const auto funcPtr = (decltype(NvCVImage_Transfer)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Transfer"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(src, dst, scale, stream, tmp); +} + +NvCV_Status NvAR_API NvCVImage_Composite(const NvCVImage* src, const NvCVImage* mat, NvCVImage* dst) { + static const auto funcPtr = (decltype(NvCVImage_Composite)*)nvGetProcAddress(getNvARLib(), "NvCVImage_Composite"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(src, mat, dst); +} + +NvCV_Status NvAR_API NvCVImage_CompositeOverConstant(const NvCVImage* src, const NvCVImage* mat, + const unsigned char bgColor[3], NvCVImage* dst) { + static const auto funcPtr = + (decltype(NvCVImage_CompositeOverConstant)*)nvGetProcAddress(getNvARLib(), "NvCVImage_CompositeOverConstant"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(src, mat, bgColor, dst); +} + +NvCV_Status NvAR_API NvCVImage_FlipY(const NvCVImage* src, NvCVImage* dst) { + static const auto funcPtr = (decltype(NvCVImage_FlipY)*)nvGetProcAddress(getNvARLib(), "NvCVImage_FlipY"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(src, dst); +} + +NvCV_Status NvAR_API NvAR_Create(NvAR_FeatureID featureID, NvAR_FeatureHandle* handle) { + static const auto funcPtr = (decltype(NvAR_Create)*)nvGetProcAddress(getNvARLib(), "NvAR_Create"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(featureID, handle); +} + +NvCV_Status NvAR_API NvAR_Destroy(NvAR_FeatureHandle handle) { + static const auto funcPtr = (decltype(NvAR_Destroy)*)nvGetProcAddress(getNvARLib(), "NvAR_Destroy"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle); +} + +NvCV_Status NvAR_API NvAR_SetU32(NvAR_FeatureHandle handle, const char* name, unsigned int val) { + static const auto funcPtr = (decltype(NvAR_SetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_SetS32(NvAR_FeatureHandle handle, const char* name, int val) { + static const auto funcPtr = (decltype(NvAR_SetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetS32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_SetF32(NvAR_FeatureHandle handle, const char* name, float val) { + static const auto funcPtr = (decltype(NvAR_SetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_SetF64(NvAR_FeatureHandle handle, const char* name, double val) { + static const auto funcPtr = (decltype(NvAR_SetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF64"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_SetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long val) { + static const auto funcPtr = (decltype(NvAR_SetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU64"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_SetObject(NvAR_FeatureHandle handle, const char* name, void* ptr, unsigned long typeSize) { + static const auto funcPtr = (decltype(NvAR_SetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_SetObject"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, ptr, typeSize); +} + +NvCV_Status NvAR_API NvAR_SetString(NvAR_FeatureHandle handle, const char* name, const char* str) { + static const auto funcPtr = (decltype(NvAR_SetString)*)nvGetProcAddress(getNvARLib(), "NvAR_SetString"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, str); +} + +NvCV_Status NvAR_API NvAR_SetCudaStream(NvAR_FeatureHandle handle, const char* name, CUstream stream) { + static const auto funcPtr = (decltype(NvAR_SetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_SetCudaStream"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, stream); +} + +NvCV_Status NvAR_API NvAR_SetF32Array(NvAR_FeatureHandle handle, const char* name, float* val, int count) { + static const auto funcPtr = (decltype(NvAR_SetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32Array"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val, count); +} + +NvCV_Status NvAR_API NvAR_GetU32(NvAR_FeatureHandle handle, const char* name, unsigned int* val) { + static const auto funcPtr = (decltype(NvAR_GetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_GetS32(NvAR_FeatureHandle handle, const char* name, int* val) { + static const auto funcPtr = (decltype(NvAR_GetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetS32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_GetF32(NvAR_FeatureHandle handle, const char* name, float* val) { + static const auto funcPtr = (decltype(NvAR_GetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF32"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_GetF64(NvAR_FeatureHandle handle, const char* name, double* val) { + static const auto funcPtr = (decltype(NvAR_GetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF64"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_GetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long* val) { + static const auto funcPtr = (decltype(NvAR_GetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU64"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, val); +} + +NvCV_Status NvAR_API NvAR_GetObject(NvAR_FeatureHandle handle, const char* name, const void** ptr, unsigned long typeSize) { + static const auto funcPtr = (decltype(NvAR_GetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_GetObject"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, ptr, typeSize); +} + +NvCV_Status NvAR_API NvAR_GetString(NvAR_FeatureHandle handle, const char* name, const char** str) { + static const auto funcPtr = (decltype(NvAR_GetString)*)nvGetProcAddress(getNvARLib(), "NvAR_GetString"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, str); +} + +NvCV_Status NvAR_API NvAR_GetCudaStream(NvAR_FeatureHandle handle, const char* name, const CUstream* stream) { + static const auto funcPtr = (decltype(NvAR_GetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_GetCudaStream"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, stream); +} + +NvCV_Status NvAR_API NvAR_GetF32Array(NvAR_FeatureHandle handle, const char* name, const float** vals, int* count) { + static const auto funcPtr = (decltype(NvAR_GetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_GetCNvAR_GetF32ArrayudaStream"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle, name, vals, count); +} + +NvCV_Status NvAR_API NvAR_Run(NvAR_FeatureHandle handle) { + static const auto funcPtr = (decltype(NvAR_Run)*)nvGetProcAddress(getNvARLib(), "NvAR_Run"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle); +} + +NvCV_Status NvAR_API NvAR_Load(NvAR_FeatureHandle handle) { + static const auto funcPtr = (decltype(NvAR_Load)*)nvGetProcAddress(getNvARLib(), "NvAR_Load"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(handle); +} + +NvCV_Status NvAR_API NvAR_CudaStreamCreate(CUstream* stream) { + static const auto funcPtr = + (decltype(NvAR_CudaStreamCreate)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamCreate"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(stream); +} + +NvCV_Status NvAR_API NvAR_CudaStreamDestroy(CUstream stream) { + static const auto funcPtr = + (decltype(NvAR_CudaStreamDestroy)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamDestroy"); + + if (nullptr == funcPtr) return NVCV_ERR_LIBRARY; + return funcPtr(stream); +} + +#ifdef _WIN32 +__declspec(dllexport) const char* __cdecl +#else +const char* +#endif // _WIN32 or linux + NvCV_GetErrorStringFromCode(NvCV_Status code) { + static const auto funcPtr = + (decltype(NvCV_GetErrorStringFromCode)*)nvGetProcAddress(getNvARLib(), "NvCV_GetErrorStringFromCode"); + + if (nullptr == funcPtr) return "Cannot find nvARPose DLL or its dependencies"; + return funcPtr(code); +} diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt new file mode 100644 index 0000000..019f900 --- /dev/null +++ b/samples/CMakeLists.txt @@ -0,0 +1,7 @@ +# Sample apps + +add_library(utils_sample INTERFACE) +target_include_directories(utils_sample INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/utils) +target_link_libraries(utils_sample INTERFACE GLM) +add_subdirectory(external) +add_subdirectory(FaceTrack) diff --git a/samples/FaceTrack/CMakeLists.txt b/samples/FaceTrack/CMakeLists.txt new file mode 100644 index 0000000..49f8858 --- /dev/null +++ b/samples/FaceTrack/CMakeLists.txt @@ -0,0 +1,25 @@ +set(SOURCE_FILES FaceEngine.cpp FaceTrack.cpp ../utils/RenderingUtils.cpp ../../nvar/src/nvARProxy.cpp) +set(HEADER_FILES FaceEngine.h) + +# Set Visual Studio source filters +source_group("Source Files" FILES ${SOURCE_FILES}) +source_group("Header Files" FILES ${HEADER_FILES}) + +add_executable(FaceTrack ${SOURCE_FILES} ${HEADER_FILES}) +target_include_directories(FaceTrack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(FaceTrack PUBLIC + ${SDK_INCLUDES_PATH} +) +target_link_libraries(FaceTrack PUBLIC + opencv346 + utils_sample + GLM +) + +set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin) +set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR}) +set_target_properties(FaceTrack PROPERTIES + FOLDER SampleApps + VS_DEBUGGER_ENVIRONMENT "${PATH_STR}" +) + diff --git a/samples/FaceTrack/FaceEngine.cpp b/samples/FaceTrack/FaceEngine.cpp new file mode 100644 index 0000000..ddab3d9 --- /dev/null +++ b/samples/FaceTrack/FaceEngine.cpp @@ -0,0 +1,621 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ +#include "FaceEngine.h" +#include "RenderingUtils.h" + +const char* NvCV_StatusStringFromCode(NvCV_Status code) { + struct TabEntry { + NvCV_Status code; + const char* str; + }; + static const TabEntry lut[] = { + {NVCV_SUCCESS, "no error"}, + {NVCV_ERR_GENERAL, "unspecified failure"}, + {NVCV_ERR_FEATURENOTFOUND, "Feature not found"}, + {NVCV_ERR_PARAMETER, "invalid parameter"}, + {NVCV_ERR_MEMORY, "provided buffer too small"}, + {NVCV_ERR_INITIALIZATION, "not initialized"}, + {NVCV_ERR_MISSINGINPUT, "missing input"}, + {NVCV_ERR_INITIALIZATION, "unable to initialize feature"}, + {NVCV_ERR_CUDA_MEMORY, "out of GPU memory"}, + {NVCV_ERR_SELECTOR, "unsupported parameter"}, + }; + for (const TabEntry* p = lut; p != &lut[sizeof(lut) / sizeof(lut[0])]; ++p) + if (p->code == code) return p->str; + return "UNKNOWN ERROR"; +} + +bool CheckResult(NvCV_Status nvErr, unsigned line) { + if (NVCV_SUCCESS == nvErr) return true; + std::cout << "ERROR: " << NvCV_StatusStringFromCode(nvErr) << ", line " << line << std::endl; + return false; +} + +FaceEngine::Err FaceEngine::fitFaceModel(cv::Mat& frame) { + FaceEngine::Err err = FaceEngine::Err::errNone; + NvCV_Status nvErr; + if (!frame.empty()) { + NvCVImage fxSrcChunkyCPU; + (void)NVWrapperForCVMat(&frame, &fxSrcChunkyCPU); + NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, NULL); + + if (NVCV_SUCCESS != cvErr) { + return errRun; + } + } + + nvErr = NvAR_Run(faceFitHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errRun); + + if (getAverageLandmarksConfidence() < LANDMARK_CONF_THRESH) return FaceEngine::Err::errRun; + +bail: + return err; +} + +NvAR_FaceMesh* FaceEngine::getFaceMesh() { return face_mesh; } + +NvAR_RenderingParams* FaceEngine::getRenderingParams() { return rendering_params; } + +FaceEngine::Err FaceEngine::createFeatures(const char* modelPath, unsigned int _batchSize) { + FaceEngine::Err err = FaceEngine::Err::errNone; + + NvCV_Status cuErr = NvAR_CudaStreamCreate(&stream); + if (appMode == faceDetection) + err = createFaceDetectionFeature(modelPath, stream); + else if (appMode == landmarkDetection) + err = createLandmarkDetectionFeature(modelPath, _batchSize, stream); + else if (appMode == faceMeshGeneration) + err = createFaceFittingFeature(modelPath, stream); + return err; +} + +FaceEngine::Err FaceEngine::createFaceDetectionFeature(const char* modelPath, CUstream stream) { + FaceEngine::Err err = FaceEngine::Err::errNone; + NvCV_Status nvErr; + + nvErr = NvAR_Create(NvAR_Feature_FaceDetection, &faceDetectHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetString(faceDetectHandle, NvAR_Parameter_Config(ModelDir), modelPath); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetCudaStream(faceDetectHandle, NvAR_Parameter_Config(CUDAStream), stream); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetU32(faceDetectHandle, NvAR_Parameter_Config(Temporal), bStabilizeFace); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_Load(faceDetectHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +FaceEngine::Err FaceEngine::createLandmarkDetectionFeature(const char* modelPath, unsigned int _batchSize, + CUstream stream) { + FaceEngine::Err err = FaceEngine::Err::errNone; + NvCV_Status nvErr; + + batchSize = _batchSize; + nvErr = NvAR_Create(NvAR_Feature_LandmarkDetection, &landmarkDetectHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetString(landmarkDetectHandle, NvAR_Parameter_Config(ModelDir), modelPath); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetCudaStream(landmarkDetectHandle, NvAR_Parameter_Config(CUDAStream), stream); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(BatchSize), batchSize); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(Temporal), bStabilizeFace); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_Load(landmarkDetectHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +FaceEngine::Err FaceEngine::createFaceFittingFeature(const char* modelPath, CUstream stream) { + FaceEngine::Err err = FaceEngine::Err::errNone; + NvCV_Status nvErr; + + nvErr = NvAR_Create(NvAR_Feature_Face3DReconstruction, &faceFitHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetString(faceFitHandle, NvAR_Parameter_Config(ModelDir), modelPath); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetCudaStream(faceFitHandle, NvAR_Parameter_Config(CUDAStream), stream); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_Load(faceFitHandle); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +FaceEngine::Err FaceEngine::initFeatureIOParams() { + FaceEngine::Err err = FaceEngine::Err::errNone; + + NvCV_Status cvErr = NvCVImage_Alloc(&inputImageBuffer, input_image_width, input_image_height, NVCV_BGR, NVCV_U8, + NVCV_CHUNKY, NVCV_GPU, 1); + + BAIL_IF_CVERR(cvErr, err, FaceEngine::Err::errInitialization); + + if (appMode == faceDetection) + err = initFaceDetectionIOParams(&inputImageBuffer); + else if (appMode == landmarkDetection) + err = initLandmarkDetectionIOParams(&inputImageBuffer); + else if (appMode == faceMeshGeneration) + err = initFaceFittingIOParams(&inputImageBuffer); + + return err; + +bail: + return err; +} + +FaceEngine::Err FaceEngine::initFaceDetectionIOParams(NvCVImage* _inputImageBuffer) { + NvCV_Status nvErr = NVCV_SUCCESS; + FaceEngine::Err err = FaceEngine::Err::errNone; + + nvErr = NvAR_SetObject(faceDetectHandle, NvAR_Parameter_Input(Image), &inputImageBuffer, sizeof(NvCVImage)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + output_bbox_data.assign(25, {0.f, 0.f, 0.f, 0.f}); + output_bbox_conf_data.assign(25, 0.f); + output_bboxes.boxes = output_bbox_data.data(); + output_bboxes.max_boxes = output_bbox_data.size(); + output_bboxes.num_boxes = 0; + nvErr = NvAR_SetObject(faceDetectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetF32Array(faceDetectHandle, NvAR_Parameter_Output(BoundingBoxesConfidence), + output_bbox_conf_data.data(), output_bboxes.max_boxes); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +FaceEngine::Err FaceEngine::initLandmarkDetectionIOParams(NvCVImage* _inputImageBuffer) { + NvCV_Status nvErr = NVCV_SUCCESS; + FaceEngine::Err err = FaceEngine::Err::errNone; + + nvErr = NvAR_SetObject(landmarkDetectHandle, NvAR_Parameter_Input(Image), &inputImageBuffer, sizeof(NvCVImage)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + unsigned int OUTPUT_SIZE_KPTS, OUTPUT_SIZE_KPTS_CONF; + nvErr = NvAR_GetU32(landmarkDetectHandle, NvAR_Parameter_Config(Landmarks_Size), &OUTPUT_SIZE_KPTS); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_GetU32(landmarkDetectHandle, NvAR_Parameter_Config(LandmarksConfidence_Size), &OUTPUT_SIZE_KPTS_CONF); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + facial_landmarks.assign(batchSize * OUTPUT_SIZE_KPTS, {0.f, 0.f}); + facial_pose.assign(batchSize, {0.f, 0.f, 0.f, 0.f}); + facial_landmarks_confidence.assign(batchSize * OUTPUT_SIZE_KPTS_CONF, 0.f); + + nvErr = NvAR_SetObject(landmarkDetectHandle, NvAR_Parameter_Output(Landmarks), facial_landmarks.data(), + sizeof(NvAR_Point2f)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = + NvAR_SetObject(landmarkDetectHandle, NvAR_Parameter_Output(Pose), facial_pose.data(), sizeof(NvAR_Quaternion)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetF32Array(landmarkDetectHandle, NvAR_Parameter_Output(LandmarksConfidence), + facial_landmarks_confidence.data(), batchSize * OUTPUT_SIZE_KPTS); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + uint output_bbox_size = batchSize; + if (!bStabilizeFace) output_bbox_size = 25; + output_bbox_data.assign(output_bbox_size, {0.f, 0.f, 0.f, 0.f}); + output_bboxes.boxes = output_bbox_data.data(); + output_bboxes.max_boxes = output_bbox_size; + output_bboxes.num_boxes = output_bbox_size; + nvErr = + NvAR_SetObject(landmarkDetectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +FaceEngine::Err FaceEngine::initFaceFittingIOParams(NvCVImage* inputImageBuffer) { + NvCV_Status nvErr = NVCV_SUCCESS; + FaceEngine::Err err = FaceEngine::Err::errNone; + + face_mesh = new NvAR_FaceMesh(); + face_mesh->vertices = new NvAR_Vector3f[FACE_MODEL_NUM_VERTICES]; + face_mesh->tvi = new NvAR_Vector3u16[FACE_MODEL_NUM_INDICES]; + rendering_params = new NvAR_RenderingParams(); + + nvErr = NvAR_SetObject(faceFitHandle, NvAR_Parameter_Input(Image), inputImageBuffer, sizeof(NvCVImage)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetS32(faceFitHandle, NvAR_Parameter_Input(Width), input_image_width); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetS32(faceFitHandle, NvAR_Parameter_Input(Height), input_image_height); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + unsigned int OUTPUT_SIZE_KPTS; + nvErr = NvAR_GetU32(faceFitHandle, NvAR_Parameter_Config(Landmarks_Size), &OUTPUT_SIZE_KPTS); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + facial_landmarks.assign(batchSize * OUTPUT_SIZE_KPTS, {0.f, 0.f}); + nvErr = + NvAR_SetObject(faceFitHandle, NvAR_Parameter_Output(Landmarks), facial_landmarks.data(), sizeof(NvAR_Point2f)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + facial_landmarks_confidence.assign(batchSize * OUTPUT_SIZE_KPTS, 0.f); + nvErr = NvAR_SetF32Array(faceFitHandle, NvAR_Parameter_Output(LandmarksConfidence), + facial_landmarks_confidence.data(), batchSize * OUTPUT_SIZE_KPTS); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + output_bbox_data.assign(batchSize, {0.f, 0.f, 0.f, 0.f}); + output_bboxes.boxes = output_bbox_data.data(); + output_bboxes.max_boxes = batchSize; + output_bboxes.num_boxes = batchSize; + nvErr = NvAR_SetObject(faceFitHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes)); + + nvErr = NvAR_SetObject(faceFitHandle, NvAR_Parameter_Output(FaceMesh), face_mesh, sizeof(NvAR_FaceMesh)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + + nvErr = NvAR_SetObject(faceFitHandle, NvAR_Parameter_Output(RenderingParams), rendering_params, + sizeof(NvAR_RenderingParams)); + BAIL_IF_CVERR(nvErr, err, FaceEngine::Err::errInitialization); + +bail: + return err; +} + +void FaceEngine::destroyFeatures() { + if (stream) { + NvAR_CudaStreamDestroy(stream); + stream = 0; + } + releaseFeatureIOParams(); + destroyFaceDetectionFeature(); + destroyLandmarkDetectionFeature(); + destroyFaceFittingFeature(); +} + +void FaceEngine::destroyFaceDetectionFeature() { + if (faceDetectHandle) { + (void)NvAR_Destroy(faceDetectHandle); + faceDetectHandle = nullptr; + } +} +void FaceEngine::destroyLandmarkDetectionFeature() { + if (landmarkDetectHandle) { + (void)NvAR_Destroy(landmarkDetectHandle); + landmarkDetectHandle = nullptr; + } +} +void FaceEngine::destroyFaceFittingFeature() { + if (faceFitHandle) { + (void)NvAR_Destroy(faceFitHandle); + faceFitHandle = nullptr; + } +} + +void FaceEngine::releaseFeatureIOParams() { + releaseFaceDetectionIOParams(); + releaseLandmarkDetectionIOParams(); + releaseFaceFittingIOParams(); +} + +void FaceEngine::releaseFaceDetectionIOParams() { + NvCVImage_Dealloc(&inputImageBuffer); + if (!output_bbox_data.empty()) output_bbox_data.clear(); + if (!output_bbox_conf_data.empty()) output_bbox_conf_data.clear(); +} + +void FaceEngine::releaseLandmarkDetectionIOParams() { + NvCVImage_Dealloc(&inputImageBuffer); + if (!output_bbox_data.empty()) output_bbox_data.clear(); + if (!facial_landmarks.empty()) facial_landmarks.clear(); + if (!facial_pose.empty()) facial_pose.clear(); + if (!facial_landmarks_confidence.empty()) facial_landmarks_confidence.clear(); +} + +void FaceEngine::releaseFaceFittingIOParams() { + if (!output_bbox_data.empty()) output_bbox_data.clear(); + if (!facial_landmarks.empty()) facial_landmarks.clear(); + if (!facial_landmarks_confidence.empty()) facial_landmarks_confidence.clear(); + NvCVImage_Dealloc(&inputImageBuffer); + if (rendering_params) { + delete rendering_params; + rendering_params = nullptr; + } + if (face_mesh) { + if (face_mesh->vertices) { + delete[] face_mesh->vertices; + face_mesh->vertices = nullptr; + } + if (face_mesh->tvi) { + delete[] face_mesh->tvi; + face_mesh->tvi = nullptr; + } + delete face_mesh; + face_mesh = nullptr; + } +} + +unsigned FaceEngine::findFaceBoxes() { + NvCV_Status nvErr = NvAR_Run(faceDetectHandle); + if (NVCV_SUCCESS != nvErr) return 0; + return (unsigned)output_bboxes.num_boxes; +} + +NvAR_Rect* FaceEngine::getLargestBox() { + NvAR_Rect *box, *bigBox, *lastBox; + float maxArea, area; + for (lastBox = (box = &output_bboxes.boxes[0]) + output_bboxes.num_boxes, bigBox = nullptr, maxArea = 0; + box != lastBox; ++box) { + if (maxArea < (area = box->width * box->height)) { + maxArea = area; + bigBox = box; + } + } + return bigBox; +} + +NvAR_BBoxes* FaceEngine::getBoundingBoxes() { return &output_bboxes; } + +void FaceEngine::enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int FLAG_variant) { + NvAR_Vector2f size = {box.width * .5f, box.height * .5f}; + NvAR_Point2f center = {box.x + size.x, box.y + size.y}; + float t; + + size.x *= (1.f + enlarge); + size.y *= (1.f + enlarge); + + if (!(FLAG_variant & 1)) /* Default: enforce square bounding box */ + { + if (size.x < size.y) /* Make square */ + size.x = size.y; + else + size.y = size.x; + } + + if (center.x < size.x) /* Shift box into image left-right */ + center.x = size.x; + else if (center.x > (t = input_image_width - size.x)) + center.x = t; + + if (center.y < size.y) /* Shift box into image up-down */ + center.y = size.y; + else if (center.y > (t = input_image_height - size.y)) + center.y = t; + + // TODO: Above we assume that the box is smaller than the image. + + box.width = roundf(size.x * 2.f); /* Integral box */ + box.height = roundf(size.y * 2.f); + box.x = roundf(center.x - box.width * .5f); + box.y = roundf(center.y - box.height * .5f); +} + +/** + * Perturb a bounding box. + * @param[in,out] ran the random number generator. + * @param[in] minMag inset magnitude of noise. + * @param[in] maxMag outset magnitude of noise. + * @param[in] cleanBox the clean input box. + * @param[out] noisyBox the perturbed output box. + */ +// TOD0: Fix the 8 bounding boxes instead if random jiggling +void FaceEngine::jiggleBox(std::mt19937& ran, float minMag, float maxMag, const NvAR_Rect& cleanBox, + NvAR_Rect& jitteredBox) { + if (0.f == minMag && 0.f == maxMag) { + jitteredBox = cleanBox; + return; + } + + std::uniform_real_distribution uRand(minMag, maxMag); +#if 1 // jitter both sides + jitteredBox.x = cleanBox.x - uRand(ran); + jitteredBox.y = cleanBox.y - uRand(ran); + jitteredBox.width = cleanBox.width + cleanBox.x + uRand(ran) - jitteredBox.x; + jitteredBox.height = cleanBox.height + cleanBox.y + uRand(ran) - jitteredBox.y; +#elif 0 // jitter only the right side + noisyBox.x = cleanBox.x; + noisyBox.y = cleanBox.y; + noisyBox.width = cleanBox.width + cleanBox.x + uRand(ran) - noisyBox.x; + noisyBox.height = cleanBox.height + cleanBox.y + uRand(ran) - noisyBox.y; +#elif 1 // jitter only the location + noisyBox.x = cleanBox.x - uRand(ran); + noisyBox.y = cleanBox.y - uRand(ran); + noisyBox.width = cleanBox.width; + noisyBox.height = cleanBox.height; +#endif // None of these makes a significant difference +} + +/** Intersect a rectangle with an image. + * @param[in] srcRect the source rectangle. + * @param[in] src the source image. + * @param[out] clipRect the source rectangle clipped to the source image. + * @return true if the rectangle was clipped, + * false if the rectangle did not need to be clipped. + */ +static bool IntersectRectWithImage(const cv::Rect& srcRect, const cv::Mat& src, cv::Rect& clipRect) { + bool result = 0; // unclipped + cv::Point2i rect[2] = {{srcRect.x, srcRect.y}, {srcRect.x + srcRect.width, srcRect.y + srcRect.height}}; + if (rect[0].x < 0) { + result = 1; + rect[0].x = 0; + } // clipped + if (rect[0].y < 0) { + result = 1; + rect[0].y = 0; + } // clipped + if (rect[1].x > src.cols) { + result = 1; + rect[1].x = src.cols; + } // clipped + if (rect[1].y > src.rows) { + result = 1; + rect[1].y = src.rows; + } // clipped + clipRect.x = rect[0].x; + clipRect.y = rect[0].y; + clipRect.width = rect[1].x - rect[0].x; + clipRect.height = rect[1].y - rect[0].y; + return result; +} + +void FaceEngine::DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) { + float R[3][3]; + set_rotation_from_quaternion(pose, R[0]); + float radius = 100.f; + float x1 = radius * R[1][0]; + float y1 = radius * R[2][0]; + float x2 = radius * R[1][1]; + float y2 = radius * R[2][1]; + float x3 = radius * R[1][2] * -1.f; + float y3 = radius * R[2][2] * -1.f; + + // 30th point is the tip of the nose + const int nose_tip = 30; + int width = src.cols; + int height = src.rows; + NvAR_Point2f cxy = *(facial_landmarks.data() + nose_tip); + float cx1 = std::min(std::max(0, int(cxy.x + x1)), width - 1); + float cy1 = std::min(std::max(0, int(cxy.y + y1)), height - 1); + float cx2 = std::min(std::max(0, int(cxy.x + x2)), width - 1); + float cy2 = std::min(std::max(0, int(cxy.y + y2)), height - 1); + float cx3 = std::min(std::max(0, int(cxy.x + x3)), width - 1); + float cy3 = std::min(std::max(0, int(cxy.y + y3)), height - 1); + + cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx1, (int)cy1), cv::Scalar(0, 0, 255), 2); + cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx2, (int)cy2), cv::Scalar(0, 255, 0), 2); + cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx3, (int)cy3), cv::Scalar(255, 0, 0), 2); +} + +NvCV_Status FaceEngine::findLandmarks() { + NvCV_Status nvErr; + + nvErr = NvAR_Run(landmarkDetectHandle); + if (NVCV_SUCCESS != nvErr) { + return nvErr; + } + + if (getAverageLandmarksConfidence() < LANDMARK_CONF_THRESH) { + return NVCV_ERR_GENERAL; + } else { + average_poses(getPose(), batchSize); + NvAR_Point2f *pt, *endPt; + int i = 0; + for (endPt = (pt = getLandmarks()) + NUM_LANDMARKS; pt != endPt; ++pt, i += 2) { + for (int j = 1; j < batchSize; j++) { + pt->x += pt[j * NUM_LANDMARKS].x; + pt->y += pt[j * NUM_LANDMARKS].y; + } + // average batch of inferences to generate final result landmark points + pt->x /= batchSize; + pt->y /= batchSize; + } + } + return NVCV_SUCCESS; +} + +NvAR_Point2f* FaceEngine::getLandmarks() { return facial_landmarks.data(); } + +float* FaceEngine::getLandmarksConfidence() { return facial_landmarks_confidence.data(); } + +float FaceEngine::getAverageLandmarksConfidence() { + float average_confidence = 0.0f; + float* keypoints_landmarks_confidence = getLandmarksConfidence(); + for (int i = 0; i < batchSize; i++) { + for (int j = 0; j < NUM_LANDMARKS; j++) { + average_confidence += keypoints_landmarks_confidence[i * NUM_LANDMARKS + j]; + } + } + average_confidence /= batchSize * NUM_LANDMARKS; + return average_confidence; +} + +NvAR_Quaternion* FaceEngine::getPose() { return facial_pose.data(); } + +unsigned FaceEngine::findLargestFaceBox(NvAR_Rect& faceBox, int variant) { + unsigned n; + NvAR_Rect* pFaceBox; + + n = findFaceBoxes(); + if (n >= 1) { + pFaceBox = getLargestBox(); + if (nullptr == pFaceBox) { + faceBox.x = faceBox.y = faceBox.width = faceBox.height = 0.0f; + } else { + faceBox = *pFaceBox; + } + enlargeAndSquarifyImageBox(.2f, faceBox, variant); + } + return n; +} + +unsigned FaceEngine::acquireFaceBox(cv::Mat& src, NvAR_Rect& faceBox, int variant) { + unsigned n = 0; + NvCVImage fxSrcChunkyCPU; + (void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU); + NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage); + + if (NVCV_SUCCESS != cvErr) { + return n; + } + + n = findLargestFaceBox(faceBox, variant); + return n; +} + +unsigned FaceEngine::acquireFaceBoxAndLandmarks(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Rect& faceBox, int variant) { + unsigned n = 0; + NvCVImage fxSrcChunkyCPU; + (void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU); + NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage); + + if (NVCV_SUCCESS != cvErr) { + return n; + } + + if (findLandmarks() != NVCV_SUCCESS) return 0; + faceBox = output_bboxes.boxes[0]; + n = 1; + memcpy(refMarks, getLandmarks(), sizeof(NvAR_Point2f) * FaceEngine::NUM_LANDMARKS); + + return n; +} + +void FaceEngine::setFaceStabilization(bool _bStabilizeFace) { bStabilizeFace = _bStabilizeFace; } + +void FaceEngine::setAppMode(FaceEngine::mode _mode) { appMode = _mode; } diff --git a/samples/FaceTrack/FaceEngine.h b/samples/FaceTrack/FaceEngine.h new file mode 100644 index 0000000..743e016 --- /dev/null +++ b/samples/FaceTrack/FaceEngine.h @@ -0,0 +1,175 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ +#ifndef __FACE_ENGINE__ +#define __FACE_ENGINE__ + +#include +#include "nvAR.h" +#include "nvCVOpenCV.h" +#include "opencv2/opencv.hpp" +#define FITFACE_PRIVATE + +class KalmanFilter1D { + private: + float Q_; // Covariance of the process noise + float xhat_; // Current prediction + float xhatminus_; // Previous prediction + float P_; // Estimated accuracy of xhat_ + float Pminus_; // Previous P_ + float K_; // Kalman gain + float R_; // Covariance of the observation noise + bool bFirstUse; + + public: + KalmanFilter1D() { reset(); } + + KalmanFilter1D(float Q, float R) { reset(Q, R); } + + void reset() { + R_ = 0.005f * 0.005f; + Q_ = 1e-5f; + xhat_ = 0.0f; + xhatminus_ = 0.0f; + P_ = 1; + bFirstUse = true; + Pminus_ = 0.0f; + K_ = 0.0f; + } + + void reset(float Q, float R) { + reset(); + Q_ = Q; + R_ = R; + } + + float update(float val) { + if (bFirstUse) { + xhat_ = val; + bFirstUse = false; + } + + xhatminus_ = xhat_; + Pminus_ = P_ + Q_; + K_ = Pminus_ / (Pminus_ + R_); + xhat_ = xhatminus_ + K_ * (val - xhatminus_); + P_ = (1 - K_) * Pminus_; + + return xhat_; + } +}; + +const char* NvCV_StatusStringFromCode(NvCV_Status code); + +bool CheckResult(NvCV_Status nvErr, unsigned line); + +#define BAIL_IF_CVERR(nvErr, err, code) \ + do { \ + if (!CheckResult(nvErr, __LINE__)) { \ + err = code; \ + goto bail; \ + } \ + } while (0) + +/******************************************************************************** + * FaceEngine + ********************************************************************************/ + +class FaceEngine { + public: + enum Err { errNone, errGeneral, errRun, errInitialization, errRead }; + int input_image_width, input_image_height, input_image_pitch; + static const int NUM_LANDMARKS = 68; // TODO: get this instead from the SDK. + static const int FACE_MODEL_NUM_VERTICES = 3448, FACE_MODEL_NUM_INDICES = 6736; + static const long LANDMARK_CONF_THRESH = 10.f; + + void setInputImageWidth(int width) { input_image_width = width; } + void setInputImageHeight(int height) { input_image_height = height; } + int getInputImageWidth() { return input_image_width; } + int getInputImageHeight() { return input_image_height; } + int getInputImagePitch() { return input_image_pitch = input_image_width * 3 * sizeof(unsigned char); } + + Err createFeatures(const char* modelPath, unsigned int _batchSize = 1); + Err createFaceDetectionFeature(const char* modelPath, CUstream stream); + Err createLandmarkDetectionFeature(const char* modelPath, unsigned int batchSize, CUstream stream); + Err createFaceFittingFeature(const char* modelPath, CUstream stream); + void destroyFeatures(); + void destroyFaceDetectionFeature(); + void destroyLandmarkDetectionFeature(); + void destroyFaceFittingFeature(); + Err initFeatureIOParams(); + Err initFaceDetectionIOParams(NvCVImage* _inputImageBuffer); + Err initLandmarkDetectionIOParams(NvCVImage* _inputImageBuffer); + Err initFaceFittingIOParams(NvCVImage* _inputImageBuffer); + void releaseFeatureIOParams(); + void releaseFaceDetectionIOParams(); + void releaseLandmarkDetectionIOParams(); + void releaseFaceFittingIOParams(); + + unsigned findFaceBoxes(); + NvAR_Rect* getLargestBox(); + NvCV_Status findLandmarks(); + NvAR_BBoxes* getBoundingBoxes(); + NvAR_Point2f* getLandmarks(); + NvAR_Quaternion* getPose(); + float* getLandmarksConfidence(); + float getAverageLandmarksConfidence(); + void enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int FLAG_variant); + static void jiggleBox(std::mt19937& ran, float minMag, float maxMag, const NvAR_Rect& cleanBox, NvAR_Rect& noisyBox); + unsigned findLargestFaceBox(NvAR_Rect& faceBox, int variant = 0); + unsigned acquireFaceBox(cv::Mat& src, NvAR_Rect& faceBox, int variant = 0); + unsigned acquireFaceBoxAndLandmarks(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Rect& faceBox, int variant = 0); + Err fitFaceModel(cv::Mat& frame = cv::Mat()); + NvAR_FaceMesh* getFaceMesh(); + NvAR_RenderingParams* getRenderingParams(); + void setFaceStabilization(bool); + void DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose); + + NvCVImage inputImageBuffer{}, tmpImage{}; + NvAR_FeatureHandle faceDetectHandle{}, landmarkDetectHandle{}, faceFitHandle{}; + std::vector facial_landmarks; + std::vector facial_landmarks_confidence; + std::vector facial_pose; + NvAR_FaceMesh* face_mesh{}; + NvAR_RenderingParams* rendering_params{}; + CUstream stream{}; + std::vector output_bbox_data; + std::vector output_bbox_conf_data; + NvAR_BBoxes output_bboxes{}; + int batchSize; + std::mt19937 ran; + + bool bStabilizeFace; + NvAR_Point2f prevLandmark[NUM_LANDMARKS] = {0}; + + FaceEngine() { + batchSize = 1; + bStabilizeFace = true; + appMode = faceMeshGeneration; + input_image_width = 640; + input_image_height = 480; + input_image_pitch = 3 * input_image_width * sizeof(unsigned char); // RGB + } + enum mode { faceDetection = 0, landmarkDetection, faceMeshGeneration } appMode; + void setAppMode(FaceEngine::mode _mAppMode); +}; +#endif diff --git a/samples/FaceTrack/FaceTrack.cpp b/samples/FaceTrack/FaceTrack.cpp new file mode 100644 index 0000000..dd3e1b3 --- /dev/null +++ b/samples/FaceTrack/FaceTrack.cpp @@ -0,0 +1,966 @@ +/*############################################################################### +# +# Copyright 2020 NVIDIA Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +###############################################################################*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FaceEngine.h" +#include "nvAR.h" +#include "nvAR_defs.h" +#include "opencv2/opencv.hpp" +#include "RenderingUtils.h" + +#ifndef M_PI +#define M_PI 3.1415926535897932385 +#endif /* M_PI */ +#ifndef M_2PI +#define M_2PI 6.2831853071795864769 +#endif /* M_2PI */ +#ifndef M_PI_2 +#define M_PI_2 1.5707963267948966192 +#endif /* M_PI_2 */ +#define F_PI ((float)M_PI) +#define F_PI_2 ((float)M_PI_2) +#define F_2PI ((float)M_2PI) + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#endif /* _MSC_VER */ + +#define BAIL(err, code) \ + do { \ + err = code; \ + goto bail; \ + } while (0) + +/******************************************************************************** + * Command-line arguments + ********************************************************************************/ + +bool FLAG_debug = false, FLAG_verbose = false, FLAG_temporal = true, FLAG_captureOutputs = false, + FLAG_offlineMode = false; +std::string FLAG_outDir, FLAG_inFile, FLAG_outFile, FLAG_modelPath, FLAG_landmarks, FLAG_proxyWireframe, + FLAG_captureCodec = "avc1", FLAG_camRes; +unsigned int FLAG_batch = 1; + +/******************************************************************************** + * Usage + ********************************************************************************/ + +static void Usage() { + printf( + "AboutFace [ ...]\n" + "where is\n" + " --verbose[=(true|false)] report interesting info\n" + " --debug[=(true|false)] report debugging info\n" + " --temporal[=(true|false)] temporally optimize face rect and landmarks\n" + " --capture_outputs[=(true|false)] enables video/image capture and writing face detection/landmark outputs\n" + " --offline_mode[=(true|false)] disables webcam, reads video from file and writes output video results\n" + " --cam_res=[WWWx]HHH specify resolution as height or width x height\n" + " --in_file= specify the input file\n" + " --codec= FOURCC code for the desired codec (default H264)\n" + " --in= specify the input file\n" + " --out_file= specify the output file\n" + " --out= specify the output file\n" + " --model_path= specify the directory containing the TRT models\n" + " --wireframe_mesh= specify the path to a proxy wireframe mesh\n" + " --batch= 1 - 8, used for batch inferencing in landmark detector " + " --benchmarks[=] run benchmarks\n"); +} + +static bool GetFlagArgVal(const char *flag, const char *arg, const char **val) { + if (*arg != '-') { + return false; + } + while (*++arg == '-') { + continue; + } + const char *s = strchr(arg, '='); + if (s == NULL) { + if (strcmp(flag, arg) != 0) { + return false; + } + *val = NULL; + return true; + } + unsigned n = (unsigned)(s - arg); + if ((strlen(flag) != n) || (strncmp(flag, arg, n) != 0)) { + return false; + } + *val = s + 1; + return true; +} + +static bool GetFlagArgVal(const char *flag, const char *arg, std::string *val) { + const char *valStr; + if (!GetFlagArgVal(flag, arg, &valStr)) return false; + val->assign(valStr ? valStr : ""); + return true; +} + +static bool GetFlagArgVal(const char *flag, const char *arg, bool *val) { + const char *valStr; + bool success = GetFlagArgVal(flag, arg, &valStr); + if (success) { + *val = (valStr == NULL || strcasecmp(valStr, "true") == 0 || strcasecmp(valStr, "on") == 0 || + strcasecmp(valStr, "yes") == 0 || strcasecmp(valStr, "1") == 0); + } + return success; +} + +bool GetFlagArgVal(const char *flag, const char *arg, long *val) { + const char *valStr; + bool success = GetFlagArgVal(flag, arg, &valStr); + if (success) { + *val = strtol(valStr, NULL, 10); + } + return success; +} + +static bool GetFlagArgVal(const char *flag, const char *arg, unsigned *val) { + long longVal; + bool success = GetFlagArgVal(flag, arg, &longVal); + if (success) { + *val = (unsigned)longVal; + } + return success; +} + +/******************************************************************************** + * StringToFourcc + ********************************************************************************/ + +static int StringToFourcc(const std::string &str) { + union chint { + int i; + char c[4]; + }; + chint x = {0}; + for (int n = (str.size() < 4) ? (int)str.size() : 4; n--;) x.c[n] = str[n]; + return x.i; +} + +/******************************************************************************** + * ParseMyArgs + ********************************************************************************/ + +static int ParseMyArgs(int argc, char **argv) { + int errs = 0; + for (--argc, ++argv; argc--; ++argv) { + bool help; + const char *arg = *argv; + if (arg[0] != '-') { + continue; + } else if ((arg[1] == '-') && + (GetFlagArgVal("verbose", arg, &FLAG_verbose) || GetFlagArgVal("debug", arg, &FLAG_debug) || + GetFlagArgVal("in", arg, &FLAG_inFile) || GetFlagArgVal("in_file", arg, &FLAG_inFile) || + GetFlagArgVal("out", arg, &FLAG_outFile) || GetFlagArgVal("out_file", arg, &FLAG_outFile) || + GetFlagArgVal("offline_mode", arg, &FLAG_offlineMode) || + GetFlagArgVal("capture_outputs", arg, &FLAG_captureOutputs) || + GetFlagArgVal("cam_res", arg, &FLAG_camRes) || GetFlagArgVal("codec", arg, &FLAG_captureCodec) || + GetFlagArgVal("landmarks", arg, &FLAG_landmarks) || GetFlagArgVal("model_path", arg, &FLAG_modelPath) || + GetFlagArgVal("wireframe_mesh", arg, &FLAG_proxyWireframe) || + GetFlagArgVal("temporal", arg, &FLAG_temporal))) { + continue; + } else if (GetFlagArgVal("help", arg, &help)) { + Usage(); + } else if (arg[1] != '-') { + for (++arg; *arg; ++arg) { + if (*arg == 'v') { + FLAG_verbose = true; + } else { + // printf("Unknown flag: \"-%c\"\n", *arg); + } + } + continue; + } else { + // printf("Unknown flag: \"%s\"\n", arg); + } + } + return errs; +} + +enum { + myErrNone = 0, + myErrShader = -1, + myErrProgram = -2, + myErrTexture = -3, +}; + +#if 1 +class MyTimer { + public: + void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */ + void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */ + void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */ + void stop() { pause(); } /**< Stop the timer. */ + double elapsedTimeFloat() const { + return std::chrono::duration(dt).count(); + } /**< Report the elapsed time as a float. */ + private: + std::chrono::high_resolution_clock::time_point t0; + std::chrono::high_resolution_clock::duration dt; +}; +#endif + +std::string getCalendarTime() { + // Get the current time + std::chrono::system_clock::time_point currentTimePoint = std::chrono::system_clock::now(); + // Convert to time_t from time_point + std::time_t currentTime = std::chrono::system_clock::to_time_t(currentTimePoint); + // Convert to tm to get structure holding a calendar date and time broken down into its components. + std::tm brokenTime = *std::localtime(¤tTime); + std::ostringstream calendarTime; + calendarTime << std::put_time( + &brokenTime, + "%Y-%m-%d-%H-%M-%S"); // (YYYY-MM-DD-HH-mm-ss)----- + // Get the time since epoch 0(Thu Jan 1 00:00:00 1970) and the remainder after division is + // our milliseconds + std::chrono::milliseconds currentMilliseconds = + std::chrono::duration_cast(currentTimePoint.time_since_epoch()) % 1000; + // Append the milliseconds to the stream + calendarTime << "-" << std::setfill('0') << std::setw(3) << currentMilliseconds.count(); // milliseconds + return calendarTime.str(); +} + +class DoApp { + public: + enum Err { + errNone, + errUnimplemented, + errMissing, + errVideo, + errImageSize, + errNotFound, + errFaceModelInit, + errGLFWInit, + errGLInit, + errRendererInit, + errGLResource, + errGLGeneric, + errFaceFit, + errNoFace, + errSDK, + errCuda, + errCancel, + errInitFaceEngine + }; + + FaceEngine face_ar_engine; + DoApp(); + ~DoApp(); + + void stop(); + Err initFaceEngine(const char *modelPath = nullptr); + Err initCamera(const char *camRes = nullptr); + Err initOfflineMode(const char *inputFilename = nullptr, const char *outputFilename = nullptr); + Err acquireFrame(); + Err acquireFaceBox(); + Err acquireFaceBoxAndLandmarks(); + Err fitFaceModel(); + Err run(); + void showFaceFitErrorMessage(); + void drawFPS(cv::Mat &img); + void DrawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox); + void DrawLandmarkPoints(const cv::Mat &src, NvAR_Point2f *facial_landmarks); + void DrawFaceMesh(const cv::Mat &src, NvAR_FaceMesh *face_mesh); + void drawKalmanStatus(cv::Mat &img); + void drawVideoCaptureStatus(cv::Mat &img); + Err setProxyWireframe(const char *path); + void processKey(int key); + void writeVideoAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks = NULL); + void writeFrameAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks = NULL); + void writeEstResults(std::ofstream &outputFile, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks = NULL); + void getFPS(); + static const char *errorStringFromCode(Err code); + + cv::VideoCapture cap{}; + cv::Mat frame; + int inputWidth, inputHeight; + cv::VideoWriter faceDetectOutputVideo{}, landMarkOutputVideo{}, faceFittingOutputVideo{}; + int frameIndex; + static const char windowTitle[]; + double frameTime; + // std::chrono::high_resolution_clock::time_point frameTimer; + MyTimer frameTimer; + cv::VideoWriter capturedVideo; + std::ofstream faceEngineVideoOutputFile; + + FaceEngine::Err nvErr; + float expr[6]; + bool drawVisualization, showFPS, captureVideo, captureFrame; + std::vector> proxyWireframe; + float scaleOffsetXY[4]; + std::vector wfMesh_tvi_data; +}; + +DoApp *gApp = nullptr; +const char DoApp::windowTitle[] = "WINDOW"; + +void DoApp::processKey(int key) { + switch (key) { + case '3': + face_ar_engine.destroyFeatures(); + face_ar_engine.setAppMode(FaceEngine::mode::faceMeshGeneration); + nvErr = face_ar_engine.createFeatures(FLAG_modelPath.c_str()); + // If there is an error, fallback to mode '2' i.e. landmark detection + if (nvErr == FaceEngine::Err::errNone) { + face_ar_engine.initFeatureIOParams(); + break; + } else if (nvErr == FaceEngine::Err::errInitialization) { + showFaceFitErrorMessage(); + } + case '2': + face_ar_engine.destroyFeatures(); + face_ar_engine.setAppMode(FaceEngine::mode::landmarkDetection); + face_ar_engine.createFeatures(FLAG_modelPath.c_str()); + face_ar_engine.initFeatureIOParams(); + break; + case '1': + face_ar_engine.destroyFeatures(); + face_ar_engine.setAppMode(FaceEngine::mode::faceDetection); + face_ar_engine.createFeatures(FLAG_modelPath.c_str()); + face_ar_engine.initFeatureIOParams(); + break; + case 'C': + case 'c': + captureVideo = !captureVideo; + break; + case 'S': + case 's': + captureFrame = !captureFrame; + break; + case 'W': + case 'w': + drawVisualization = !drawVisualization; + break; + case 'F': + case 'f': + showFPS = !showFPS; + break; + default: + break; + } +} + +DoApp::Err DoApp::initFaceEngine(const char *modelPath) { + Err err = errNone; + + if (!cap.isOpened()) return errVideo; + + nvErr = face_ar_engine.createFeatures(modelPath); + if (nvErr != FaceEngine::Err::errNone) { + if (nvErr == FaceEngine::Err::errInitialization && face_ar_engine.appMode == FaceEngine::mode::faceMeshGeneration) { + showFaceFitErrorMessage(); + face_ar_engine.destroyFeatures(); + face_ar_engine.setAppMode(FaceEngine::mode::landmarkDetection); + nvErr = face_ar_engine.createFeatures(modelPath); + } + if (nvErr != FaceEngine::Err::errNone) + err = errInitFaceEngine; + } + +#ifdef DEBUG + detector->setOutputLocation(outputDir); +#endif // DEBUG + +#define VISUALIZE +#ifdef VISUALIZE + if (!FLAG_offlineMode) cv::namedWindow(windowTitle, 1); +#endif // VISUALIZE + + frameIndex = 0; + + return err; +} + +void DoApp::stop() { + face_ar_engine.destroyFeatures(); + + if (FLAG_offlineMode) { + faceDetectOutputVideo.release(); + landMarkOutputVideo.release(); + faceFittingOutputVideo.release(); + } + cap.release(); +#ifdef VISUALIZE + cv::destroyAllWindows(); +#endif // VISUALIZE +} + +void DoApp::showFaceFitErrorMessage() { + cv::Mat errBox = cv::Mat::zeros(120, 640, CV_8UC3); + cv::putText(errBox, cv::String("Warning: Face Fitting needs face_model0.nvf in the path --model_path"), cv::Point(20, 20), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1); + cv::putText(errBox, cv::String("or in NVAR_MODEL_DIR environment variable."), cv::Point(20, 40), cv::FONT_HERSHEY_SIMPLEX, + 0.5, cv::Scalar(255, 255, 255), 1); + cv::putText(errBox, cv::String("See samples\\FaceTrack\\Readme.txt"), cv::Point(20, 60), cv::FONT_HERSHEY_SIMPLEX, + 0.5, cv::Scalar(255, 255, 255), 1); + cv::putText(errBox, cv::String("Press any key to continue with other features"), cv::Point(20, 80), cv::FONT_HERSHEY_SIMPLEX, 0.5, + cv::Scalar(255, 255, 255), 1); + cv::imshow(windowTitle, errBox); + cv::waitKey(0); +} + +void DoApp::DrawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox) { + cv::Mat frame; + if (FLAG_offlineMode) + frame = src.clone(); + else + frame = src; + + if (output_bbox) + cv::rectangle(frame, cv::Point((int)output_bbox->x, (int)output_bbox->y), + cv::Point((int)output_bbox->x + output_bbox->width, (int)output_bbox->y + output_bbox->height), + cv::Scalar(255, 0, 0), 2); + if (FLAG_offlineMode) faceDetectOutputVideo.write(frame); +} + +void DoApp::writeVideoAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks) { + if (captureVideo) { + if (!capturedVideo.isOpened()) { + const std::string currentCalendarTime = getCalendarTime(); + const std::string capturedOutputFileName = currentCalendarTime + ".mp4"; + getFPS(); + if (frameTime) { + float fps = 1. / frameTime; + capturedVideo.open(capturedOutputFileName, StringToFourcc(FLAG_captureCodec), fps, + cv::Size(frame.cols, frame.rows)); + if (!capturedVideo.isOpened()) { + std::cout << "Error: Could not open video: \"" << capturedOutputFileName << "\"\n"; + return; + } + if (FLAG_verbose) { + std::cout << "Capturing video started" << std::endl; + } + } else { // If frameTime is 0.f, returns without writing the frame to the Video + return; + } + const std::string outputsFileName = currentCalendarTime + ".txt"; + faceEngineVideoOutputFile.open(outputsFileName, std::ios_base::out); + if (!faceEngineVideoOutputFile.is_open()) { + std::cout << "Error: Could not open file: \"" << outputsFileName << "\"\n"; + return; + } + std::string landmarkDetectionMode = (landmarks == NULL) ? "Off" : "On"; + faceEngineVideoOutputFile << "// FaceDetectOn, LandmarkDetect" << landmarkDetectionMode << "\n "; + faceEngineVideoOutputFile + << "// kNumFaces, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumFaces}, kNumLMs, [lm_x, lm_y]{kNumLMs}\n"; + } + // Write each frame to the Video + capturedVideo << frame; + writeEstResults(faceEngineVideoOutputFile, output_bboxes, landmarks); + } else { + if (capturedVideo.isOpened()) { + if (FLAG_verbose) { + std::cout << "Capturing video ended" << std::endl; + } + capturedVideo.release(); + if (faceEngineVideoOutputFile.is_open()) faceEngineVideoOutputFile.close(); + } + } +} + +void DoApp::writeEstResults(std::ofstream &outputFile, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks) { + /** + * Output File Format : + * FaceDetectOn, LandmarkDetectOn + * kNumFaces, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumFaces}, kNumLMs, [lm_x, lm_y]{kNumLMs} + */ + + int faceDetectOn = (face_ar_engine.appMode == FaceEngine::mode::faceDetection || + face_ar_engine.appMode == FaceEngine::mode::landmarkDetection || + face_ar_engine.appMode == FaceEngine::mode::faceMeshGeneration) + ? 1 + : 0; + int landmarkDetectOn = (face_ar_engine.appMode == FaceEngine::mode::landmarkDetection || + face_ar_engine.appMode == FaceEngine::mode::faceMeshGeneration) + ? 1 + : 0; + outputFile << faceDetectOn << "," << landmarkDetectOn << "\n"; + + if (faceDetectOn && output_bboxes.num_boxes) { + // Append number of faces detected in the current frame + outputFile << unsigned(output_bboxes.num_boxes) << ","; + // write outputbboxes to outputFile + for (size_t i = 0; i < output_bboxes.num_boxes; i++) { + int x1 = (int)output_bboxes.boxes[i].x, y1 = (int)output_bboxes.boxes[i].y, + width = (int)output_bboxes.boxes[i].width, height = (int)output_bboxes.boxes[i].height; + outputFile << x1 << "," << y1 << "," << width << "," << height << ","; + } + } else { + outputFile << "0,"; + } + if (landmarkDetectOn && output_bboxes.num_boxes) { + // Append number of landmarks + outputFile << FaceEngine::NUM_LANDMARKS << ","; + // Append NUM_LANDMARKS * 2 points + NvAR_Point2f *pt, *endPt; + for (endPt = (pt = (NvAR_Point2f *)landmarks) + FaceEngine::NUM_LANDMARKS; pt < endPt; ++pt) + outputFile << pt->x << "," << pt->y << ","; + } else { + outputFile << "0,"; + } + + outputFile << "\n"; +} + +void DoApp::writeFrameAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *landmarks) { + if (captureFrame) { + const std::string currentCalendarTime = getCalendarTime(); + const std::string capturedFrame = currentCalendarTime + ".png"; + cv::imwrite(capturedFrame, frame); + if (FLAG_verbose) { + std::cout << "Captured the frame" << std::endl; + } + // Write Face Engine Outputs + const std::string outputFilename = currentCalendarTime + ".txt"; + std::ofstream outputFile; + outputFile.open(outputFilename, std::ios_base::out); + if (!outputFile.is_open()) { + std::cout << "Error: Could not open file: \"" << outputFilename << "\"\n"; + return; + } + std::string landmarkDetectionMode = (landmarks == NULL) ? "Off" : "On"; + outputFile << "// FaceDetectOn, LandmarkDetect" << landmarkDetectionMode << "\n"; + outputFile << "// kNumFaces, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumFaces}, kNumLMs, [lm_x, lm_y]{kNumLMs}\n"; + writeEstResults(outputFile, output_bboxes, landmarks); + if (outputFile.is_open()) outputFile.close(); + captureFrame = false; + } +} + +void DoApp::DrawLandmarkPoints(const cv::Mat &src, NvAR_Point2f *facial_landmarks) { + cv::Mat frame; + if (FLAG_offlineMode) + frame = src.clone(); + else + frame = src; + NvAR_Point2f *pt, *endPt; + for (endPt = (pt = (NvAR_Point2f *)facial_landmarks) + FaceEngine::NUM_LANDMARKS; pt < endPt; ++pt) + cv::circle(frame, cv::Point(lround(pt->x), lround(pt->y)), 1, cv::Scalar(0, 0, 255), -1); + NvAR_Quaternion *pose = face_ar_engine.getPose(); + if (pose) + face_ar_engine.DrawPose(frame, pose); + if (FLAG_offlineMode) landMarkOutputVideo.write(frame); +} + +void DoApp::DrawFaceMesh(const cv::Mat &src, NvAR_FaceMesh *face_mesh) { + cv::Mat render_frame; + if (FLAG_offlineMode) + render_frame = src.clone(); + else + render_frame = src; + + const cv::Scalar wfColor(0, 160, 0, 255); + //Low resolution mesh can be used for visualization only + if (proxyWireframe.size() > 0) { + NvAR_FaceMesh wfMesh{nullptr, 0, nullptr, 0}; + wfMesh.num_vertices = face_mesh->num_vertices; + wfMesh.vertices = face_mesh->vertices; + wfMesh.num_tri_idx = proxyWireframe.size(); + wfMesh_tvi_data.resize(wfMesh.num_tri_idx); + wfMesh.tvi = wfMesh_tvi_data.data(); + + for (int i = 0; i < proxyWireframe.size(); i++) { + auto proxyWireframe_idx = proxyWireframe[i]; + wfMesh.tvi[i].vec[0] = proxyWireframe_idx[0]; + wfMesh.tvi[i].vec[1] = proxyWireframe_idx[1]; + wfMesh.tvi[i].vec[2] = proxyWireframe_idx[2]; + } + draw_wireframe(render_frame, wfMesh, *face_ar_engine.getRenderingParams(), wfColor); + } else { + draw_wireframe(render_frame, *face_mesh, * face_ar_engine.getRenderingParams(), wfColor); + } + + if (FLAG_offlineMode) faceFittingOutputVideo.write(render_frame); +} + +DoApp::Err DoApp::acquireFrame() { + Err err = errNone; + + // If the machine goes to sleep with the app running and then wakes up, the camera object is not destroyed but the + // frames we try to read are empty. So we try to re-initialize the camera with the same resolution settings. If the + // resolution has changed, you will need to destroy and create the features again with the new camera resolution (not + // done here) as well as reallocate memory accordingly with FaceEngine::initFeatureIOParams() + cap >> frame; // get a new frame from camera + if (frame.empty()) { + // if in Offline mode, this means end of video,so we return + if (FLAG_offlineMode) return errVideo; + // try Init one more time if reading frames from camera + initCamera(FLAG_camRes.c_str()); + cap >> frame; + if (frame.empty()) return errVideo; + } + + return err; +} + +DoApp::Err DoApp::acquireFaceBox() { + Err err = errNone; + NvAR_Rect output_bbox; + + // get landmarks in original image resolution coordinate space + unsigned n = face_ar_engine.acquireFaceBox(frame, output_bbox, 0); + + if (n && FLAG_verbose) { + printf("FaceBox: [\n"); + printf("%7.1f%7.1f%7.1f%7.1f\n", output_bbox.x, output_bbox.y, output_bbox.x + output_bbox.width, + output_bbox.y + output_bbox.height); + printf("]\n"); + } + if (FLAG_captureOutputs) { + writeFrameAndEstResults(frame, face_ar_engine.output_bboxes); + writeVideoAndEstResults(frame, face_ar_engine.output_bboxes); + } + if (0 == n) return errNoFace; + +#ifdef VISUALIZE + + if (drawVisualization) { + DrawBBoxes(frame, &output_bbox); + } +#endif // VISUALIZE + frameIndex++; + + return err; +} + +DoApp::Err DoApp::acquireFaceBoxAndLandmarks() { + Err err = errNone; + + NvAR_Rect output_bbox; + NvAR_Point2f facial_landmarks[FaceEngine::NUM_LANDMARKS]; + + // get landmarks in original image resolution coordinate space + unsigned n = face_ar_engine.acquireFaceBoxAndLandmarks(frame, facial_landmarks, output_bbox, 0); + + if (n && FLAG_verbose && face_ar_engine.appMode != FaceEngine::mode::faceDetection) { + printf("Landmarks: [\n"); + NvAR_Point2f *pt, *endPt; + for (endPt = (pt = (NvAR_Point2f *)facial_landmarks) + FaceEngine::NUM_LANDMARKS; pt < endPt; ++pt) + printf("%7.1f%7.1f\n", pt->x, pt->y); + printf("]\n"); + } + if (FLAG_captureOutputs) { + writeFrameAndEstResults(frame, face_ar_engine.output_bboxes, facial_landmarks); + writeVideoAndEstResults(frame, face_ar_engine.output_bboxes, facial_landmarks); + } + if (0 == n) return errNoFace; + +#ifdef VISUALIZE + + if (drawVisualization) { + DrawLandmarkPoints(frame, facial_landmarks); + if (FLAG_offlineMode) { + DrawBBoxes(frame, &output_bbox); + } + } +#endif // VISUALIZE + frameIndex++; + + return err; +} + +DoApp::Err DoApp::initCamera(const char *camRes) { + if (cap.open(0)) { + if (camRes) { + int n; + n = sscanf(camRes, "%d%*[xX]%d", &inputWidth, &inputHeight); + switch (n) { + case 2: + break; // We have read both width and height + case 1: + inputHeight = inputWidth; + inputWidth = (int)(inputHeight * (4. / 3.) + .5); + break; + default: + inputHeight = 0; + inputWidth = 0; + break; + } + if (inputWidth) cap.set(CV_CAP_PROP_FRAME_WIDTH, inputWidth); + if (inputHeight) cap.set(CV_CAP_PROP_FRAME_HEIGHT, inputHeight); + + inputWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); + inputHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); + face_ar_engine.setInputImageWidth(inputWidth); + face_ar_engine.setInputImageHeight(inputHeight); + } + } else + return errVideo; + return errNone; +} + +DoApp::Err DoApp::initOfflineMode(const char *inputFilename, const char *outputFilename) { + if (cap.open(inputFilename)) { + inputWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); + inputHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); + face_ar_engine.setInputImageWidth(inputWidth); + face_ar_engine.setInputImageHeight(inputHeight); + } else { + return Err::errNotFound; + } + + std::string fdOutputVideoName, fldOutputVideoName, ffOutputVideoName; + std::string outputFilePrefix; + if (outputFilename && strlen(outputFilename) != 0) { + outputFilePrefix = outputFilename; + } else { + size_t lastindex = std::string(inputFilename).find_last_of("."); + outputFilePrefix = std::string(inputFilename).substr(0, lastindex); + } + fdOutputVideoName = outputFilePrefix + "_bbox.mp4"; + fldOutputVideoName = outputFilePrefix + "_landmarks.mp4"; + ffOutputVideoName = outputFilePrefix + "_faceModel.mp4"; + + if (!faceDetectOutputVideo.open(fdOutputVideoName, StringToFourcc(FLAG_captureCodec), cap.get(CV_CAP_PROP_FPS), + cv::Size(inputWidth, inputHeight))) + return Err::errSDK; + if (!landMarkOutputVideo.open(fldOutputVideoName, StringToFourcc(FLAG_captureCodec), cap.get(CV_CAP_PROP_FPS), + cv::Size(inputWidth, inputHeight))) + return Err::errSDK; + if (!faceFittingOutputVideo.open(ffOutputVideoName, StringToFourcc(FLAG_captureCodec), cap.get(CV_CAP_PROP_FPS), + cv::Size(inputWidth, inputHeight))) + return Err::errSDK; + + return Err::errNone; +} + +DoApp::Err DoApp::fitFaceModel() { + DoApp::Err doErr = errNone; + nvErr = face_ar_engine.fitFaceModel(frame); + + if (FaceEngine::Err::errNone == nvErr) { +#ifdef VISUALIZE + frameTimer.pause(); + if (drawVisualization) { + DrawFaceMesh(frame, face_ar_engine.getFaceMesh()); + if (FLAG_offlineMode) { + DrawLandmarkPoints(frame, face_ar_engine.getLandmarks()); + DrawBBoxes(frame, face_ar_engine.getLargestBox()); + } + } + frameTimer.resume(); +#endif // VISUALIZE + } else { + doErr = errFaceFit; + } + + return doErr; +} + +DoApp::DoApp() { + // Make sure things are initialized properly + gApp = this; + drawVisualization = true; + showFPS = false; + captureVideo = false; + captureFrame = false; + frameTime = 0; + frameIndex = 0; + nvErr = FaceEngine::errNone; + scaleOffsetXY[0] = scaleOffsetXY[2] = 1.f; + scaleOffsetXY[1] = scaleOffsetXY[3] = 0.f; +} + +DoApp::~DoApp() {} + +void DoApp::getFPS() { + const float timeConstant = 16.f; + frameTimer.stop(); + float t = (float)frameTimer.elapsedTimeFloat(); + if (t < 100.f) { + if (frameTime) + frameTime += (t - frameTime) * (1.f / timeConstant); // 1 pole IIR filter + else + frameTime = t; + } else { // Ludicrous time interval; reset + frameTime = 0.f; // WAKE UP + } + frameTimer.start(); +} + +void DoApp::drawFPS(cv::Mat &img) { + getFPS(); + if (frameTime && showFPS) { + char buf[32]; + snprintf(buf, sizeof(buf), "%.1f", 1. / frameTime); + cv::putText(img, buf, cv::Point(img.cols - 80, img.rows - 10), cv::FONT_HERSHEY_SIMPLEX, 1, + cv::Scalar(255, 255, 255), 1); + } +} + +void DoApp::drawKalmanStatus(cv::Mat &img) { + char buf[32]; + snprintf(buf, sizeof(buf), "Kalman %s", (face_ar_engine.bStabilizeFace ? "on" : "off")); + cv::putText(img, buf, cv::Point(10, img.rows - 40), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 1); +} + +void DoApp::drawVideoCaptureStatus(cv::Mat &img) { + char buf[32]; + snprintf(buf, sizeof(buf), "Video Capturing %s", (captureVideo ? "on" : "off")); + cv::putText(img, buf, cv::Point(10, img.rows - 70), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 1); +} + +DoApp::Err DoApp::run() { + DoApp::Err doErr = errNone; + + face_ar_engine.initFeatureIOParams(); + + while (1) { + doErr = acquireFrame(); + if (doErr != DoApp::errNone) return doErr; + if (face_ar_engine.appMode == FaceEngine::mode::faceDetection) { + doErr = acquireFaceBox(); + } else if (face_ar_engine.appMode == FaceEngine::mode::landmarkDetection) { + doErr = acquireFaceBoxAndLandmarks(); + } else if (face_ar_engine.appMode == FaceEngine::mode::faceMeshGeneration) { + doErr = fitFaceModel(); + } + if ((DoApp::errNoFace == doErr || DoApp::errFaceFit == doErr) && FLAG_offlineMode) { + faceDetectOutputVideo.write(frame); + landMarkOutputVideo.write(frame); + faceFittingOutputVideo.write(frame); + } + if (DoApp::errCancel == doErr || DoApp::errVideo == doErr) return doErr; + if (!frame.empty() && !FLAG_offlineMode) { + if (drawVisualization) { + drawFPS(frame); + drawKalmanStatus(frame); + if (FLAG_captureOutputs && captureVideo) drawVideoCaptureStatus(frame); + } + cv::imshow(windowTitle, frame); + } + + if (!FLAG_offlineMode) { + int n = cv::waitKey(1); + if (n >= 0) { + static const int ESC_KEY = 27; + if (n == ESC_KEY) break; + processKey(n); + } + } + } + return doErr; +} + +DoApp::Err DoApp::setProxyWireframe(const char *path) { + std::ifstream file(path); + if (!file.is_open()) return errFaceModelInit; + std::string lineBuf; + while (getline(file, lineBuf)) { + std::array tri; + if (3 == sscanf(lineBuf.c_str(), "f %hd %hd %hd", &tri[0], &tri[1], &tri[2])) { + --tri[0]; /* Convert from 1-based to 0-based indices */ + --tri[1]; + --tri[2]; + proxyWireframe.push_back(tri); + } + } + file.close(); + return errNone; +} + +const char *DoApp::errorStringFromCode(DoApp::Err code) { + struct LUTEntry { + Err code; + const char *str; + }; + static const LUTEntry lut[] = { + {errNone, "no error"}, + {errUnimplemented, "the feature is unimplemented"}, + {errMissing, "missing input parameter"}, + {errVideo, "no video source has been found"}, + {errImageSize, "the image size cannot be accommodated"}, + {errNotFound, "the item cannot be found"}, + {errFaceModelInit, "face model initialization failed"}, + {errGLFWInit, "GLFW initialization failed"}, + {errGLInit, "OpenGL initialization failed"}, + {errRendererInit, "renderer initialization failed"}, + {errGLResource, "an OpenGL resource could not be found"}, + {errGLGeneric, "an otherwise unspecified OpenGL error has occurred"}, + {errFaceFit, "an error has occurred while face fitting"}, + {errNoFace, "no face has been found"}, + {errSDK, "an SDK error has occurred"}, + {errCuda, "a CUDA error has occurred"}, + {errCancel, "the user cancelled"}, + {errInitFaceEngine, "an error occurred while initializing the Face Engine"}, + }; + for (const LUTEntry *p = lut; p < &lut[sizeof(lut) / sizeof(lut[0])]; ++p) + if (p->code == code) return p->str; + static char msg[18]; + snprintf(msg, sizeof(msg), "error #%d", code); + return msg; +} + +/******************************************************************************** + * main + ********************************************************************************/ + +int main(int argc, char **argv) { + DoApp app; + DoApp::Err doErr; + NvCV_Status nvErr; + + // Parse the arguments + if (0 != ParseMyArgs(argc, argv)) return -100; + + if (FLAG_verbose) printf("Enable temporal optimizations in detecting face and landmarks = %d\n", FLAG_temporal); + app.face_ar_engine.setFaceStabilization(FLAG_temporal); + + doErr = DoApp::errFaceModelInit; + if (FLAG_modelPath.empty()) { + printf("WARNING: Model path not specified. Please set --model_path=/path/to/trt/and/face/models\n" + "SDK will attempt to load the models from NVAR_MODEL_DIR environment variable"); + } + + if (FLAG_offlineMode) { + if (FLAG_inFile.empty()) { + doErr = DoApp::errMissing; + printf("ERROR: %s, please specify input file using --in_file or --in \n", app.errorStringFromCode(doErr)); + goto bail; + } + app.initOfflineMode(FLAG_inFile.c_str(), FLAG_outFile.c_str()); + } else { + app.initCamera(FLAG_camRes.c_str()); + } + doErr = app.initFaceEngine(FLAG_modelPath.c_str()); + if (DoApp::errNone != doErr) { + printf("ERROR: %s\n", app.errorStringFromCode(doErr)); + goto bail; + } + + if (!FLAG_proxyWireframe.empty()) app.setProxyWireframe(FLAG_proxyWireframe.c_str()); + + doErr = app.run(); + +bail: + app.stop(); + return (int)doErr; +} diff --git a/samples/FaceTrack/FaceTrack.exe b/samples/FaceTrack/FaceTrack.exe new file mode 100644 index 0000000..0d9316e Binary files /dev/null and b/samples/FaceTrack/FaceTrack.exe differ diff --git a/samples/FaceTrack/Readme.txt b/samples/FaceTrack/Readme.txt new file mode 100644 index 0000000..4ac5e07 --- /dev/null +++ b/samples/FaceTrack/Readme.txt @@ -0,0 +1,48 @@ +FaceTrack is a sample Windows application that demonstrates the face detection, landmark detection, +and 3D face reconstruction features of the NVIDIA AR SDK. The application requires a video feed +from a camera connected to the computer running the application, or from a video file, as specified +with command-line arguments (enumerated by executing: FaceTrack.exe --help). + +The sample application can run in 3 modes which can be toggled through the '1', '2' and '3' keys on +the keyboard +1 - Face tracking +2 - Facial landmark tracking +3 - 3D face reconstruction + +For more controls and configurations of the sample app, please read the SDK programming guide. + +3D face fitting requires the model file face_model0.nvf which is not part of the SDK package. +It has to be generated through the steps described below. The sample app can still be used in +mode 1 and 2 without this file. + +To generate the face model file face_model0.nvf required for 3D face fitting: + +1) Download the following Surrey Face Model files from the eos project page on Github: + sfm_shape_3448.bin + expression_blendshapes_3448.bin + sfm_3448_edge_topology.json + sfm_model_contours.json + ibug_to_sfm.txt + +2) Convert the files that you downloaded to the NVIDIA .nvf format. + +tools\ConvertSurreyFaceModel.exe +--shape=/sfm_shape_3448.bin +--blend_shape=/expression_blendshapes_3448.bin +--topology=/sfm_3448_edge_topology.json +--contours=/sfm_model_contours.json +--ibug=/ibug_to_sfm.txt +--out=/face_model0.nvf + +path +The full or relative path to the folder that contains the Surrey Face Model files that you downloaded. +Either the forward slash (/) or back slash (\) can be used as a separator between path elements. + +output-path +The full or relative path to the folder where you want the output .nvf format file to be written. +Either the forward slash (/) or back slash (\) can be used as a separator between path elements. + +The ConvertSurreyFaceModel.exe file is distributed in the https://github.com/nvidia/BROADCAST-AR-SDK repo. + +3) The sample application provided with NVIDIA AR SDK requires that the model file be named face_model0.nvf. +Place the face_model0.nvf file in the /bin/models folder. diff --git a/samples/FaceTrack/run.bat b/samples/FaceTrack/run.bat new file mode 100644 index 0000000..bc2f255 --- /dev/null +++ b/samples/FaceTrack/run.bat @@ -0,0 +1,3 @@ +SETLOCAL +SET PATH=%PATH%;..\..\samples\external\opencv\bin; +FaceTrack.exe diff --git a/samples/external/CMakeLists.txt b/samples/external/CMakeLists.txt new file mode 100644 index 0000000..f036c91 --- /dev/null +++ b/samples/external/CMakeLists.txt @@ -0,0 +1,44 @@ +####################### +# Interface to OpenCV # +####################### + +if(MSVC) + if(CMAKE_CL_64) + set(OpenCV_ARCH x64) + elseif((CMAKE_GENERATOR MATCHES "ARM") OR ("${arch_hint}" STREQUAL "ARM") OR (CMAKE_VS_EFFECTIVE_PLATFORMS MATCHES "ARM|arm")) + # see Modules/CmakeGenericSystem.cmake + set(OpenCV_ARCH ARM) + else() + set(OpenCV_ARCH x86) + endif() + if(MSVC_VERSION GREATER_EQUAL 1920) + #set(OpenCV_RUNTIME vc16) + message("No Visual Studio 2019 OpenCV library available; trying 2017 library instead") + set(OpenCV_RUNTIME vc15) + elseif(MSVC_VERSION GREATER_EQUAL 1910) + set(OpenCV_RUNTIME vc15) + elseif(MSVC_VERSION GREATER_EQUAL 1900) + set(OpenCV_RUNTIME vc14) + else() + message("MSVC_VERSION ${MSVC_VERSION} is not accommodated") + endif() +endif() + +add_library(opencv346 INTERFACE) +set(OpenCV_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/opencv/include ${CMAKE_CURRENT_SOURCE_DIR}/opencv/include/opencv2) +target_include_directories(opencv346 INTERFACE ${OpenCV_INCLUDE_DIR}) +target_link_libraries(opencv346 INTERFACE optimized ${CMAKE_CURRENT_SOURCE_DIR}/opencv/lib/opencv_world346.lib) + +#################### +# Interface to GLM # +#################### +find_path(GLM_INCLUDE_DIR glm/glm.hpp + PATH_SUFFIXES include + PATHS + glm + /usr/local/include/glm +) +add_library(GLM INTERFACE) +target_include_directories(GLM INTERFACE ${GLM_INCLUDE_DIR}) +#message( "GLM_INCLUDE_DIR is ${GLM_INCLUDE_DIR}" ) + diff --git a/samples/external/ThirdPartyLicenses.txt b/samples/external/ThirdPartyLicenses.txt new file mode 100644 index 0000000..171aa57 --- /dev/null +++ b/samples/external/ThirdPartyLicenses.txt @@ -0,0 +1,76 @@ +====OpenCV 3.4.6==== +By downloading, copying, installing or using the software you agree to this license. If you do not agree to this license, do not download, install, copy or use the software. + +License Agreement +For Open Source Computer Vision Library +(3-clause BSD License) + +Copyright (C) 2000-2019, Intel Corporation, all rights reserved. +Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. +Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. +Copyright (C) 2015-2016, Itseez Inc., all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the names of the copyright holders nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission. +This software is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall copyright holders or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. + +====GLM 0.9.8==== +================================================================================ +OpenGL Mathematics (GLM) +-------------------------------------------------------------------------------- +GLM is licensed under The Happy Bunny License and MIT License + +================================================================================ +The Happy Bunny License (Modified MIT License) +-------------------------------------------------------------------------------- +Copyright (c) 2005 - 2014 G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Restrictions: + By making use of the Software for military purposes, you choose to make a + Bunny unhappy. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +================================================================================ +The MIT License +-------------------------------------------------------------------------------- +Copyright (c) 2005 - 2014 G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/samples/external/glm/include/glm/CMakeLists.txt b/samples/external/glm/include/glm/CMakeLists.txt new file mode 100644 index 0000000..d60a887 --- /dev/null +++ b/samples/external/glm/include/glm/CMakeLists.txt @@ -0,0 +1,67 @@ +file(GLOB ROOT_SOURCE *.cpp) +file(GLOB ROOT_INLINE *.inl) +file(GLOB ROOT_HEADER *.hpp) +file(GLOB ROOT_TEXT ../*.txt) +file(GLOB ROOT_MD ../*.md) +file(GLOB ROOT_NAT ../util/glm.natvis) + +file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp) +file(GLOB_RECURSE CORE_INLINE ./detail/*.inl) +file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp) + +file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp) +file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl) +file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp) + +file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp) +file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl) +file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp) + +file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp) +file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl) +file(GLOB_RECURSE SIMD_HEADER ./simd/*.h) + +source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD}) +source_group("Core Files" FILES ${CORE_SOURCE}) +source_group("Core Files" FILES ${CORE_INLINE}) +source_group("Core Files" FILES ${CORE_HEADER}) +source_group("GTC Files" FILES ${GTC_SOURCE}) +source_group("GTC Files" FILES ${GTC_INLINE}) +source_group("GTC Files" FILES ${GTC_HEADER}) +source_group("GTX Files" FILES ${GTX_SOURCE}) +source_group("GTX Files" FILES ${GTX_INLINE}) +source_group("GTX Files" FILES ${GTX_HEADER}) +source_group("SIMD Files" FILES ${SIMD_SOURCE}) +source_group("SIMD Files" FILES ${SIMD_INLINE}) +source_group("SIMD Files" FILES ${SIMD_HEADER}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +if(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE) + if(GLM_STATIC_LIBRARY_ENABLE) + add_library(glm_static STATIC ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) + endif(GLM_STATIC_LIBRARY_ENABLE) + + if(GLM_DYNAMIC_LIBRARY_ENABLE) + add_library(glm_shared SHARED ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) + endif(GLM_DYNAMIC_LIBRARY_ENABLE) + +else(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE) + add_executable(glm_dummy ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) + +endif(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE) diff --git a/samples/external/glm/include/glm/common.hpp b/samples/external/glm/include/glm/common.hpp new file mode 100644 index 0000000..f57e800 --- /dev/null +++ b/samples/external/glm/include/glm/common.hpp @@ -0,0 +1,6 @@ +/// @ref core +/// @file glm/common.hpp + +#pragma once + +#include "detail/func_common.hpp" diff --git a/samples/external/glm/include/glm/detail/_features.hpp b/samples/external/glm/include/glm/detail/_features.hpp new file mode 100644 index 0000000..97dd633 --- /dev/null +++ b/samples/external/glm/include/glm/detail/_features.hpp @@ -0,0 +1,399 @@ +/// @ref core +/// @file glm/detail/_features.hpp + +#pragma once + +// #define GLM_CXX98_EXCEPTIONS +// #define GLM_CXX98_RTTI + +// #define GLM_CXX11_RVALUE_REFERENCES +// Rvalue references - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html + +// GLM_CXX11_TRAILING_RETURN +// Rvalue references for *this - GCC not supported +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Initialization of class objects by rvalues - GCC any +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Non-static data member initializers - GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm + +// #define GLM_CXX11_VARIADIC_TEMPLATE +// Variadic templates - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf + +// +// Extending variadic template template parameters - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf + +// #define GLM_CXX11_GENERALIZED_INITIALIZERS +// Initializer lists - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm + +// #define GLM_CXX11_STATIC_ASSERT +// Static assertions - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html + +// #define GLM_CXX11_AUTO_TYPE +// auto-typed variables - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Multi-declarator auto - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Removal of auto as a storage-class specifier - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm + +// #define GLM_CXX11_AUTO_TYPE +// New function declarator syntax - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm + +// #define GLM_CXX11_LAMBDAS +// New wording for C++0x lambdas - GCC 4.5 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf + +// #define GLM_CXX11_DECLTYPE +// Declared type of an expression - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf + +// +// Right angle brackets - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html + +// +// Default template arguments for function templates DR226 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226 + +// +// Solving the SFINAE problem for expressions DR339 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html + +// #define GLM_CXX11_ALIAS_TEMPLATE +// Template aliases N2258 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf + +// +// Extern templates N1987 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm + +// #define GLM_CXX11_NULLPTR +// Null pointer constant N2431 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf + +// #define GLM_CXX11_STRONG_ENUMS +// Strongly-typed enums N2347 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf + +// +// Forward declarations for enums N2764 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf + +// +// Generalized attributes N2761 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf + +// +// Generalized constant expressions N2235 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf + +// +// Alignment support N2341 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf + +// #define GLM_CXX11_DELEGATING_CONSTRUCTORS +// Delegating constructors N1986 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf + +// +// Inheriting constructors N2540 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm + +// #define GLM_CXX11_EXPLICIT_CONVERSIONS +// Explicit conversion operators N2437 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf + +// +// New character types N2249 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html + +// +// Unicode string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Raw string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Universal character name literals N2170 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html + +// #define GLM_CXX11_USER_LITERALS +// User-defined literals N2765 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf + +// +// Standard Layout Types N2342 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm + +// #define GLM_CXX11_DEFAULTED_FUNCTIONS +// #define GLM_CXX11_DELETED_FUNCTIONS +// Defaulted and deleted functions N2346 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm + +// +// Extended friend declarations N1791 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf + +// +// Extending sizeof N2253 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html + +// #define GLM_CXX11_INLINE_NAMESPACES +// Inline namespaces N2535 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm + +// #define GLM_CXX11_UNRESTRICTED_UNIONS +// Unrestricted unions N2544 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + +// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +// Local and unnamed types as template arguments N2657 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm + +// #define GLM_CXX11_RANGE_FOR +// Range-based for N2930 GCC 4.6 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html + +// #define GLM_CXX11_OVERRIDE_CONTROL +// Explicit virtual overrides N2928 N3206 N3272 GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm + +// +// Minimal support for garbage collection and reachability-based leak detection N2670 No +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm + +// #define GLM_CXX11_NOEXCEPT +// Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only) +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html + +// +// Defining move special member functions N3053 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html + +// +// Sequence points N2239 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Atomic operations N2427 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Strong Compare and Exchange N2748 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html + +// +// Bidirectional Fences N2752 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm + +// +// Memory model N2429 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm + +// +// Data-dependency ordering: atomics and memory model N2664 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm + +// +// Propagating exceptions N2179 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html + +// +// Abandoning a process and at_quick_exit N2440 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm + +// +// Allow atomics use in signal handlers N2547 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm + +// +// Thread-local storage N2659 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm + +// +// Dynamic initialization and destruction with concurrency N2660 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm + +// +// __func__ predefined identifier N2340 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm + +// +// C99 preprocessor N1653 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm + +// +// long long N1811 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf + +// +// Extended integral types N1988 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf + +#if(GLM_COMPILER & GLM_COMPILER_GCC) + +# if(GLM_COMPILER >= GLM_COMPILER_GCC43) +# define GLM_CXX11_STATIC_ASSERT +# endif + +#elif(GLM_COMPILER & GLM_COMPILER_CLANG) +# if(__has_feature(cxx_exceptions)) +# define GLM_CXX98_EXCEPTIONS +# endif + +# if(__has_feature(cxx_rtti)) +# define GLM_CXX98_RTTI +# endif + +# if(__has_feature(cxx_access_control_sfinae)) +# define GLM_CXX11_ACCESS_CONTROL_SFINAE +# endif + +# if(__has_feature(cxx_alias_templates)) +# define GLM_CXX11_ALIAS_TEMPLATE +# endif + +# if(__has_feature(cxx_alignas)) +# define GLM_CXX11_ALIGNAS +# endif + +# if(__has_feature(cxx_attributes)) +# define GLM_CXX11_ATTRIBUTES +# endif + +# if(__has_feature(cxx_constexpr)) +# define GLM_CXX11_CONSTEXPR +# endif + +# if(__has_feature(cxx_decltype)) +# define GLM_CXX11_DECLTYPE +# endif + +# if(__has_feature(cxx_default_function_template_args)) +# define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_defaulted_functions)) +# define GLM_CXX11_DEFAULTED_FUNCTIONS +# endif + +# if(__has_feature(cxx_delegating_constructors)) +# define GLM_CXX11_DELEGATING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_deleted_functions)) +# define GLM_CXX11_DELETED_FUNCTIONS +# endif + +# if(__has_feature(cxx_explicit_conversions)) +# define GLM_CXX11_EXPLICIT_CONVERSIONS +# endif + +# if(__has_feature(cxx_generalized_initializers)) +# define GLM_CXX11_GENERALIZED_INITIALIZERS +# endif + +# if(__has_feature(cxx_implicit_moves)) +# define GLM_CXX11_IMPLICIT_MOVES +# endif + +# if(__has_feature(cxx_inheriting_constructors)) +# define GLM_CXX11_INHERITING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_inline_namespaces)) +# define GLM_CXX11_INLINE_NAMESPACES +# endif + +# if(__has_feature(cxx_lambdas)) +# define GLM_CXX11_LAMBDAS +# endif + +# if(__has_feature(cxx_local_type_template_args)) +# define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_noexcept)) +# define GLM_CXX11_NOEXCEPT +# endif + +# if(__has_feature(cxx_nonstatic_member_init)) +# define GLM_CXX11_NONSTATIC_MEMBER_INIT +# endif + +# if(__has_feature(cxx_nullptr)) +# define GLM_CXX11_NULLPTR +# endif + +# if(__has_feature(cxx_override_control)) +# define GLM_CXX11_OVERRIDE_CONTROL +# endif + +# if(__has_feature(cxx_reference_qualified_functions)) +# define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS +# endif + +# if(__has_feature(cxx_range_for)) +# define GLM_CXX11_RANGE_FOR +# endif + +# if(__has_feature(cxx_raw_string_literals)) +# define GLM_CXX11_RAW_STRING_LITERALS +# endif + +# if(__has_feature(cxx_rvalue_references)) +# define GLM_CXX11_RVALUE_REFERENCES +# endif + +# if(__has_feature(cxx_static_assert)) +# define GLM_CXX11_STATIC_ASSERT +# endif + +# if(__has_feature(cxx_auto_type)) +# define GLM_CXX11_AUTO_TYPE +# endif + +# if(__has_feature(cxx_strong_enums)) +# define GLM_CXX11_STRONG_ENUMS +# endif + +# if(__has_feature(cxx_trailing_return)) +# define GLM_CXX11_TRAILING_RETURN +# endif + +# if(__has_feature(cxx_unicode_literals)) +# define GLM_CXX11_UNICODE_LITERALS +# endif + +# if(__has_feature(cxx_unrestricted_unions)) +# define GLM_CXX11_UNRESTRICTED_UNIONS +# endif + +# if(__has_feature(cxx_user_literals)) +# define GLM_CXX11_USER_LITERALS +# endif + +# if(__has_feature(cxx_variadic_templates)) +# define GLM_CXX11_VARIADIC_TEMPLATES +# endif + +#endif//(GLM_COMPILER & GLM_COMPILER_CLANG) diff --git a/samples/external/glm/include/glm/detail/_fixes.hpp b/samples/external/glm/include/glm/detail/_fixes.hpp new file mode 100644 index 0000000..c957562 --- /dev/null +++ b/samples/external/glm/include/glm/detail/_fixes.hpp @@ -0,0 +1,30 @@ +/// @ref core +/// @file glm/detail/_fixes.hpp + +#include + +//! Workaround for compatibility with other libraries +#ifdef max +#undef max +#endif + +//! Workaround for compatibility with other libraries +#ifdef min +#undef min +#endif + +//! Workaround for Android +#ifdef isnan +#undef isnan +#endif + +//! Workaround for Android +#ifdef isinf +#undef isinf +#endif + +//! Workaround for Chrone Native Client +#ifdef log2 +#undef log2 +#endif + diff --git a/samples/external/glm/include/glm/detail/_noise.hpp b/samples/external/glm/include/glm/detail/_noise.hpp new file mode 100644 index 0000000..89403f4 --- /dev/null +++ b/samples/external/glm/include/glm/detail/_noise.hpp @@ -0,0 +1,107 @@ +/// @ref core +/// @file glm/detail/_noise.hpp + +#pragma once + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mod289(T const & x) + { + return x - floor(x * static_cast(1.0) / static_cast(289.0)) * static_cast(289.0); + } + + template + GLM_FUNC_QUALIFIER T permute(T const & x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER tvec2 permute(tvec2 const & x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER tvec3 permute(tvec3 const & x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER tvec4 permute(tvec4 const & x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } +/* + template class vecType> + GLM_FUNC_QUALIFIER vecType permute(vecType const & x) + { + return mod289(((x * T(34)) + T(1)) * x); + } +*/ + template + GLM_FUNC_QUALIFIER T taylorInvSqrt(T const & r) + { + return T(1.79284291400159) - T(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER tvec2 taylorInvSqrt(tvec2 const & r) + { + return T(1.79284291400159) - T(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER tvec3 taylorInvSqrt(tvec3 const & r) + { + return T(1.79284291400159) - T(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER tvec4 taylorInvSqrt(tvec4 const & r) + { + return T(1.79284291400159) - T(0.85373472095314) * r; + } +/* + template class vecType> + GLM_FUNC_QUALIFIER vecType taylorInvSqrt(vecType const & r) + { + return T(1.79284291400159) - T(0.85373472095314) * r; + } +*/ + + template + GLM_FUNC_QUALIFIER tvec2 fade(tvec2 const & t) + { + return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); + } + + template + GLM_FUNC_QUALIFIER tvec3 fade(tvec3 const & t) + { + return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); + } + + template + GLM_FUNC_QUALIFIER tvec4 fade(tvec4 const & t) + { + return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); + } +/* + template class vecType> + GLM_FUNC_QUALIFIER vecType fade(vecType const & t) + { + return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); + } +*/ +}//namespace detail +}//namespace glm + diff --git a/samples/external/glm/include/glm/detail/_swizzle.hpp b/samples/external/glm/include/glm/detail/_swizzle.hpp new file mode 100644 index 0000000..8e134d9 --- /dev/null +++ b/samples/external/glm/include/glm/detail/_swizzle.hpp @@ -0,0 +1,797 @@ +/// @ref core +/// @file glm/detail/_swizzle.hpp + +#pragma once + +namespace glm{ +namespace detail +{ + // Internal class for implementing swizzle operators + template + struct _swizzle_base0 + { + protected: + GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast(_buffer))[i]; } + GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast(_buffer))[i]; } + + // Use an opaque buffer to *ensure* the compiler doesn't call a constructor. + // The size 1 buffer is assumed to aligned to the actual members so that the + // elem() + char _buffer[1]; + }; + + template class vecType, int E0, int E1, int E2, int E3, bool Aligned> + struct _swizzle_base1 : public _swizzle_base0 + { + }; + + template class vecType, int E0, int E1, bool Aligned> + struct _swizzle_base1<2, T, P, vecType, E0,E1,-1,-2, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vecType operator ()() const { return vecType(this->elem(E0), this->elem(E1)); } + }; + + template class vecType, int E0, int E1, int E2, bool Aligned> + struct _swizzle_base1<3, T, P, vecType, E0,E1,E2,-1, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vecType operator ()() const { return vecType(this->elem(E0), this->elem(E1), this->elem(E2)); } + }; + + template class vecType, int E0, int E1, int E2, int E3, bool Aligned> + struct _swizzle_base1<4, T, P, vecType, E0,E1,E2,E3, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vecType operator ()() const { return vecType(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); } + }; + + // Internal class for implementing swizzle operators + /* + Template parameters: + + ValueType = type of scalar values (e.g. float, double) + VecType = class the swizzle is applies to (e.g. tvec3) + N = number of components in the vector (e.g. 3) + E0...3 = what index the n-th element of this swizzle refers to in the unswizzled vec + + DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles + containing duplicate elements so that they cannot be used as r-values). + */ + template class vecType, int E0, int E1, int E2, int E3, int DUPLICATE_ELEMENTS> + struct _swizzle_base2 : public _swizzle_base1::value> + { + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t) + { + for (int i = 0; i < N; ++i) + (*this)[i] = t; + return *this; + } + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vecType const& that) + { + struct op { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e = t; } + }; + _apply_op(that, op()); + return *this; + } + + GLM_FUNC_QUALIFIER void operator -= (vecType const& that) + { + struct op { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e -= t; } + }; + _apply_op(that, op()); + } + + GLM_FUNC_QUALIFIER void operator += (vecType const& that) + { + struct op { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e += t; } + }; + _apply_op(that, op()); + } + + GLM_FUNC_QUALIFIER void operator *= (vecType const& that) + { + struct op { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e *= t; } + }; + _apply_op(that, op()); + } + + GLM_FUNC_QUALIFIER void operator /= (vecType const& that) + { + struct op { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e /= t; } + }; + _apply_op(that, op()); + } + + GLM_FUNC_QUALIFIER T& operator[](size_t i) + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + GLM_FUNC_QUALIFIER T operator[](size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + + protected: + template + GLM_FUNC_QUALIFIER void _apply_op(vecType const& that, U op) + { + // Make a copy of the data in this == &that. + // The copier should optimize out the copy in cases where the function is + // properly inlined and the copy is not necessary. + T t[N]; + for (int i = 0; i < N; ++i) + t[i] = that[i]; + for (int i = 0; i < N; ++i) + op( (*this)[i], t[i] ); + } + }; + + // Specialization for swizzles containing duplicate elements. These cannot be modified. + template class vecType, int E0, int E1, int E2, int E3> + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct Stub {}; + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const &) { return *this; } + + GLM_FUNC_QUALIFIER T operator[] (size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + }; + + template class vecType, int E0, int E1, int E2, int E3> + struct _swizzle : public _swizzle_base2 + { + typedef _swizzle_base2 base_type; + + using base_type::operator=; + + GLM_FUNC_QUALIFIER operator vecType () const { return (*this)(); } + }; + +// +// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros +// +#define _GLM_SWIZZLE_TEMPLATE1 template class vecType, int E0, int E1, int E2, int E3> +#define _GLM_SWIZZLE_TEMPLATE2 template class vecType, int E0, int E1, int E2, int E3, int F0, int F1, int F2, int F3> +#define _GLM_SWIZZLE_TYPE1 _swizzle +#define _GLM_SWIZZLE_TYPE2 _swizzle + +// +// Wrapper for a binary operator (e.g. u.yy + v.zy) +// +#define _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + _GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER vecType operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b) \ + { \ + return a() OPERAND b(); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vecType operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const vecType& b) \ + { \ + return a() OPERAND b; \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vecType operator OPERAND ( const vecType& a, const _GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz) +// +#define _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vecType operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const T& b) \ + { \ + return a() OPERAND b; \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vecType operator OPERAND ( const T& a, const _GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Macro for wrapping a function taking one argument (e.g. abs()) +// +#define _GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION) \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a) \ + { \ + return FUNCTION(a()); \ + } + +// +// Macro for wrapping a function taking two vector arguments (e.g. dot()). +// +#define _GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION) \ + _GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const typename V& b) \ + { \ + return FUNCTION(a(), b); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const _GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a, b()); \ + } + +// +// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()). +// +#define _GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION) \ + _GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\ + { \ + return FUNCTION(a(), b, c); \ + } \ + _GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const _GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a, b(), c); \ + } + +}//namespace detail +}//namespace glm + +namespace glm +{ + namespace detail + { + _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-) + _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*) + _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+) + _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-) + _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*) + _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/) + } + + // + // Swizzles are distinct types from the unswizzled type. The below macros will + // provide template specializations for the swizzle types for the given functions + // so that the compiler does not have any ambiguity to choosing how to handle + // the function. + // + // The alternative is to use the operator()() when calling the function in order + // to explicitly convert the swizzled type to the unswizzled type. + // + + //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, abs); + //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acos); + //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acosh); + //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, all); + //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, any); + + //_GLM_SWIZZLE_FUNCTION_2_ARGS(value_type, dot); + //_GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, cross); + //_GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, step); + //_GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix); +} + +#define _GLM_SWIZZLE2_2_MEMBERS(T, P, V, E0,E1) \ + struct { detail::_swizzle<2, T, P, V, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2, T, P, V, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2, T, P, V, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2, T, P, V, 1,1,-1,-2> E1 ## E1; }; + +#define _GLM_SWIZZLE2_3_MEMBERS(T, P, V, E0,E1) \ + struct { detail::_swizzle<3,T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3,T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, P, V, 1,1,1,-1> E1 ## E1 ## E1; }; + +#define _GLM_SWIZZLE2_4_MEMBERS(T, P, V, E0,E1) \ + struct { detail::_swizzle<4,T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; + +#define _GLM_SWIZZLE3_2_MEMBERS(T, P, V, E0,E1,E2) \ + struct { detail::_swizzle<2,T, P, V, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 2,2,-1,-2> E2 ## E2; }; + +#define _GLM_SWIZZLE3_3_MEMBERS(T, P, V ,E0,E1,E2) \ + struct { detail::_swizzle<3, T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,2,-1> E2 ## E2 ## E2; }; + +#define _GLM_SWIZZLE3_4_MEMBERS(T, P, V, E0,E1,E2) \ + struct { detail::_swizzle<4,T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, P, V, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; + +#define _GLM_SWIZZLE4_2_MEMBERS(T, P, V, E0,E1,E2,E3) \ + struct { detail::_swizzle<2,T, P, V, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 0,3,-1,-2> E0 ## E3; }; \ + struct { detail::_swizzle<2,T, P, V, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 1,3,-1,-2> E1 ## E3; }; \ + struct { detail::_swizzle<2,T, P, V, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 2,2,-1,-2> E2 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 2,3,-1,-2> E2 ## E3; }; \ + struct { detail::_swizzle<2,T, P, V, 3,0,-1,-2> E3 ## E0; }; \ + struct { detail::_swizzle<2,T, P, V, 3,1,-1,-2> E3 ## E1; }; \ + struct { detail::_swizzle<2,T, P, V, 3,2,-1,-2> E3 ## E2; }; \ + struct { detail::_swizzle<2,T, P, V, 3,3,-1,-2> E3 ## E3; }; + +#define _GLM_SWIZZLE4_3_MEMBERS(T, P, V, E0,E1,E2,E3) \ + struct { detail::_swizzle<3, T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,0,3,-1> E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,1,3,-1> E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,2,3,-1> E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 0,3,0,-1> E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 0,3,1,-1> E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 0,3,2,-1> E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 0,3,3,-1> E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,0,3,-1> E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,1,3,-1> E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,2,3,-1> E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 1,3,0,-1> E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 1,3,1,-1> E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 1,3,2,-1> E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 1,3,3,-1> E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,0,3,-1> E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,1,3,-1> E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,2,-1> E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,2,3,-1> E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 2,3,0,-1> E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 2,3,1,-1> E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 2,3,2,-1> E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 2,3,3,-1> E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 3,0,0,-1> E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 3,0,1,-1> E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 3,0,2,-1> E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 3,0,3,-1> E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 3,1,0,-1> E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 3,1,1,-1> E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 3,1,2,-1> E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 3,1,3,-1> E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 3,2,0,-1> E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 3,2,1,-1> E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 3,2,2,-1> E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 3,2,3,-1> E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, P, V, 3,3,0,-1> E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, P, V, 3,3,1,-1> E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, P, V, 3,3,2,-1> E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, P, V, 3,3,3,-1> E3 ## E3 ## E3; }; + +#define _GLM_SWIZZLE4_4_MEMBERS(T, P, V, E0,E1,E2,E3) \ + struct { detail::_swizzle<4, T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, P, V, 3,3,3,3> E3 ## E3 ## E3 ## E3; }; diff --git a/samples/external/glm/include/glm/detail/_swizzle_func.hpp b/samples/external/glm/include/glm/detail/_swizzle_func.hpp new file mode 100644 index 0000000..4b37edb --- /dev/null +++ b/samples/external/glm/include/glm/detail/_swizzle_func.hpp @@ -0,0 +1,696 @@ +/// @ref core +/// @file glm/detail/_swizzle_func.hpp + +#pragma once + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B) \ + SWIZZLED_TYPE A ## B() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C) \ + SWIZZLED_TYPE A ## B ## C() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C, D) \ + SWIZZLED_TYPE A ## B ## C ## D() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B, this->C, this->D); \ + } + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B) \ + template \ + SWIZZLED_TYPE CLASS_TYPE::A ## B() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C) \ + template \ + SWIZZLED_TYPE CLASS_TYPE::A ## B ## C() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C, D) \ + template \ + SWIZZLED_TYPE CLASS_TYPE::A ## B ## C ## D() CONST \ + { \ + return SWIZZLED_TYPE(this->A, this->B, this->C, this->D); \ + } + +#define GLM_MUTABLE + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, x, y) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, r, g) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, s, t) + +//GLM_SWIZZLE_GEN_REF_FROM_VEC2(valType, detail::vec2, detail::ref2) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, x, y, z) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, r, g, b) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, s, t, p) + +//GLM_SWIZZLE_GEN_REF_FROM_VEC3(valType, detail::vec3, detail::ref2, detail::ref3) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, C) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, B) + +#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, C, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z, w) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b, a) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p, q) + +//GLM_SWIZZLE_GEN_REF_FROM_VEC4(valType, detail::vec4, detail::ref2, detail::ref3, detail::ref4) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t) + +//GLM_SWIZZLE_GEN_VEC_FROM_VEC2(valType, detail::vec2, detail::vec2, detail::vec3, detail::vec4) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p) + +//GLM_SWIZZLE_GEN_VEC_FROM_VEC3(valType, detail::vec3, detail::vec2, detail::vec3, detail::vec4) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z, w) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b, a) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p, q) + +//GLM_SWIZZLE_GEN_VEC_FROM_VEC4(valType, detail::vec4, detail::vec2, detail::vec3, detail::vec4) diff --git a/samples/external/glm/include/glm/detail/_vectorize.hpp b/samples/external/glm/include/glm/detail/_vectorize.hpp new file mode 100644 index 0000000..a08ed34 --- /dev/null +++ b/samples/external/glm/include/glm/detail/_vectorize.hpp @@ -0,0 +1,131 @@ +/// @ref core +/// @file glm/detail/_vectorize.hpp + +#pragma once + +#include "type_vec1.hpp" +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include "type_vec4.hpp" + +namespace glm{ +namespace detail +{ + template class vecType> + struct functor1{}; + + template + struct functor1 + { + GLM_FUNC_QUALIFIER static tvec1 call(R (*Func) (T x), tvec1 const & v) + { + return tvec1(Func(v.x)); + } + }; + + template + struct functor1 + { + GLM_FUNC_QUALIFIER static tvec2 call(R (*Func) (T x), tvec2 const & v) + { + return tvec2(Func(v.x), Func(v.y)); + } + }; + + template + struct functor1 + { + GLM_FUNC_QUALIFIER static tvec3 call(R (*Func) (T x), tvec3 const & v) + { + return tvec3(Func(v.x), Func(v.y), Func(v.z)); + } + }; + + template + struct functor1 + { + GLM_FUNC_QUALIFIER static tvec4 call(R (*Func) (T x), tvec4 const & v) + { + return tvec4(Func(v.x), Func(v.y), Func(v.z), Func(v.w)); + } + }; + + template class vecType> + struct functor2{}; + + template + struct functor2 + { + GLM_FUNC_QUALIFIER static tvec1 call(T (*Func) (T x, T y), tvec1 const & a, tvec1 const & b) + { + return tvec1(Func(a.x, b.x)); + } + }; + + template + struct functor2 + { + GLM_FUNC_QUALIFIER static tvec2 call(T (*Func) (T x, T y), tvec2 const & a, tvec2 const & b) + { + return tvec2(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template + struct functor2 + { + GLM_FUNC_QUALIFIER static tvec3 call(T (*Func) (T x, T y), tvec3 const & a, tvec3 const & b) + { + return tvec3(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template + struct functor2 + { + GLM_FUNC_QUALIFIER static tvec4 call(T (*Func) (T x, T y), tvec4 const & a, tvec4 const & b) + { + return tvec4(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; + + template class vecType> + struct functor2_vec_sca{}; + + template + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static tvec1 call(T (*Func) (T x, T y), tvec1 const & a, T b) + { + return tvec1(Func(a.x, b)); + } + }; + + template + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static tvec2 call(T (*Func) (T x, T y), tvec2 const & a, T b) + { + return tvec2(Func(a.x, b), Func(a.y, b)); + } + }; + + template + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static tvec3 call(T (*Func) (T x, T y), tvec3 const & a, T b) + { + return tvec3(Func(a.x, b), Func(a.y, b), Func(a.z, b)); + } + }; + + template + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static tvec4 call(T (*Func) (T x, T y), tvec4 const & a, T b) + { + return tvec4(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); + } + }; +}//namespace detail +}//namespace glm diff --git a/samples/external/glm/include/glm/detail/dummy.cpp b/samples/external/glm/include/glm/detail/dummy.cpp new file mode 100644 index 0000000..a519a6d --- /dev/null +++ b/samples/external/glm/include/glm/detail/dummy.cpp @@ -0,0 +1,207 @@ +/// @ref core +/// @file glm/core/dummy.cpp +/// +/// GLM is a header only library. There is nothing to compile. +/// dummy.cpp exist only a wordaround for CMake file. + +/* +#define GLM_MESSAGES +#include +#include +#include + +struct material +{ + glm::vec4 emission; // Ecm + glm::vec4 ambient; // Acm + glm::vec4 diffuse; // Dcm + glm::vec4 specular; // Scm + float shininess; // Srm +}; + +struct light +{ + glm::vec4 ambient; // Acli + glm::vec4 diffuse; // Dcli + glm::vec4 specular; // Scli + glm::vec4 position; // Ppli + glm::vec4 halfVector; // Derived: Hi + glm::vec3 spotDirection; // Sdli + float spotExponent; // Srli + float spotCutoff; // Crli + // (range: [0.0,90.0], 180.0) + float spotCosCutoff; // Derived: cos(Crli) + // (range: [1.0,0.0],-1.0) + float constantAttenuation; // K0 + float linearAttenuation; // K1 + float quadraticAttenuation;// K2 +}; + + +// Sample 1 +#include // glm::vec3 +#include // glm::cross, glm::normalize + +glm::vec3 computeNormal +( + glm::vec3 const & a, + glm::vec3 const & b, + glm::vec3 const & c +) +{ + return glm::normalize(glm::cross(c - a, b - a)); +} + +typedef unsigned int GLuint; +#define GL_FALSE 0 +void glUniformMatrix4fv(GLuint, int, int, float*){} + +// Sample 2 +#include // glm::vec3 +#include // glm::vec4, glm::ivec4 +#include // glm::mat4 +#include // glm::translate, glm::rotate, glm::scale, glm::perspective +#include // glm::value_ptr +void func(GLuint LocationMVP, float Translate, glm::vec2 const & Rotate) +{ + glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f); + glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate)); + glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + glm::mat4 View = glm::rotate(ViewRotateX, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); + glm::mat4 MVP = Projection * View * Model; + glUniformMatrix4fv(LocationMVP, 1, GL_FALSE, glm::value_ptr(MVP)); +} + +// Sample 3 +#include // glm::vec2 +#include // glm::packUnorm2x16 +#include // glm::uint +#include // glm::i8vec2, glm::i32vec2 +std::size_t const VertexCount = 4; +// Float quad geometry +std::size_t const PositionSizeF32 = VertexCount * sizeof(glm::vec2); +glm::vec2 const PositionDataF32[VertexCount] = +{ + glm::vec2(-1.0f,-1.0f), + glm::vec2( 1.0f,-1.0f), + glm::vec2( 1.0f, 1.0f), + glm::vec2(-1.0f, 1.0f) + }; +// Half-float quad geometry +std::size_t const PositionSizeF16 = VertexCount * sizeof(glm::uint); +glm::uint const PositionDataF16[VertexCount] = +{ + glm::uint(glm::packUnorm2x16(glm::vec2(-1.0f, -1.0f))), + glm::uint(glm::packUnorm2x16(glm::vec2( 1.0f, -1.0f))), + glm::uint(glm::packUnorm2x16(glm::vec2( 1.0f, 1.0f))), + glm::uint(glm::packUnorm2x16(glm::vec2(-1.0f, 1.0f))) +}; +// 8 bits signed integer quad geometry +std::size_t const PositionSizeI8 = VertexCount * sizeof(glm::i8vec2); +glm::i8vec2 const PositionDataI8[VertexCount] = +{ + glm::i8vec2(-1,-1), + glm::i8vec2( 1,-1), + glm::i8vec2( 1, 1), + glm::i8vec2(-1, 1) +}; +// 32 bits signed integer quad geometry +std::size_t const PositionSizeI32 = VertexCount * sizeof(glm::i32vec2); +glm::i32vec2 const PositionDataI32[VertexCount] = +{ + glm::i32vec2 (-1,-1), + glm::i32vec2 ( 1,-1), + glm::i32vec2 ( 1, 1), + glm::i32vec2 (-1, 1) +}; + +struct intersection +{ + glm::vec4 position; + glm::vec3 normal; +}; +*/ + + +/* +// Sample 4 +#include // glm::vec3 +#include // glm::normalize, glm::dot, glm::reflect +#include // glm::pow +#include // glm::vecRand3 +glm::vec3 lighting +( + intersection const & Intersection, + material const & Material, + light const & Light, + glm::vec3 const & View +) +{ + glm::vec3 Color(0.0f); + glm::vec3 LightVertor(glm::normalize( + Light.position - Intersection.position + + glm::vecRand3(0.0f, Light.inaccuracy)); + + if(!shadow(Intersection.position, Light.position, LightVertor)) + { + float Diffuse = glm::dot(Intersection.normal, LightVector); + if(Diffuse <= 0.0f) + return Color; + if(Material.isDiffuse()) + Color += Light.color() * Material.diffuse * Diffuse; + if(Material.isSpecular()) + { + glm::vec3 Reflect(glm::reflect( + glm::normalize(-LightVector), + glm::normalize(Intersection.normal))); + float Dot = glm::dot(Reflect, View); + float Base = Dot > 0.0f ? Dot : 0.0f; + float Specular = glm::pow(Base, Material.exponent); + Color += Material.specular * Specular; + } + } + return Color; +} +*/ + +/* +template class vecType> +T normalizeDotA(vecType const & x, vecType const & y) +{ + return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); +} + +#define GLM_TEMPLATE_GENTYPE typename T, glm::precision P, template class + +template +T normalizeDotB(vecType const & x, vecType const & y) +{ + return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); +} + +template +typename vecType::value_type normalizeDotC(vecType const & a, vecType const & b) +{ + return glm::dot(a, b) * glm::inversesqrt(glm::dot(a, a) * glm::dot(b, b)); +} +*/ +int main() +{ +/* + glm::vec1 o(1); + glm::vec2 a(1); + glm::vec3 b(1); + glm::vec4 c(1); + + glm::quat q; + glm::dualquat p; + + glm::mat4 m(1); + + float a0 = normalizeDotA(a, a); + float b0 = normalizeDotB(b, b); + float c0 = normalizeDotC(c, c); +*/ + return 0; +} diff --git a/samples/external/glm/include/glm/detail/func_common.hpp b/samples/external/glm/include/glm/detail/func_common.hpp new file mode 100644 index 0000000..871fed6 --- /dev/null +++ b/samples/external/glm/include/glm/detail/func_common.hpp @@ -0,0 +1,427 @@ +/// @ref core +/// @file glm/detail/func_common.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.3 Common Functions +/// +/// @defgroup core_func_common Common functions +/// @ingroup core +/// +/// These all operate component-wise. The description is per component. + +#pragma once + +#include "setup.hpp" +#include "precision.hpp" +#include "type_int.hpp" +#include "_fixes.hpp" + +namespace glm +{ + /// @addtogroup core_func_common + /// @{ + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam genType floating-point or signed integer; scalar or vector types. + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType abs(genType x); + + template class vecType> + GLM_FUNC_DECL vecType abs(vecType const & x); + + /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. + /// + /// @tparam genType Floating-point or signed integer; scalar or vector types. + /// + /// @see GLSL sign man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template class vecType> + GLM_FUNC_DECL vecType sign(vecType const & x); + + /// Returns a value equal to the nearest integer that is less then or equal to x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL floor man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template class vecType> + GLM_FUNC_DECL vecType floor(vecType const & x); + + /// Returns a value equal to the nearest integer to x + /// whose absolute value is not larger than the absolute value of x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL trunc man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template class vecType> + GLM_FUNC_DECL vecType trunc(vecType const & x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// This includes the possibility that round(x) returns the + /// same value as roundEven(x) for all values of x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL round man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template class vecType> + GLM_FUNC_DECL vecType round(vecType const & x); + + /// Returns a value equal to the nearest integer to x. + /// A fractional part of 0.5 will round toward the nearest even + /// integer. (Both 3.5 and 4.5 for x will return 4.0.) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL roundEven man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// @see New round to even technique + template class vecType> + GLM_FUNC_DECL vecType roundEven(vecType const & x); + + /// Returns a value equal to the nearest integer + /// that is greater than or equal to x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL ceil man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template class vecType> + GLM_FUNC_DECL vecType ceil(vecType const & x); + + /// Return x - floor(x). + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fract(genType x); + + template class vecType> + GLM_FUNC_DECL vecType fract(vecType const & x); + + /// Modulus. Returns x - y * floor(x / y) + /// for each component in x using the floating point value y. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL mod man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType mod(genType x, genType y); + + template class vecType> + GLM_FUNC_DECL vecType mod(vecType const & x, T y); + + template class vecType> + GLM_FUNC_DECL vecType mod(vecType const & x, vecType const & y); + + /// Returns the fractional part of x and sets i to the integer + /// part (as a whole number floating point value). Both the + /// return value and the output parameter will have the same + /// sign as x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL modf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType modf(genType x, genType & i); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType min(genType x, genType y); + + template class vecType> + GLM_FUNC_DECL vecType min(vecType const & x, T y); + + template class vecType> + GLM_FUNC_DECL vecType min(vecType const & x, vecType const & y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType max(genType x, genType y); + + template class vecType> + GLM_FUNC_DECL vecType max(vecType const & x, T y); + + template class vecType> + GLM_FUNC_DECL vecType max(vecType const & x, vecType const & y); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType clamp(genType x, genType minVal, genType maxVal); + + template class vecType> + GLM_FUNC_DECL vecType clamp(vecType const & x, T minVal, T maxVal); + + template class vecType> + GLM_FUNC_DECL vecType clamp(vecType const & x, vecType const & minVal, vecType const & maxVal); + + /// If genTypeU is a floating scalar or vector: + /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of + /// x and y using the floating-point value a. + /// The value for a is not restricted to the range [0, 1]. + /// + /// If genTypeU is a boolean scalar or vector: + /// Selects which vector each returned component comes + /// from. For a component of that is false, the + /// corresponding component of x is returned. For a + /// component of a that is true, the corresponding + /// component of y is returned. Components of x and y that + /// are not selected are allowed to be invalid floating point + /// values and will have no effect on the results. Thus, this + /// provides different functionality than + /// genType mix(genType x, genType y, genType(a)) + /// where a is a Boolean vector. + /// + /// @see GLSL mix man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// + /// @param[in] x Value to interpolate. + /// @param[in] y Value to interpolate. + /// @param[in] a Interpolant. + /// + /// @tparam genTypeT Floating point scalar or vector. + /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT. + /// + /// @code + /// #include + /// ... + /// float a; + /// bool b; + /// glm::dvec3 e; + /// glm::dvec3 f; + /// glm::vec4 g; + /// glm::vec4 h; + /// ... + /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. + /// glm::vec4 s = glm::mix(g, h, b); // Teturns g or h; + /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second. + /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter. + /// @endcode + template class vecType> + GLM_FUNC_DECL vecType mix(vecType const & x, vecType const & y, vecType const & a); + + template class vecType> + GLM_FUNC_DECL vecType mix(vecType const & x, vecType const & y, U a); + + template + GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType. + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType step(genType edge, genType x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template